From 50123887ba0f33cf47520bee7c419d68742af2d1 Mon Sep 17 00:00:00 2001 From: Qt by Nokia Date: Wed, 27 Apr 2011 12:05:43 +0200 Subject: Initial import from the monolithic Qt. This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12 --- 3rdparty/clucene/APACHE.license | 201 + 3rdparty/clucene/AUTHORS | 22 + 3rdparty/clucene/COPYING | 30 + 3rdparty/clucene/ChangeLog | 0 3rdparty/clucene/LGPL.license | 475 + 3rdparty/clucene/README | 92 + 3rdparty/clucene/src/CLucene.h | 38 + 3rdparty/clucene/src/CLucene/CLBackwards.h | 87 + 3rdparty/clucene/src/CLucene/CLConfig.h | 304 + 3rdparty/clucene/src/CLucene/CLMonolithic.cpp | 115 + 3rdparty/clucene/src/CLucene/LuceneThreads.h | 72 + 3rdparty/clucene/src/CLucene/StdHeader.cpp | 134 + 3rdparty/clucene/src/CLucene/StdHeader.h | 501 + .../src/CLucene/analysis/AnalysisHeader.cpp | 200 + .../clucene/src/CLucene/analysis/AnalysisHeader.h | 234 + .../clucene/src/CLucene/analysis/Analyzers.cpp | 389 + 3rdparty/clucene/src/CLucene/analysis/Analyzers.h | 309 + .../CLucene/analysis/standard/StandardAnalyzer.cpp | 46 + .../CLucene/analysis/standard/StandardAnalyzer.h | 47 + .../CLucene/analysis/standard/StandardFilter.cpp | 58 + .../src/CLucene/analysis/standard/StandardFilter.h | 37 + .../analysis/standard/StandardTokenizer.cpp | 446 + .../CLucene/analysis/standard/StandardTokenizer.h | 88 + .../analysis/standard/StandardTokenizerConstants.h | 30 + 3rdparty/clucene/src/CLucene/config/CompilerAcc.h | 166 + 3rdparty/clucene/src/CLucene/config/CompilerBcb.h | 68 + 3rdparty/clucene/src/CLucene/config/CompilerGcc.h | 175 + 3rdparty/clucene/src/CLucene/config/CompilerMsvc.h | 136 + 3rdparty/clucene/src/CLucene/config/PlatformMac.h | 19 + 3rdparty/clucene/src/CLucene/config/PlatformUnix.h | 12 + .../clucene/src/CLucene/config/PlatformWin32.h | 11 + 3rdparty/clucene/src/CLucene/config/compiler.h | 259 + 3rdparty/clucene/src/CLucene/config/define_std.h | 113 + .../clucene/src/CLucene/config/gunichartables.cpp | 386 + .../clucene/src/CLucene/config/gunichartables.h | 11264 +++++++++++++++++++ 3rdparty/clucene/src/CLucene/config/repl_lltot.cpp | 47 + 3rdparty/clucene/src/CLucene/config/repl_tchar.h | 126 + .../clucene/src/CLucene/config/repl_tcscasecmp.cpp | 21 + .../clucene/src/CLucene/config/repl_tcslwr.cpp | 15 + .../clucene/src/CLucene/config/repl_tcstod.cpp | 23 + .../clucene/src/CLucene/config/repl_tcstoll.cpp | 46 + .../clucene/src/CLucene/config/repl_tprintf.cpp | 149 + 3rdparty/clucene/src/CLucene/config/repl_wchar.h | 121 + .../clucene/src/CLucene/config/threadCSection.h | 71 + .../clucene/src/CLucene/config/threadPthread.h | 59 + 3rdparty/clucene/src/CLucene/config/threads.cpp | 162 + 3rdparty/clucene/src/CLucene/config/utf8.cpp | 237 + 3rdparty/clucene/src/CLucene/debug/condition.cpp | 80 + 3rdparty/clucene/src/CLucene/debug/condition.h | 64 + 3rdparty/clucene/src/CLucene/debug/error.cpp | 73 + 3rdparty/clucene/src/CLucene/debug/error.h | 74 + 3rdparty/clucene/src/CLucene/debug/lucenebase.h | 75 + 3rdparty/clucene/src/CLucene/debug/mem.h | 130 + 3rdparty/clucene/src/CLucene/debug/memtracking.cpp | 371 + .../clucene/src/CLucene/document/DateField.cpp | 60 + 3rdparty/clucene/src/CLucene/document/DateField.h | 64 + 3rdparty/clucene/src/CLucene/document/Document.cpp | 237 + 3rdparty/clucene/src/CLucene/document/Document.h | 158 + 3rdparty/clucene/src/CLucene/document/Field.cpp | 315 + 3rdparty/clucene/src/CLucene/document/Field.h | 261 + .../clucene/src/CLucene/index/CompoundFile.cpp | 380 + 3rdparty/clucene/src/CLucene/index/CompoundFile.h | 219 + .../clucene/src/CLucene/index/DocumentWriter.cpp | 571 + .../clucene/src/CLucene/index/DocumentWriter.h | 107 + 3rdparty/clucene/src/CLucene/index/FieldInfo.h | 16 + 3rdparty/clucene/src/CLucene/index/FieldInfos.cpp | 236 + 3rdparty/clucene/src/CLucene/index/FieldInfos.h | 171 + .../clucene/src/CLucene/index/FieldsReader.cpp | 231 + 3rdparty/clucene/src/CLucene/index/FieldsReader.h | 60 + .../clucene/src/CLucene/index/FieldsWriter.cpp | 186 + 3rdparty/clucene/src/CLucene/index/FieldsWriter.h | 49 + .../clucene/src/CLucene/index/IndexModifier.cpp | 254 + 3rdparty/clucene/src/CLucene/index/IndexModifier.h | 316 + 3rdparty/clucene/src/CLucene/index/IndexReader.cpp | 668 ++ 3rdparty/clucene/src/CLucene/index/IndexReader.h | 485 + 3rdparty/clucene/src/CLucene/index/IndexWriter.cpp | 697 ++ 3rdparty/clucene/src/CLucene/index/IndexWriter.h | 425 + 3rdparty/clucene/src/CLucene/index/MultiReader.cpp | 722 ++ 3rdparty/clucene/src/CLucene/index/MultiReader.h | 202 + 3rdparty/clucene/src/CLucene/index/SegmentHeader.h | 314 + .../clucene/src/CLucene/index/SegmentInfos.cpp | 259 + 3rdparty/clucene/src/CLucene/index/SegmentInfos.h | 128 + .../clucene/src/CLucene/index/SegmentMergeInfo.cpp | 104 + .../clucene/src/CLucene/index/SegmentMergeInfo.h | 47 + .../src/CLucene/index/SegmentMergeQueue.cpp | 74 + .../clucene/src/CLucene/index/SegmentMergeQueue.h | 38 + .../clucene/src/CLucene/index/SegmentMerger.cpp | 723 ++ 3rdparty/clucene/src/CLucene/index/SegmentMerger.h | 169 + .../clucene/src/CLucene/index/SegmentReader.cpp | 816 ++ .../clucene/src/CLucene/index/SegmentTermDocs.cpp | 216 + .../clucene/src/CLucene/index/SegmentTermEnum.cpp | 389 + .../clucene/src/CLucene/index/SegmentTermEnum.h | 138 + .../src/CLucene/index/SegmentTermPositions.cpp | 101 + .../src/CLucene/index/SegmentTermVector.cpp | 188 + 3rdparty/clucene/src/CLucene/index/Term.cpp | 182 + 3rdparty/clucene/src/CLucene/index/Term.h | 146 + 3rdparty/clucene/src/CLucene/index/TermInfo.cpp | 53 + 3rdparty/clucene/src/CLucene/index/TermInfo.h | 61 + .../clucene/src/CLucene/index/TermInfosReader.cpp | 443 + .../clucene/src/CLucene/index/TermInfosReader.h | 106 + .../clucene/src/CLucene/index/TermInfosWriter.cpp | 185 + .../clucene/src/CLucene/index/TermInfosWriter.h | 89 + 3rdparty/clucene/src/CLucene/index/TermVector.h | 418 + .../clucene/src/CLucene/index/TermVectorReader.cpp | 393 + .../clucene/src/CLucene/index/TermVectorWriter.cpp | 349 + 3rdparty/clucene/src/CLucene/index/Terms.h | 174 + 3rdparty/clucene/src/CLucene/queryParser/Lexer.cpp | 371 + 3rdparty/clucene/src/CLucene/queryParser/Lexer.h | 67 + .../CLucene/queryParser/MultiFieldQueryParser.cpp | 215 + .../CLucene/queryParser/MultiFieldQueryParser.h | 136 + .../src/CLucene/queryParser/QueryParser.cpp | 509 + .../clucene/src/CLucene/queryParser/QueryParser.h | 165 + .../src/CLucene/queryParser/QueryParserBase.cpp | 369 + .../src/CLucene/queryParser/QueryParserBase.h | 204 + .../clucene/src/CLucene/queryParser/QueryToken.cpp | 73 + .../clucene/src/CLucene/queryParser/QueryToken.h | 76 + .../clucene/src/CLucene/queryParser/TokenList.cpp | 79 + .../clucene/src/CLucene/queryParser/TokenList.h | 38 + .../clucene/src/CLucene/search/BooleanClause.h | 90 + .../clucene/src/CLucene/search/BooleanQuery.cpp | 363 + 3rdparty/clucene/src/CLucene/search/BooleanQuery.h | 126 + .../clucene/src/CLucene/search/BooleanScorer.cpp | 248 + .../clucene/src/CLucene/search/BooleanScorer.h | 99 + .../src/CLucene/search/CachingWrapperFilter.cpp | 86 + .../src/CLucene/search/CachingWrapperFilter.h | 80 + .../clucene/src/CLucene/search/ChainedFilter.cpp | 213 + .../clucene/src/CLucene/search/ChainedFilter.h | 86 + 3rdparty/clucene/src/CLucene/search/Compare.h | 161 + .../src/CLucene/search/ConjunctionScorer.cpp | 144 + .../clucene/src/CLucene/search/ConjunctionScorer.h | 50 + 3rdparty/clucene/src/CLucene/search/DateFilter.cpp | 93 + 3rdparty/clucene/src/CLucene/search/DateFilter.h | 59 + .../src/CLucene/search/ExactPhraseScorer.cpp | 85 + .../clucene/src/CLucene/search/ExactPhraseScorer.h | 31 + .../clucene/src/CLucene/search/Explanation.cpp | 133 + 3rdparty/clucene/src/CLucene/search/Explanation.h | 66 + 3rdparty/clucene/src/CLucene/search/FieldCache.cpp | 55 + 3rdparty/clucene/src/CLucene/search/FieldCache.h | 182 + .../clucene/src/CLucene/search/FieldCacheImpl.cpp | 529 + .../clucene/src/CLucene/search/FieldCacheImpl.h | 144 + 3rdparty/clucene/src/CLucene/search/FieldDoc.h | 70 + .../src/CLucene/search/FieldDocSortedHitQueue.cpp | 171 + .../src/CLucene/search/FieldDocSortedHitQueue.h | 159 + .../src/CLucene/search/FieldSortedHitQueue.cpp | 212 + .../src/CLucene/search/FieldSortedHitQueue.h | 216 + 3rdparty/clucene/src/CLucene/search/Filter.h | 46 + .../src/CLucene/search/FilteredTermEnum.cpp | 136 + .../clucene/src/CLucene/search/FilteredTermEnum.h | 61 + 3rdparty/clucene/src/CLucene/search/FuzzyQuery.cpp | 357 + 3rdparty/clucene/src/CLucene/search/FuzzyQuery.h | 156 + 3rdparty/clucene/src/CLucene/search/HitQueue.cpp | 107 + 3rdparty/clucene/src/CLucene/search/HitQueue.h | 55 + 3rdparty/clucene/src/CLucene/search/Hits.cpp | 174 + .../clucene/src/CLucene/search/IndexSearcher.cpp | 362 + .../clucene/src/CLucene/search/IndexSearcher.h | 73 + .../clucene/src/CLucene/search/MultiSearcher.cpp | 227 + .../clucene/src/CLucene/search/MultiSearcher.h | 95 + .../clucene/src/CLucene/search/MultiTermQuery.cpp | 98 + .../clucene/src/CLucene/search/MultiTermQuery.h | 62 + .../clucene/src/CLucene/search/PhrasePositions.cpp | 116 + .../clucene/src/CLucene/search/PhrasePositions.h | 41 + .../clucene/src/CLucene/search/PhraseQuery.cpp | 463 + 3rdparty/clucene/src/CLucene/search/PhraseQuery.h | 127 + 3rdparty/clucene/src/CLucene/search/PhraseQueue.h | 36 + .../clucene/src/CLucene/search/PhraseScorer.cpp | 225 + 3rdparty/clucene/src/CLucene/search/PhraseScorer.h | 65 + .../clucene/src/CLucene/search/PrefixQuery.cpp | 273 + 3rdparty/clucene/src/CLucene/search/PrefixQuery.h | 75 + .../clucene/src/CLucene/search/QueryFilter.cpp | 73 + 3rdparty/clucene/src/CLucene/search/QueryFilter.h | 44 + .../clucene/src/CLucene/search/RangeFilter.cpp | 150 + 3rdparty/clucene/src/CLucene/search/RangeFilter.h | 51 + 3rdparty/clucene/src/CLucene/search/RangeQuery.cpp | 204 + 3rdparty/clucene/src/CLucene/search/RangeQuery.h | 71 + 3rdparty/clucene/src/CLucene/search/Scorer.h | 80 + .../clucene/src/CLucene/search/SearchHeader.cpp | 141 + 3rdparty/clucene/src/CLucene/search/SearchHeader.h | 456 + 3rdparty/clucene/src/CLucene/search/Similarity.cpp | 233 + 3rdparty/clucene/src/CLucene/search/Similarity.h | 268 + .../src/CLucene/search/SloppyPhraseScorer.cpp | 106 + .../src/CLucene/search/SloppyPhraseScorer.h | 34 + 3rdparty/clucene/src/CLucene/search/Sort.cpp | 345 + 3rdparty/clucene/src/CLucene/search/Sort.h | 356 + 3rdparty/clucene/src/CLucene/search/TermQuery.cpp | 213 + 3rdparty/clucene/src/CLucene/search/TermQuery.h | 81 + 3rdparty/clucene/src/CLucene/search/TermScorer.cpp | 120 + 3rdparty/clucene/src/CLucene/search/TermScorer.h | 53 + .../clucene/src/CLucene/search/WildcardQuery.cpp | 147 + .../clucene/src/CLucene/search/WildcardQuery.h | 69 + .../src/CLucene/search/WildcardTermEnum.cpp | 150 + .../clucene/src/CLucene/search/WildcardTermEnum.h | 67 + 3rdparty/clucene/src/CLucene/store/Directory.h | 108 + 3rdparty/clucene/src/CLucene/store/FSDirectory.cpp | 662 ++ 3rdparty/clucene/src/CLucene/store/FSDirectory.h | 216 + 3rdparty/clucene/src/CLucene/store/IndexInput.cpp | 233 + 3rdparty/clucene/src/CLucene/store/IndexInput.h | 190 + 3rdparty/clucene/src/CLucene/store/IndexOutput.cpp | 163 + 3rdparty/clucene/src/CLucene/store/IndexOutput.h | 152 + 3rdparty/clucene/src/CLucene/store/InputStream.h | 21 + 3rdparty/clucene/src/CLucene/store/Lock.cpp | 27 + 3rdparty/clucene/src/CLucene/store/Lock.h | 106 + 3rdparty/clucene/src/CLucene/store/MMapInput.cpp | 203 + 3rdparty/clucene/src/CLucene/store/OutputStream.h | 23 + .../clucene/src/CLucene/store/RAMDirectory.cpp | 446 + 3rdparty/clucene/src/CLucene/store/RAMDirectory.h | 195 + .../CLucene/store/TransactionalRAMDirectory.cpp | 212 + .../src/CLucene/store/TransactionalRAMDirectory.h | 76 + 3rdparty/clucene/src/CLucene/util/Arrays.h | 164 + 3rdparty/clucene/src/CLucene/util/BitSet.cpp | 119 + 3rdparty/clucene/src/CLucene/util/BitSet.h | 62 + 3rdparty/clucene/src/CLucene/util/Equators.cpp | 180 + 3rdparty/clucene/src/CLucene/util/Equators.h | 274 + .../clucene/src/CLucene/util/FastCharStream.cpp | 107 + 3rdparty/clucene/src/CLucene/util/FastCharStream.h | 55 + 3rdparty/clucene/src/CLucene/util/Misc.cpp | 295 + 3rdparty/clucene/src/CLucene/util/Misc.h | 75 + 3rdparty/clucene/src/CLucene/util/PriorityQueue.h | 177 + 3rdparty/clucene/src/CLucene/util/Reader.cpp | 186 + 3rdparty/clucene/src/CLucene/util/Reader.h | 138 + 3rdparty/clucene/src/CLucene/util/StringBuffer.cpp | 335 + 3rdparty/clucene/src/CLucene/util/StringBuffer.h | 77 + 3rdparty/clucene/src/CLucene/util/StringIntern.cpp | 158 + 3rdparty/clucene/src/CLucene/util/StringIntern.h | 61 + 3rdparty/clucene/src/CLucene/util/ThreadLocal.cpp | 55 + 3rdparty/clucene/src/CLucene/util/ThreadLocal.h | 143 + 3rdparty/clucene/src/CLucene/util/VoidList.h | 175 + 3rdparty/clucene/src/CLucene/util/VoidMap.h | 270 + 3rdparty/clucene/src/CLucene/util/bufferedstream.h | 157 + 3rdparty/clucene/src/CLucene/util/dirent.cpp | 221 + 3rdparty/clucene/src/CLucene/util/dirent.h | 105 + .../clucene/src/CLucene/util/fileinputstream.cpp | 103 + .../clucene/src/CLucene/util/fileinputstream.h | 38 + .../clucene/src/CLucene/util/inputstreambuffer.h | 126 + 3rdparty/clucene/src/CLucene/util/jstreamsconfig.h | 9 + 3rdparty/clucene/src/CLucene/util/streambase.h | 148 + 3rdparty/clucene/src/CLucene/util/stringreader.h | 124 + 3rdparty/clucene/src/CLucene/util/subinputstream.h | 141 + demos/arthurplugin/arthur_plugin.qrc | 7 + demos/arthurplugin/arthurplugin.pro | 54 + demos/arthurplugin/bg1.jpg | Bin 0 -> 23771 bytes demos/arthurplugin/flower.jpg | Bin 0 -> 49616 bytes demos/arthurplugin/flower_alpha.jpg | Bin 0 -> 67326 bytes demos/arthurplugin/plugin.cpp | 296 + demos/shared/arthurstyle.cpp | 452 + demos/shared/arthurstyle.h | 79 + demos/shared/arthurwidgets.cpp | 371 + demos/shared/arthurwidgets.h | 137 + demos/shared/hoverpoints.cpp | 415 + demos/shared/hoverpoints.h | 162 + demos/shared/images/bg_pattern.png | Bin 0 -> 104 bytes demos/shared/images/button_normal_cap_left.png | Bin 0 -> 654 bytes demos/shared/images/button_normal_cap_right.png | Bin 0 -> 674 bytes demos/shared/images/button_normal_stretch.png | Bin 0 -> 185 bytes demos/shared/images/button_pressed_cap_left.png | Bin 0 -> 710 bytes demos/shared/images/button_pressed_cap_right.png | Bin 0 -> 785 bytes demos/shared/images/button_pressed_stretch.png | Bin 0 -> 217 bytes demos/shared/images/curve_thing_edit-6.png | Bin 0 -> 58097 bytes demos/shared/images/frame_bottom.png | Bin 0 -> 166 bytes demos/shared/images/frame_bottomleft.png | Bin 0 -> 602 bytes demos/shared/images/frame_bottomright.png | Bin 0 -> 553 bytes demos/shared/images/frame_left.png | Bin 0 -> 182 bytes demos/shared/images/frame_right.png | Bin 0 -> 175 bytes demos/shared/images/frame_top.png | Bin 0 -> 188 bytes demos/shared/images/frame_topleft.png | Bin 0 -> 801 bytes demos/shared/images/frame_topright.png | Bin 0 -> 851 bytes demos/shared/images/groupframe_bottom_left.png | Bin 0 -> 397 bytes demos/shared/images/groupframe_bottom_right.png | Bin 0 -> 383 bytes demos/shared/images/groupframe_bottom_stretch.png | Bin 0 -> 141 bytes demos/shared/images/groupframe_left_stretch.png | Bin 0 -> 132 bytes demos/shared/images/groupframe_right_stretch.png | Bin 0 -> 113 bytes demos/shared/images/groupframe_top_stretch.png | Bin 0 -> 115 bytes demos/shared/images/groupframe_topleft.png | Bin 0 -> 412 bytes demos/shared/images/groupframe_topright.png | Bin 0 -> 449 bytes demos/shared/images/line_dash_dot.png | Bin 0 -> 151 bytes demos/shared/images/line_dash_dot_dot.png | Bin 0 -> 155 bytes demos/shared/images/line_dashed.png | Bin 0 -> 121 bytes demos/shared/images/line_dotted.png | Bin 0 -> 116 bytes demos/shared/images/line_solid.png | Bin 0 -> 110 bytes demos/shared/images/radiobutton-off.png | Bin 0 -> 442 bytes demos/shared/images/radiobutton-on.png | Bin 0 -> 474 bytes demos/shared/images/radiobutton_off.png | Bin 0 -> 442 bytes demos/shared/images/radiobutton_on.png | Bin 0 -> 499 bytes demos/shared/images/slider_bar.png | Bin 0 -> 748 bytes demos/shared/images/slider_thumb_off.png | Bin 0 -> 823 bytes demos/shared/images/slider_thumb_on.png | Bin 0 -> 798 bytes demos/shared/images/title_cap_left.png | Bin 0 -> 179 bytes demos/shared/images/title_cap_right.png | Bin 0 -> 184 bytes demos/shared/images/title_stretch.png | Bin 0 -> 106 bytes demos/shared/shared.pri | 21 + demos/shared/shared.pro | 38 + demos/shared/shared.qrc | 39 + examples/designer/README | 37 + .../calculatorbuilder/calculatorbuilder.pro | 16 + .../calculatorbuilder/calculatorbuilder.qrc | 5 + .../designer/calculatorbuilder/calculatorform.cpp | 91 + .../designer/calculatorbuilder/calculatorform.h | 70 + .../designer/calculatorbuilder/calculatorform.ui | 303 + examples/designer/calculatorbuilder/main.cpp | 53 + .../designer/calculatorform/calculatorform.cpp | 65 + examples/designer/calculatorform/calculatorform.h | 65 + .../designer/calculatorform/calculatorform.pro | 15 + examples/designer/calculatorform/calculatorform.ui | 284 + examples/designer/calculatorform/main.cpp | 52 + .../containerextension/containerextension.pro | 28 + .../containerextension/multipagewidget.cpp | 130 + .../designer/containerextension/multipagewidget.h | 87 + .../multipagewidgetcontainerextension.cpp | 100 + .../multipagewidgetcontainerextension.h | 74 + .../multipagewidgetextensionfactory.cpp | 64 + .../multipagewidgetextensionfactory.h | 63 + .../containerextension/multipagewidgetplugin.cpp | 196 + .../containerextension/multipagewidgetplugin.h | 80 + .../designer/customwidgetplugin/analogclock.cpp | 110 + examples/designer/customwidgetplugin/analogclock.h | 58 + .../customwidgetplugin/customwidgetplugin.cpp | 155 + .../customwidgetplugin/customwidgetplugin.h | 72 + .../customwidgetplugin/customwidgetplugin.pro | 23 + examples/designer/designer.pro | 21 + .../taskmenuextension/taskmenuextension.pro | 27 + examples/designer/taskmenuextension/tictactoe.cpp | 175 + examples/designer/taskmenuextension/tictactoe.h | 82 + .../designer/taskmenuextension/tictactoedialog.cpp | 98 + .../designer/taskmenuextension/tictactoedialog.h | 72 + .../designer/taskmenuextension/tictactoeplugin.cpp | 141 + .../designer/taskmenuextension/tictactoeplugin.h | 77 + .../taskmenuextension/tictactoetaskmenu.cpp | 103 + .../designer/taskmenuextension/tictactoetaskmenu.h | 87 + examples/designer/worldtimeclockbuilder/form.ui | 162 + examples/designer/worldtimeclockbuilder/main.cpp | 69 + .../worldtimeclockbuilder.pro | 13 + .../worldtimeclockbuilder.qrc | 5 + .../worldtimeclockplugin/worldtimeclock.cpp | 121 + .../designer/worldtimeclockplugin/worldtimeclock.h | 72 + .../worldtimeclockplugin/worldtimeclockplugin.cpp | 123 + .../worldtimeclockplugin/worldtimeclockplugin.h | 73 + .../worldtimeclockplugin/worldtimeclockplugin.pro | 23 + examples/examples.pro | 2 + examples/help/README | 38 + .../contextsensitivehelp/contextsensitivehelp.pro | 20 + examples/help/contextsensitivehelp/doc/amount.html | 11 + examples/help/contextsensitivehelp/doc/filter.html | 12 + examples/help/contextsensitivehelp/doc/plants.html | 44 + examples/help/contextsensitivehelp/doc/rain.html | 11 + examples/help/contextsensitivehelp/doc/source.html | 33 + .../help/contextsensitivehelp/doc/temperature.html | 13 + examples/help/contextsensitivehelp/doc/time.html | 11 + .../contextsensitivehelp/doc/wateringmachine.qch | Bin 0 -> 25600 bytes .../contextsensitivehelp/doc/wateringmachine.qhc | Bin 0 -> 8192 bytes .../contextsensitivehelp/doc/wateringmachine.qhcp | 14 + .../contextsensitivehelp/doc/wateringmachine.qhp | 25 + examples/help/contextsensitivehelp/helpbrowser.cpp | 80 + examples/help/contextsensitivehelp/helpbrowser.h | 64 + examples/help/contextsensitivehelp/main.cpp | 50 + .../contextsensitivehelp/wateringconfigdialog.cpp | 68 + .../contextsensitivehelp/wateringconfigdialog.h | 61 + .../contextsensitivehelp/wateringconfigdialog.ui | 446 + examples/help/help.pro | 13 + examples/help/remotecontrol/enter.png | Bin 0 -> 315 bytes examples/help/remotecontrol/main.cpp | 53 + examples/help/remotecontrol/remotecontrol.cpp | 174 + examples/help/remotecontrol/remotecontrol.h | 78 + examples/help/remotecontrol/remotecontrol.pro | 15 + examples/help/remotecontrol/remotecontrol.qrc | 5 + examples/help/remotecontrol/remotecontrol.ui | 228 + examples/help/simpletextviewer/assistant.cpp | 109 + examples/help/simpletextviewer/assistant.h | 62 + .../help/simpletextviewer/documentation/about.txt | 9 + .../simpletextviewer/documentation/browse.html | 34 + .../simpletextviewer/documentation/filedialog.html | 48 + .../simpletextviewer/documentation/findfile.html | 32 + .../documentation/images/browse.png | Bin 0 -> 21553 bytes .../documentation/images/fadedfilemenu.png | Bin 0 -> 9589 bytes .../documentation/images/filedialog.png | Bin 0 -> 12318 bytes .../documentation/images/handbook.png | Bin 0 -> 1060 bytes .../simpletextviewer/documentation/images/icon.png | Bin 0 -> 5513 bytes .../documentation/images/mainwindow.png | Bin 0 -> 12769 bytes .../simpletextviewer/documentation/images/open.png | Bin 0 -> 11697 bytes .../documentation/images/wildcard.png | Bin 0 -> 11266 bytes .../help/simpletextviewer/documentation/index.html | 41 + .../help/simpletextviewer/documentation/intro.html | 28 + .../simpletextviewer/documentation/openfile.html | 36 + .../documentation/simpletextviewer.qch | Bin 0 -> 108544 bytes .../documentation/simpletextviewer.qhc | Bin 0 -> 18432 bytes .../documentation/simpletextviewer.qhcp | 30 + .../documentation/simpletextviewer.qhp | 49 + .../documentation/wildcardmatching.html | 57 + examples/help/simpletextviewer/findfiledialog.cpp | 221 + examples/help/simpletextviewer/findfiledialog.h | 98 + examples/help/simpletextviewer/main.cpp | 51 + examples/help/simpletextviewer/mainwindow.cpp | 146 + examples/help/simpletextviewer/mainwindow.h | 83 + .../help/simpletextviewer/simpletextviewer.pro | 18 + examples/help/simpletextviewer/textedit.cpp | 74 + examples/help/simpletextviewer/textedit.h | 60 + qttools.pro | 12 + src/assistant/assistant.pro | 6 + .../lib/fulltextsearch/fulltextsearch.pri | 161 + .../lib/fulltextsearch/fulltextsearch.pro | 50 + src/assistant/lib/fulltextsearch/license.txt | 503 + src/assistant/lib/fulltextsearch/qanalyzer.cpp | 219 + src/assistant/lib/fulltextsearch/qanalyzer_p.h | 152 + .../lib/fulltextsearch/qclucene-config_p.h | 557 + .../lib/fulltextsearch/qclucene_global_p.h | 134 + src/assistant/lib/fulltextsearch/qdocument.cpp | 180 + src/assistant/lib/fulltextsearch/qdocument_p.h | 100 + src/assistant/lib/fulltextsearch/qfield.cpp | 171 + src/assistant/lib/fulltextsearch/qfield_p.h | 119 + src/assistant/lib/fulltextsearch/qfilter.cpp | 57 + src/assistant/lib/fulltextsearch/qfilter_p.h | 75 + src/assistant/lib/fulltextsearch/qhits.cpp | 94 + src/assistant/lib/fulltextsearch/qhits_p.h | 86 + src/assistant/lib/fulltextsearch/qindexreader.cpp | 169 + src/assistant/lib/fulltextsearch/qindexreader_p.h | 115 + src/assistant/lib/fulltextsearch/qindexwriter.cpp | 191 + src/assistant/lib/fulltextsearch/qindexwriter_p.h | 124 + src/assistant/lib/fulltextsearch/qquery.cpp | 358 + src/assistant/lib/fulltextsearch/qquery_p.h | 188 + src/assistant/lib/fulltextsearch/qqueryparser.cpp | 176 + src/assistant/lib/fulltextsearch/qqueryparser_p.h | 109 + src/assistant/lib/fulltextsearch/qreader.cpp | 101 + src/assistant/lib/fulltextsearch/qreader_p.h | 104 + src/assistant/lib/fulltextsearch/qsearchable.cpp | 203 + src/assistant/lib/fulltextsearch/qsearchable_p.h | 135 + src/assistant/lib/fulltextsearch/qsort.cpp | 97 + src/assistant/lib/fulltextsearch/qsort_p.h | 84 + src/assistant/lib/fulltextsearch/qterm.cpp | 134 + src/assistant/lib/fulltextsearch/qterm_p.h | 100 + src/assistant/lib/fulltextsearch/qtoken.cpp | 150 + src/assistant/lib/fulltextsearch/qtoken_p.h | 112 + src/assistant/lib/fulltextsearch/qtokenizer.cpp | 117 + src/assistant/lib/fulltextsearch/qtokenizer_p.h | 97 + src/assistant/lib/fulltextsearch/qtokenstream.cpp | 67 + src/assistant/lib/fulltextsearch/qtokenstream_p.h | 95 + src/assistant/lib/helpsystem.qrc | 8 + src/assistant/lib/images/1leftarrow.png | Bin 0 -> 669 bytes src/assistant/lib/images/1rightarrow.png | Bin 0 -> 706 bytes src/assistant/lib/images/3leftarrow.png | Bin 0 -> 832 bytes src/assistant/lib/images/3rightarrow.png | Bin 0 -> 820 bytes src/assistant/lib/lib.pro | 71 + src/assistant/lib/qclucenefieldnames.cpp | 57 + src/assistant/lib/qclucenefieldnames_p.h | 63 + src/assistant/lib/qhelp_global.cpp | 114 + src/assistant/lib/qhelp_global.h | 78 + src/assistant/lib/qhelpcollectionhandler.cpp | 603 + src/assistant/lib/qhelpcollectionhandler_p.h | 124 + src/assistant/lib/qhelpcontentwidget.cpp | 586 + src/assistant/lib/qhelpcontentwidget.h | 146 + src/assistant/lib/qhelpdatainterface.cpp | 273 + src/assistant/lib/qhelpdatainterface_p.h | 155 + src/assistant/lib/qhelpdbreader.cpp | 583 + src/assistant/lib/qhelpdbreader_p.h | 128 + src/assistant/lib/qhelpengine.cpp | 213 + src/assistant/lib/qhelpengine.h | 84 + src/assistant/lib/qhelpengine_p.h | 144 + src/assistant/lib/qhelpenginecore.cpp | 737 ++ src/assistant/lib/qhelpenginecore.h | 136 + src/assistant/lib/qhelpgenerator.cpp | 909 ++ src/assistant/lib/qhelpgenerator_p.h | 118 + src/assistant/lib/qhelpindexwidget.cpp | 444 + src/assistant/lib/qhelpindexwidget.h | 114 + src/assistant/lib/qhelpprojectdata.cpp | 450 + src/assistant/lib/qhelpprojectdata_p.h | 89 + src/assistant/lib/qhelpsearchengine.cpp | 450 + src/assistant/lib/qhelpsearchengine.h | 125 + src/assistant/lib/qhelpsearchindex_default.cpp | 60 + src/assistant/lib/qhelpsearchindex_default_p.h | 149 + src/assistant/lib/qhelpsearchindexreader.cpp | 104 + .../lib/qhelpsearchindexreader_clucene.cpp | 481 + .../lib/qhelpsearchindexreader_clucene_p.h | 114 + .../lib/qhelpsearchindexreader_default.cpp | 612 + .../lib/qhelpsearchindexreader_default_p.h | 131 + src/assistant/lib/qhelpsearchindexreader_p.h | 106 + .../lib/qhelpsearchindexwriter_clucene.cpp | 898 ++ .../lib/qhelpsearchindexwriter_clucene_p.h | 124 + .../lib/qhelpsearchindexwriter_default.cpp | 384 + .../lib/qhelpsearchindexwriter_default_p.h | 130 + src/assistant/lib/qhelpsearchquerywidget.cpp | 587 + src/assistant/lib/qhelpsearchquerywidget.h | 92 + src/assistant/lib/qhelpsearchresultwidget.cpp | 447 + src/assistant/lib/qhelpsearchresultwidget.h | 85 + src/assistant/tools/assistant/Info_mac.plist | 18 + src/assistant/tools/assistant/aboutdialog.cpp | 184 + src/assistant/tools/assistant/aboutdialog.h | 91 + src/assistant/tools/assistant/assistant.icns | Bin 0 -> 162568 bytes src/assistant/tools/assistant/assistant.ico | Bin 0 -> 355574 bytes src/assistant/tools/assistant/assistant.pro | 118 + src/assistant/tools/assistant/assistant.qch | Bin 0 -> 364544 bytes src/assistant/tools/assistant/assistant.qrc | 5 + src/assistant/tools/assistant/assistant.rc | 32 + src/assistant/tools/assistant/assistant_images.qrc | 37 + src/assistant/tools/assistant/bookmarkdialog.cpp | 237 + src/assistant/tools/assistant/bookmarkdialog.h | 89 + src/assistant/tools/assistant/bookmarkdialog.ui | 156 + .../tools/assistant/bookmarkfiltermodel.cpp | 321 + .../tools/assistant/bookmarkfiltermodel.h | 118 + src/assistant/tools/assistant/bookmarkitem.cpp | 184 + src/assistant/tools/assistant/bookmarkitem.h | 91 + src/assistant/tools/assistant/bookmarkmanager.cpp | 559 + src/assistant/tools/assistant/bookmarkmanager.h | 160 + .../tools/assistant/bookmarkmanagerwidget.cpp | 321 + .../tools/assistant/bookmarkmanagerwidget.h | 103 + .../tools/assistant/bookmarkmanagerwidget.ui | 137 + src/assistant/tools/assistant/bookmarkmodel.cpp | 461 + src/assistant/tools/assistant/bookmarkmodel.h | 117 + src/assistant/tools/assistant/bookmarkwidget.ui | 85 + src/assistant/tools/assistant/centralwidget.cpp | 636 ++ src/assistant/tools/assistant/centralwidget.h | 172 + src/assistant/tools/assistant/cmdlineparser.cpp | 376 + src/assistant/tools/assistant/cmdlineparser.h | 117 + src/assistant/tools/assistant/contentwindow.cpp | 204 + src/assistant/tools/assistant/contentwindow.h | 86 + src/assistant/tools/assistant/doc/HOWTO | 16 + src/assistant/tools/assistant/doc/assistant.qdoc | 461 + .../tools/assistant/doc/assistant.qdocconf | 16 + src/assistant/tools/assistant/doc/assistant.qhp | 22 + src/assistant/tools/assistant/doc/classic.css | 92 + .../doc/images/assistant-address-toolbar.png | Bin 0 -> 2899 bytes .../assistant/doc/images/assistant-assistant.png | Bin 0 -> 205326 bytes .../assistant/doc/images/assistant-dockwidgets.png | Bin 0 -> 50554 bytes .../assistant/doc/images/assistant-docwindow.png | Bin 0 -> 55582 bytes .../assistant/doc/images/assistant-examples.png | Bin 0 -> 9799 bytes .../doc/images/assistant-filter-toolbar.png | Bin 0 -> 1767 bytes .../images/assistant-preferences-documentation.png | Bin 0 -> 13417 bytes .../doc/images/assistant-preferences-filters.png | Bin 0 -> 15561 bytes .../doc/images/assistant-preferences-fonts.png | Bin 0 -> 13139 bytes .../doc/images/assistant-preferences-options.png | Bin 0 -> 14255 bytes .../assistant/doc/images/assistant-search.png | Bin 0 -> 59254 bytes .../assistant/doc/images/assistant-toolbar.png | Bin 0 -> 6532 bytes src/assistant/tools/assistant/filternamedialog.cpp | 77 + src/assistant/tools/assistant/filternamedialog.h | 67 + src/assistant/tools/assistant/filternamedialog.ui | 67 + src/assistant/tools/assistant/findwidget.cpp | 234 + src/assistant/tools/assistant/findwidget.h | 100 + src/assistant/tools/assistant/globalactions.cpp | 246 + src/assistant/tools/assistant/globalactions.h | 105 + .../tools/assistant/helpenginewrapper.cpp | 844 ++ src/assistant/tools/assistant/helpenginewrapper.h | 218 + src/assistant/tools/assistant/helpviewer.cpp | 221 + src/assistant/tools/assistant/helpviewer.h | 158 + src/assistant/tools/assistant/helpviewer_p.h | 123 + src/assistant/tools/assistant/helpviewer_qtb.cpp | 384 + src/assistant/tools/assistant/helpviewer_qwv.cpp | 495 + .../tools/assistant/images/assistant-128.png | Bin 0 -> 6448 bytes src/assistant/tools/assistant/images/assistant.png | Bin 0 -> 2034 bytes src/assistant/tools/assistant/images/bookmark.png | Bin 0 -> 1266 bytes .../tools/assistant/images/closebutton.png | Bin 0 -> 288 bytes .../tools/assistant/images/darkclosebutton.png | Bin 0 -> 319 bytes .../tools/assistant/images/mac/addtab.png | Bin 0 -> 469 bytes src/assistant/tools/assistant/images/mac/book.png | Bin 0 -> 1477 bytes .../tools/assistant/images/mac/closetab.png | Bin 0 -> 516 bytes .../tools/assistant/images/mac/editcopy.png | Bin 0 -> 1468 bytes src/assistant/tools/assistant/images/mac/find.png | Bin 0 -> 1836 bytes src/assistant/tools/assistant/images/mac/home.png | Bin 0 -> 1807 bytes src/assistant/tools/assistant/images/mac/next.png | Bin 0 -> 1310 bytes .../tools/assistant/images/mac/previous.png | Bin 0 -> 1080 bytes src/assistant/tools/assistant/images/mac/print.png | Bin 0 -> 2087 bytes .../tools/assistant/images/mac/resetzoom.png | Bin 0 -> 1567 bytes .../tools/assistant/images/mac/synctoc.png | Bin 0 -> 1838 bytes .../tools/assistant/images/mac/zoomin.png | Bin 0 -> 1696 bytes .../tools/assistant/images/mac/zoomout.png | Bin 0 -> 1662 bytes .../tools/assistant/images/trolltech-logo.png | Bin 0 -> 10096 bytes .../tools/assistant/images/win/addtab.png | Bin 0 -> 314 bytes src/assistant/tools/assistant/images/win/book.png | Bin 0 -> 1109 bytes .../tools/assistant/images/win/closetab.png | Bin 0 -> 375 bytes .../tools/assistant/images/win/editcopy.png | Bin 0 -> 1325 bytes src/assistant/tools/assistant/images/win/find.png | Bin 0 -> 1944 bytes src/assistant/tools/assistant/images/win/home.png | Bin 0 -> 1414 bytes src/assistant/tools/assistant/images/win/next.png | Bin 0 -> 1038 bytes .../tools/assistant/images/win/previous.png | Bin 0 -> 898 bytes src/assistant/tools/assistant/images/win/print.png | Bin 0 -> 1456 bytes .../tools/assistant/images/win/resetzoom.png | Bin 0 -> 1134 bytes .../tools/assistant/images/win/synctoc.png | Bin 0 -> 1235 bytes .../tools/assistant/images/win/zoomin.png | Bin 0 -> 1208 bytes .../tools/assistant/images/win/zoomout.png | Bin 0 -> 1226 bytes src/assistant/tools/assistant/images/wrap.png | Bin 0 -> 500 bytes src/assistant/tools/assistant/indexwindow.cpp | 231 + src/assistant/tools/assistant/indexwindow.h | 90 + src/assistant/tools/assistant/installdialog.cpp | 355 + src/assistant/tools/assistant/installdialog.h | 105 + src/assistant/tools/assistant/installdialog.ui | 118 + src/assistant/tools/assistant/main.cpp | 440 + src/assistant/tools/assistant/mainwindow.cpp | 1099 ++ src/assistant/tools/assistant/mainwindow.h | 172 + src/assistant/tools/assistant/openpagesmanager.cpp | 378 + src/assistant/tools/assistant/openpagesmanager.h | 115 + src/assistant/tools/assistant/openpagesmodel.cpp | 119 + src/assistant/tools/assistant/openpagesmodel.h | 76 + .../tools/assistant/openpagesswitcher.cpp | 194 + src/assistant/tools/assistant/openpagesswitcher.h | 85 + src/assistant/tools/assistant/openpageswidget.cpp | 237 + src/assistant/tools/assistant/openpageswidget.h | 92 + .../tools/assistant/preferencesdialog.cpp | 507 + src/assistant/tools/assistant/preferencesdialog.h | 110 + src/assistant/tools/assistant/preferencesdialog.ui | 400 + src/assistant/tools/assistant/qtdocinstaller.cpp | 128 + src/assistant/tools/assistant/qtdocinstaller.h | 84 + src/assistant/tools/assistant/remotecontrol.cpp | 388 + src/assistant/tools/assistant/remotecontrol.h | 96 + src/assistant/tools/assistant/remotecontrol_win.h | 68 + src/assistant/tools/assistant/searchwidget.cpp | 237 + src/assistant/tools/assistant/searchwidget.h | 90 + src/assistant/tools/assistant/topicchooser.cpp | 87 + src/assistant/tools/assistant/topicchooser.h | 73 + src/assistant/tools/assistant/topicchooser.ui | 116 + src/assistant/tools/assistant/tracer.h | 75 + src/assistant/tools/assistant/xbelsupport.cpp | 233 + src/assistant/tools/assistant/xbelsupport.h | 87 + src/assistant/tools/qcollectiongenerator/main.cpp | 615 + .../qcollectiongenerator/qcollectiongenerator.pro | 17 + src/assistant/tools/qhelpconverter/adpreader.cpp | 179 + src/assistant/tools/qhelpconverter/adpreader.h | 90 + .../tools/qhelpconverter/assistant-128.png | Bin 0 -> 6448 bytes src/assistant/tools/qhelpconverter/assistant.png | Bin 0 -> 2034 bytes .../tools/qhelpconverter/conversionwizard.cpp | 265 + .../tools/qhelpconverter/conversionwizard.h | 96 + .../tools/qhelpconverter/doc/filespage.html | 8 + .../tools/qhelpconverter/doc/filterpage.html | 13 + .../tools/qhelpconverter/doc/generalpage.html | 10 + .../tools/qhelpconverter/doc/identifierpage.html | 17 + .../tools/qhelpconverter/doc/inputpage.html | 7 + .../tools/qhelpconverter/doc/outputpage.html | 7 + .../tools/qhelpconverter/doc/pathpage.html | 8 + src/assistant/tools/qhelpconverter/filespage.cpp | 112 + src/assistant/tools/qhelpconverter/filespage.h | 73 + src/assistant/tools/qhelpconverter/filespage.ui | 79 + src/assistant/tools/qhelpconverter/filterpage.cpp | 147 + src/assistant/tools/qhelpconverter/filterpage.h | 79 + src/assistant/tools/qhelpconverter/filterpage.ui | 125 + src/assistant/tools/qhelpconverter/finishpage.cpp | 75 + src/assistant/tools/qhelpconverter/finishpage.h | 65 + src/assistant/tools/qhelpconverter/generalpage.cpp | 92 + src/assistant/tools/qhelpconverter/generalpage.h | 66 + src/assistant/tools/qhelpconverter/generalpage.ui | 69 + src/assistant/tools/qhelpconverter/helpwindow.cpp | 84 + src/assistant/tools/qhelpconverter/helpwindow.h | 65 + .../tools/qhelpconverter/identifierpage.cpp | 71 + .../tools/qhelpconverter/identifierpage.h | 66 + .../tools/qhelpconverter/identifierpage.ui | 132 + src/assistant/tools/qhelpconverter/inputpage.cpp | 103 + src/assistant/tools/qhelpconverter/inputpage.h | 71 + src/assistant/tools/qhelpconverter/inputpage.ui | 79 + src/assistant/tools/qhelpconverter/main.cpp | 77 + src/assistant/tools/qhelpconverter/outputpage.cpp | 110 + src/assistant/tools/qhelpconverter/outputpage.h | 71 + src/assistant/tools/qhelpconverter/outputpage.ui | 95 + src/assistant/tools/qhelpconverter/pathpage.cpp | 112 + src/assistant/tools/qhelpconverter/pathpage.h | 71 + src/assistant/tools/qhelpconverter/pathpage.ui | 114 + src/assistant/tools/qhelpconverter/qhcpwriter.cpp | 145 + src/assistant/tools/qhelpconverter/qhcpwriter.h | 70 + .../tools/qhelpconverter/qhelpconverter.pro | 47 + .../tools/qhelpconverter/qhelpconverter.qrc | 13 + src/assistant/tools/qhelpconverter/qhpwriter.cpp | 184 + src/assistant/tools/qhelpconverter/qhpwriter.h | 85 + src/assistant/tools/qhelpgenerator/main.cpp | 178 + .../tools/qhelpgenerator/qhelpgenerator.pro | 14 + .../tools/shared/collectionconfiguration.cpp | 327 + .../tools/shared/collectionconfiguration.h | 149 + src/assistant/tools/shared/helpgenerator.cpp | 84 + src/assistant/tools/shared/helpgenerator.h | 73 + src/assistant/tools/tools.pro | 8 + src/checksdk/README | 3 + src/checksdk/cesdkhandler.cpp | 132 + src/checksdk/cesdkhandler.h | 111 + src/checksdk/checksdk.pro | 36 + src/checksdk/main.cpp | 165 + src/designer/data/generate_header.xsl | 465 + src/designer/data/generate_impl.xsl | 1161 ++ src/designer/data/generate_shared.xsl | 331 + src/designer/data/ui3.xsd | 353 + src/designer/data/ui4.xsd | 589 + src/designer/designer.pro | 5 + .../src/components/buddyeditor/buddyeditor.cpp | 446 + .../src/components/buddyeditor/buddyeditor.h | 92 + .../src/components/buddyeditor/buddyeditor.pri | 16 + .../components/buddyeditor/buddyeditor_global.h | 57 + .../buddyeditor/buddyeditor_instance.cpp | 50 + .../components/buddyeditor/buddyeditor_plugin.cpp | 133 + .../components/buddyeditor/buddyeditor_plugin.h | 93 + .../components/buddyeditor/buddyeditor_tool.cpp | 111 + .../src/components/buddyeditor/buddyeditor_tool.h | 89 + src/designer/src/components/component.pri | 2 + src/designer/src/components/components.pro | 3 + .../components/formeditor/brushmanagerproxy.cpp | 303 + .../src/components/formeditor/brushmanagerproxy.h | 77 + .../formeditor/default_actionprovider.cpp | 207 + .../components/formeditor/default_actionprovider.h | 131 + .../components/formeditor/default_container.cpp | 173 + .../src/components/formeditor/default_container.h | 213 + .../formeditor/default_layoutdecoration.cpp | 79 + .../formeditor/default_layoutdecoration.h | 69 + .../src/components/formeditor/defaultbrushes.xml | 542 + .../components/formeditor/deviceprofiledialog.cpp | 203 + .../components/formeditor/deviceprofiledialog.h | 104 + .../components/formeditor/deviceprofiledialog.ui | 108 + .../src/components/formeditor/dpi_chooser.cpp | 207 + .../src/components/formeditor/dpi_chooser.h | 94 + .../components/formeditor/embeddedoptionspage.cpp | 453 + .../components/formeditor/embeddedoptionspage.h | 103 + .../src/components/formeditor/formeditor.cpp | 203 + .../src/components/formeditor/formeditor.h | 69 + .../src/components/formeditor/formeditor.pri | 77 + .../src/components/formeditor/formeditor.qrc | 175 + .../src/components/formeditor/formeditor_global.h | 57 + .../formeditor/formeditor_optionspage.cpp | 191 + .../components/formeditor/formeditor_optionspage.h | 79 + .../src/components/formeditor/formwindow.cpp | 2981 +++++ .../src/components/formeditor/formwindow.h | 374 + .../components/formeditor/formwindow_dnditem.cpp | 116 + .../src/components/formeditor/formwindow_dnditem.h | 65 + .../formeditor/formwindow_widgetstack.cpp | 217 + .../components/formeditor/formwindow_widgetstack.h | 102 + .../src/components/formeditor/formwindowcursor.cpp | 211 + .../src/components/formeditor/formwindowcursor.h | 93 + .../components/formeditor/formwindowmanager.cpp | 1036 ++ .../src/components/formeditor/formwindowmanager.h | 200 + .../components/formeditor/formwindowsettings.cpp | 282 + .../src/components/formeditor/formwindowsettings.h | 85 + .../components/formeditor/formwindowsettings.ui | 328 + .../src/components/formeditor/iconcache.cpp | 121 + src/designer/src/components/formeditor/iconcache.h | 78 + .../src/components/formeditor/images/cleartext.png | Bin 0 -> 760 bytes .../src/components/formeditor/images/color.png | Bin 0 -> 117 bytes .../src/components/formeditor/images/configure.png | Bin 0 -> 1016 bytes .../components/formeditor/images/cursors/arrow.png | Bin 0 -> 171 bytes .../components/formeditor/images/cursors/busy.png | Bin 0 -> 201 bytes .../formeditor/images/cursors/closedhand.png | Bin 0 -> 147 bytes .../components/formeditor/images/cursors/cross.png | Bin 0 -> 130 bytes .../components/formeditor/images/cursors/hand.png | Bin 0 -> 159 bytes .../formeditor/images/cursors/hsplit.png | Bin 0 -> 155 bytes .../components/formeditor/images/cursors/ibeam.png | Bin 0 -> 124 bytes .../components/formeditor/images/cursors/no.png | Bin 0 -> 199 bytes .../formeditor/images/cursors/openhand.png | Bin 0 -> 160 bytes .../formeditor/images/cursors/sizeall.png | Bin 0 -> 174 bytes .../components/formeditor/images/cursors/sizeb.png | Bin 0 -> 161 bytes .../components/formeditor/images/cursors/sizef.png | Bin 0 -> 161 bytes .../components/formeditor/images/cursors/sizeh.png | Bin 0 -> 145 bytes .../components/formeditor/images/cursors/sizev.png | Bin 0 -> 141 bytes .../formeditor/images/cursors/uparrow.png | Bin 0 -> 132 bytes .../formeditor/images/cursors/vsplit.png | Bin 0 -> 161 bytes .../components/formeditor/images/cursors/wait.png | Bin 0 -> 172 bytes .../formeditor/images/cursors/whatsthis.png | Bin 0 -> 191 bytes .../src/components/formeditor/images/downplus.png | Bin 0 -> 562 bytes .../formeditor/images/dropdownbutton.png | Bin 0 -> 527 bytes .../src/components/formeditor/images/edit.png | Bin 0 -> 929 bytes .../components/formeditor/images/editdelete-16.png | Bin 0 -> 553 bytes .../src/components/formeditor/images/emptyicon.png | Bin 0 -> 108 bytes .../components/formeditor/images/filenew-16.png | Bin 0 -> 454 bytes .../components/formeditor/images/fileopen-16.png | Bin 0 -> 549 bytes .../src/components/formeditor/images/leveldown.png | Bin 0 -> 557 bytes .../src/components/formeditor/images/levelup.png | Bin 0 -> 564 bytes .../formeditor/images/mac/adjustsize.png | Bin 0 -> 1929 bytes .../src/components/formeditor/images/mac/back.png | Bin 0 -> 678 bytes .../components/formeditor/images/mac/buddytool.png | Bin 0 -> 2046 bytes .../src/components/formeditor/images/mac/down.png | Bin 0 -> 594 bytes .../formeditor/images/mac/editbreaklayout.png | Bin 0 -> 2067 bytes .../components/formeditor/images/mac/editcopy.png | Bin 0 -> 1468 bytes .../components/formeditor/images/mac/editcut.png | Bin 0 -> 1512 bytes .../formeditor/images/mac/editdelete.png | Bin 0 -> 1097 bytes .../components/formeditor/images/mac/editform.png | Bin 0 -> 621 bytes .../components/formeditor/images/mac/editgrid.png | Bin 0 -> 751 bytes .../formeditor/images/mac/edithlayout.png | Bin 0 -> 1395 bytes .../formeditor/images/mac/edithlayoutsplit.png | Bin 0 -> 1188 bytes .../components/formeditor/images/mac/editlower.png | Bin 0 -> 595 bytes .../components/formeditor/images/mac/editpaste.png | Bin 0 -> 1906 bytes .../components/formeditor/images/mac/editraise.png | Bin 0 -> 1213 bytes .../formeditor/images/mac/editvlayout.png | Bin 0 -> 586 bytes .../formeditor/images/mac/editvlayoutsplit.png | Bin 0 -> 872 bytes .../components/formeditor/images/mac/filenew.png | Bin 0 -> 772 bytes .../components/formeditor/images/mac/fileopen.png | Bin 0 -> 904 bytes .../components/formeditor/images/mac/filesave.png | Bin 0 -> 1206 bytes .../components/formeditor/images/mac/forward.png | Bin 0 -> 655 bytes .../formeditor/images/mac/insertimage.png | Bin 0 -> 1280 bytes .../src/components/formeditor/images/mac/minus.png | Bin 0 -> 488 bytes .../src/components/formeditor/images/mac/plus.png | Bin 0 -> 810 bytes .../src/components/formeditor/images/mac/redo.png | Bin 0 -> 1752 bytes .../formeditor/images/mac/resetproperty.png | Bin 0 -> 169 bytes .../formeditor/images/mac/resourceeditortool.png | Bin 0 -> 2171 bytes .../formeditor/images/mac/signalslottool.png | Bin 0 -> 1989 bytes .../formeditor/images/mac/simplifyrichtext.png | Bin 0 -> 1988 bytes .../formeditor/images/mac/tabordertool.png | Bin 0 -> 1963 bytes .../formeditor/images/mac/textanchor.png | Bin 0 -> 2543 bytes .../components/formeditor/images/mac/textbold.png | Bin 0 -> 1611 bytes .../formeditor/images/mac/textcenter.png | Bin 0 -> 1404 bytes .../formeditor/images/mac/textitalic.png | Bin 0 -> 1164 bytes .../formeditor/images/mac/textjustify.png | Bin 0 -> 1257 bytes .../components/formeditor/images/mac/textleft.png | Bin 0 -> 1235 bytes .../components/formeditor/images/mac/textright.png | Bin 0 -> 1406 bytes .../formeditor/images/mac/textsubscript.png | Bin 0 -> 1054 bytes .../formeditor/images/mac/textsuperscript.png | Bin 0 -> 1109 bytes .../components/formeditor/images/mac/textunder.png | Bin 0 -> 1183 bytes .../src/components/formeditor/images/mac/undo.png | Bin 0 -> 1746 bytes .../src/components/formeditor/images/mac/up.png | Bin 0 -> 692 bytes .../formeditor/images/mac/widgettool.png | Bin 0 -> 1874 bytes .../src/components/formeditor/images/minus-16.png | Bin 0 -> 296 bytes .../src/components/formeditor/images/plus-16.png | Bin 0 -> 383 bytes .../components/formeditor/images/prefix-add.png | Bin 0 -> 411 bytes .../src/components/formeditor/images/qt3logo.png | Bin 0 -> 1101 bytes .../src/components/formeditor/images/qtlogo.png | Bin 0 -> 825 bytes .../src/components/formeditor/images/reload.png | Bin 0 -> 1363 bytes .../components/formeditor/images/resetproperty.png | Bin 0 -> 169 bytes .../src/components/formeditor/images/sort.png | Bin 0 -> 563 bytes .../src/components/formeditor/images/submenu.png | Bin 0 -> 179 bytes .../formeditor/images/widgets/calendarwidget.png | Bin 0 -> 968 bytes .../formeditor/images/widgets/checkbox.png | Bin 0 -> 817 bytes .../formeditor/images/widgets/columnview.png | Bin 0 -> 518 bytes .../formeditor/images/widgets/combobox.png | Bin 0 -> 853 bytes .../images/widgets/commandlinkbutton.png | Bin 0 -> 1208 bytes .../formeditor/images/widgets/dateedit.png | Bin 0 -> 672 bytes .../formeditor/images/widgets/datetimeedit.png | Bin 0 -> 1132 bytes .../components/formeditor/images/widgets/dial.png | Bin 0 -> 978 bytes .../formeditor/images/widgets/dialogbuttonbox.png | Bin 0 -> 1003 bytes .../formeditor/images/widgets/dockwidget.png | Bin 0 -> 638 bytes .../formeditor/images/widgets/doublespinbox.png | Bin 0 -> 749 bytes .../formeditor/images/widgets/fontcombobox.png | Bin 0 -> 966 bytes .../components/formeditor/images/widgets/frame.png | Bin 0 -> 721 bytes .../formeditor/images/widgets/graphicsview.png | Bin 0 -> 1182 bytes .../formeditor/images/widgets/groupbox.png | Bin 0 -> 439 bytes .../images/widgets/groupboxcollapsible.png | Bin 0 -> 702 bytes .../formeditor/images/widgets/hscrollbar.png | Bin 0 -> 408 bytes .../formeditor/images/widgets/hslider.png | Bin 0 -> 729 bytes .../formeditor/images/widgets/hsplit.png | Bin 0 -> 164 bytes .../components/formeditor/images/widgets/label.png | Bin 0 -> 953 bytes .../formeditor/images/widgets/lcdnumber.png | Bin 0 -> 555 bytes .../components/formeditor/images/widgets/line.png | Bin 0 -> 287 bytes .../formeditor/images/widgets/lineedit.png | Bin 0 -> 405 bytes .../formeditor/images/widgets/listbox.png | Bin 0 -> 797 bytes .../formeditor/images/widgets/listview.png | Bin 0 -> 756 bytes .../formeditor/images/widgets/mdiarea.png | Bin 0 -> 643 bytes .../formeditor/images/widgets/plaintextedit.png | Bin 0 -> 807 bytes .../formeditor/images/widgets/progress.png | Bin 0 -> 559 bytes .../formeditor/images/widgets/pushbutton.png | Bin 0 -> 408 bytes .../formeditor/images/widgets/radiobutton.png | Bin 0 -> 586 bytes .../formeditor/images/widgets/scrollarea.png | Bin 0 -> 548 bytes .../formeditor/images/widgets/spacer.png | Bin 0 -> 686 bytes .../formeditor/images/widgets/spinbox.png | Bin 0 -> 680 bytes .../formeditor/images/widgets/tabbar.png | Bin 0 -> 623 bytes .../components/formeditor/images/widgets/table.png | Bin 0 -> 483 bytes .../formeditor/images/widgets/tabwidget.png | Bin 0 -> 572 bytes .../formeditor/images/widgets/textedit.png | Bin 0 -> 823 bytes .../formeditor/images/widgets/timeedit.png | Bin 0 -> 1353 bytes .../formeditor/images/widgets/toolbox.png | Bin 0 -> 783 bytes .../formeditor/images/widgets/toolbutton.png | Bin 0 -> 1167 bytes .../components/formeditor/images/widgets/vline.png | Bin 0 -> 314 bytes .../formeditor/images/widgets/vscrollbar.png | Bin 0 -> 415 bytes .../formeditor/images/widgets/vslider.png | Bin 0 -> 726 bytes .../formeditor/images/widgets/vspacer.png | Bin 0 -> 677 bytes .../formeditor/images/widgets/widget.png | Bin 0 -> 716 bytes .../formeditor/images/widgets/widgetstack.png | Bin 0 -> 828 bytes .../formeditor/images/widgets/wizard.png | Bin 0 -> 898 bytes .../formeditor/images/win/adjustsize.png | Bin 0 -> 1262 bytes .../src/components/formeditor/images/win/back.png | Bin 0 -> 678 bytes .../components/formeditor/images/win/buddytool.png | Bin 0 -> 997 bytes .../src/components/formeditor/images/win/down.png | Bin 0 -> 594 bytes .../formeditor/images/win/editbreaklayout.png | Bin 0 -> 1321 bytes .../components/formeditor/images/win/editcopy.png | Bin 0 -> 1325 bytes .../components/formeditor/images/win/editcut.png | Bin 0 -> 1384 bytes .../formeditor/images/win/editdelete.png | Bin 0 -> 850 bytes .../components/formeditor/images/win/editform.png | Bin 0 -> 349 bytes .../components/formeditor/images/win/editgrid.png | Bin 0 -> 349 bytes .../formeditor/images/win/edithlayout.png | Bin 0 -> 455 bytes .../formeditor/images/win/edithlayoutsplit.png | Bin 0 -> 860 bytes .../components/formeditor/images/win/editlower.png | Bin 0 -> 1038 bytes .../components/formeditor/images/win/editpaste.png | Bin 0 -> 1482 bytes .../components/formeditor/images/win/editraise.png | Bin 0 -> 1045 bytes .../formeditor/images/win/editvlayout.png | Bin 0 -> 340 bytes .../formeditor/images/win/editvlayoutsplit.png | Bin 0 -> 740 bytes .../components/formeditor/images/win/filenew.png | Bin 0 -> 768 bytes .../components/formeditor/images/win/fileopen.png | Bin 0 -> 1662 bytes .../components/formeditor/images/win/filesave.png | Bin 0 -> 1205 bytes .../components/formeditor/images/win/forward.png | Bin 0 -> 655 bytes .../formeditor/images/win/insertimage.png | Bin 0 -> 885 bytes .../src/components/formeditor/images/win/minus.png | Bin 0 -> 429 bytes .../src/components/formeditor/images/win/plus.png | Bin 0 -> 709 bytes .../src/components/formeditor/images/win/redo.png | Bin 0 -> 1212 bytes .../formeditor/images/win/resourceeditortool.png | Bin 0 -> 1429 bytes .../formeditor/images/win/signalslottool.png | Bin 0 -> 1128 bytes .../formeditor/images/win/simplifyrichtext.png | Bin 0 -> 1933 bytes .../formeditor/images/win/tabordertool.png | Bin 0 -> 1205 bytes .../formeditor/images/win/textanchor.png | Bin 0 -> 1581 bytes .../components/formeditor/images/win/textbold.png | Bin 0 -> 1134 bytes .../formeditor/images/win/textcenter.png | Bin 0 -> 627 bytes .../formeditor/images/win/textitalic.png | Bin 0 -> 829 bytes .../formeditor/images/win/textjustify.png | Bin 0 -> 695 bytes .../components/formeditor/images/win/textleft.png | Bin 0 -> 673 bytes .../components/formeditor/images/win/textright.png | Bin 0 -> 677 bytes .../formeditor/images/win/textsubscript.png | Bin 0 -> 897 bytes .../formeditor/images/win/textsuperscript.png | Bin 0 -> 864 bytes .../components/formeditor/images/win/textunder.png | Bin 0 -> 971 bytes .../src/components/formeditor/images/win/undo.png | Bin 0 -> 1181 bytes .../src/components/formeditor/images/win/up.png | Bin 0 -> 692 bytes .../formeditor/images/win/widgettool.png | Bin 0 -> 1039 bytes .../formeditor/itemview_propertysheet.cpp | 270 + .../components/formeditor/itemview_propertysheet.h | 92 + .../components/formeditor/layout_propertysheet.cpp | 546 + .../components/formeditor/layout_propertysheet.h | 82 + .../components/formeditor/line_propertysheet.cpp | 86 + .../src/components/formeditor/line_propertysheet.h | 71 + .../components/formeditor/previewactiongroup.cpp | 149 + .../src/components/formeditor/previewactiongroup.h | 90 + .../components/formeditor/qdesigner_resource.cpp | 2475 ++++ .../src/components/formeditor/qdesigner_resource.h | 178 + .../components/formeditor/qdesignerundostack.cpp | 112 + .../src/components/formeditor/qdesignerundostack.h | 90 + .../formeditor/qlayoutwidget_propertysheet.cpp | 83 + .../formeditor/qlayoutwidget_propertysheet.h | 72 + .../formeditor/qmainwindow_container.cpp | 199 + .../components/formeditor/qmainwindow_container.h | 81 + .../components/formeditor/qmdiarea_container.cpp | 281 + .../src/components/formeditor/qmdiarea_container.h | 119 + .../src/components/formeditor/qtbrushmanager.cpp | 140 + .../src/components/formeditor/qtbrushmanager.h | 85 + .../components/formeditor/qwizard_container.cpp | 226 + .../src/components/formeditor/qwizard_container.h | 123 + .../components/formeditor/qworkspace_container.cpp | 100 + .../components/formeditor/qworkspace_container.h | 79 + .../components/formeditor/spacer_propertysheet.cpp | 82 + .../components/formeditor/spacer_propertysheet.h | 72 + .../components/formeditor/templateoptionspage.cpp | 183 + .../components/formeditor/templateoptionspage.h | 110 + .../components/formeditor/templateoptionspage.ui | 59 + .../components/formeditor/tool_widgeteditor.cpp | 363 + .../src/components/formeditor/tool_widgeteditor.h | 107 + .../src/components/formeditor/widgetselection.cpp | 746 ++ .../src/components/formeditor/widgetselection.h | 145 + src/designer/src/components/lib/lib.pro | 77 + src/designer/src/components/lib/lib_pch.h | 43 + .../src/components/lib/qdesigner_components.cpp | 277 + .../components/objectinspector/objectinspector.cpp | 835 ++ .../components/objectinspector/objectinspector.h | 95 + .../components/objectinspector/objectinspector.pri | 16 + .../objectinspector/objectinspector_global.h | 61 + .../objectinspector/objectinspectormodel.cpp | 516 + .../objectinspector/objectinspectormodel_p.h | 168 + .../propertyeditor/brushpropertymanager.cpp | 298 + .../propertyeditor/brushpropertymanager.h | 105 + .../propertyeditor/designerpropertymanager.cpp | 2836 +++++ .../propertyeditor/designerpropertymanager.h | 315 + .../src/components/propertyeditor/fontmapping.xml | 73 + .../propertyeditor/fontpropertymanager.cpp | 377 + .../propertyeditor/fontpropertymanager.h | 124 + .../propertyeditor/newdynamicpropertydialog.cpp | 170 + .../propertyeditor/newdynamicpropertydialog.h | 104 + .../propertyeditor/newdynamicpropertydialog.ui | 106 + .../components/propertyeditor/paletteeditor.cpp | 616 + .../src/components/propertyeditor/paletteeditor.h | 204 + .../src/components/propertyeditor/paletteeditor.ui | 264 + .../propertyeditor/paletteeditorbutton.cpp | 88 + .../propertyeditor/paletteeditorbutton.h | 86 + .../src/components/propertyeditor/previewframe.cpp | 119 + .../src/components/propertyeditor/previewframe.h | 76 + .../components/propertyeditor/previewwidget.cpp | 59 + .../src/components/propertyeditor/previewwidget.h | 66 + .../src/components/propertyeditor/previewwidget.ui | 238 + .../components/propertyeditor/propertyeditor.cpp | 1294 +++ .../src/components/propertyeditor/propertyeditor.h | 207 + .../components/propertyeditor/propertyeditor.pri | 52 + .../components/propertyeditor/propertyeditor.qrc | 5 + .../propertyeditor/propertyeditor_global.h | 61 + .../propertyeditor/qlonglongvalidator.cpp | 153 + .../components/propertyeditor/qlonglongvalidator.h | 110 + .../components/propertyeditor/stringlisteditor.cpp | 212 + .../components/propertyeditor/stringlisteditor.h | 92 + .../components/propertyeditor/stringlisteditor.ui | 265 + .../propertyeditor/stringlisteditorbutton.cpp | 81 + .../propertyeditor/stringlisteditorbutton.h | 81 + .../components/signalsloteditor/connectdialog.cpp | 335 + .../components/signalsloteditor/connectdialog.ui | 150 + .../components/signalsloteditor/connectdialog_p.h | 109 + .../signalsloteditor/signalslot_utils.cpp | 334 + .../signalsloteditor/signalslot_utils_p.h | 104 + .../signalsloteditor/signalsloteditor.cpp | 528 + .../components/signalsloteditor/signalsloteditor.h | 98 + .../signalsloteditor/signalsloteditor.pri | 21 + .../signalsloteditor/signalsloteditor_global.h | 57 + .../signalsloteditor/signalsloteditor_instance.cpp | 50 + .../signalsloteditor/signalsloteditor_p.h | 138 + .../signalsloteditor/signalsloteditor_plugin.cpp | 133 + .../signalsloteditor/signalsloteditor_plugin.h | 92 + .../signalsloteditor/signalsloteditor_tool.cpp | 123 + .../signalsloteditor/signalsloteditor_tool.h | 93 + .../signalsloteditor/signalsloteditorwindow.cpp | 864 ++ .../signalsloteditor/signalsloteditorwindow.h | 96 + .../components/tabordereditor/tabordereditor.cpp | 433 + .../src/components/tabordereditor/tabordereditor.h | 109 + .../components/tabordereditor/tabordereditor.pri | 16 + .../tabordereditor/tabordereditor_global.h | 57 + .../tabordereditor/tabordereditor_instance.cpp | 49 + .../tabordereditor/tabordereditor_plugin.cpp | 133 + .../tabordereditor/tabordereditor_plugin.h | 93 + .../tabordereditor/tabordereditor_tool.cpp | 114 + .../tabordereditor/tabordereditor_tool.h | 89 + .../src/components/taskmenu/button_taskmenu.cpp | 709 ++ .../src/components/taskmenu/button_taskmenu.h | 170 + .../src/components/taskmenu/combobox_taskmenu.cpp | 133 + .../src/components/taskmenu/combobox_taskmenu.h | 94 + .../taskmenu/containerwidget_taskmenu.cpp | 348 + .../components/taskmenu/containerwidget_taskmenu.h | 157 + .../src/components/taskmenu/groupbox_taskmenu.cpp | 105 + .../src/components/taskmenu/groupbox_taskmenu.h | 77 + .../src/components/taskmenu/inplace_editor.cpp | 136 + .../src/components/taskmenu/inplace_editor.h | 110 + .../components/taskmenu/inplace_widget_helper.cpp | 120 + .../components/taskmenu/inplace_widget_helper.h | 88 + .../src/components/taskmenu/itemlisteditor.cpp | 478 + .../src/components/taskmenu/itemlisteditor.h | 165 + .../src/components/taskmenu/itemlisteditor.ui | 156 + .../src/components/taskmenu/label_taskmenu.cpp | 117 + .../src/components/taskmenu/label_taskmenu.h | 81 + .../src/components/taskmenu/layouttaskmenu.cpp | 93 + .../src/components/taskmenu/layouttaskmenu.h | 93 + .../src/components/taskmenu/lineedit_taskmenu.cpp | 103 + .../src/components/taskmenu/lineedit_taskmenu.h | 74 + .../components/taskmenu/listwidget_taskmenu.cpp | 117 + .../src/components/taskmenu/listwidget_taskmenu.h | 85 + .../src/components/taskmenu/listwidgeteditor.cpp | 138 + .../src/components/taskmenu/listwidgeteditor.h | 78 + .../src/components/taskmenu/menutaskmenu.cpp | 107 + .../src/components/taskmenu/menutaskmenu.h | 106 + .../components/taskmenu/tablewidget_taskmenu.cpp | 115 + .../src/components/taskmenu/tablewidget_taskmenu.h | 85 + .../src/components/taskmenu/tablewidgeteditor.cpp | 450 + .../src/components/taskmenu/tablewidgeteditor.h | 130 + .../src/components/taskmenu/tablewidgeteditor.ui | 157 + src/designer/src/components/taskmenu/taskmenu.pri | 50 + .../src/components/taskmenu/taskmenu_component.cpp | 106 + .../src/components/taskmenu/taskmenu_component.h | 73 + .../src/components/taskmenu/taskmenu_global.h | 57 + .../src/components/taskmenu/textedit_taskmenu.cpp | 105 + .../src/components/taskmenu/textedit_taskmenu.h | 89 + .../src/components/taskmenu/toolbar_taskmenu.cpp | 111 + .../src/components/taskmenu/toolbar_taskmenu.h | 99 + .../components/taskmenu/treewidget_taskmenu.cpp | 114 + .../src/components/taskmenu/treewidget_taskmenu.h | 85 + .../src/components/taskmenu/treewidgeteditor.cpp | 642 ++ .../src/components/taskmenu/treewidgeteditor.h | 129 + .../src/components/taskmenu/treewidgeteditor.ui | 257 + .../src/components/widgetbox/widgetbox.cpp | 235 + src/designer/src/components/widgetbox/widgetbox.h | 103 + .../src/components/widgetbox/widgetbox.pri | 14 + .../src/components/widgetbox/widgetbox.qrc | 5 + .../src/components/widgetbox/widgetbox.xml | 932 ++ .../src/components/widgetbox/widgetbox_dnditem.cpp | 225 + .../src/components/widgetbox/widgetbox_dnditem.h | 67 + .../src/components/widgetbox/widgetbox_global.h | 57 + .../widgetbox/widgetboxcategorylistview.cpp | 510 + .../widgetbox/widgetboxcategorylistview.h | 118 + .../components/widgetbox/widgetboxtreewidget.cpp | 1001 ++ .../src/components/widgetbox/widgetboxtreewidget.h | 150 + src/designer/src/designer/Info_mac.plist | 35 + src/designer/src/designer/appfontdialog.cpp | 429 + src/designer/src/designer/appfontdialog.h | 101 + src/designer/src/designer/assistantclient.cpp | 175 + src/designer/src/designer/assistantclient.h | 83 + src/designer/src/designer/designer.icns | Bin 0 -> 154893 bytes src/designer/src/designer/designer.ico | Bin 0 -> 355574 bytes src/designer/src/designer/designer.pro | 90 + src/designer/src/designer/designer.qrc | 5 + src/designer/src/designer/designer.rc | 32 + src/designer/src/designer/designer_enums.h | 52 + src/designer/src/designer/images/designer.png | Bin 0 -> 4205 bytes src/designer/src/designer/images/mdi.png | Bin 0 -> 59505 bytes src/designer/src/designer/images/sdi.png | Bin 0 -> 61037 bytes src/designer/src/designer/images/workbench.png | Bin 0 -> 2085 bytes src/designer/src/designer/main.cpp | 58 + src/designer/src/designer/mainwindow.cpp | 419 + src/designer/src/designer/mainwindow.h | 187 + src/designer/src/designer/newform.cpp | 227 + src/designer/src/designer/newform.h | 104 + src/designer/src/designer/preferencesdialog.cpp | 118 + src/designer/src/designer/preferencesdialog.h | 82 + src/designer/src/designer/preferencesdialog.ui | 91 + src/designer/src/designer/qdesigner.cpp | 320 + src/designer/src/designer/qdesigner.h | 102 + src/designer/src/designer/qdesigner_actions.cpp | 1437 +++ src/designer/src/designer/qdesigner_actions.h | 231 + .../src/designer/qdesigner_appearanceoptions.cpp | 167 + .../src/designer/qdesigner_appearanceoptions.h | 136 + .../src/designer/qdesigner_appearanceoptions.ui | 57 + src/designer/src/designer/qdesigner_formwindow.cpp | 290 + src/designer/src/designer/qdesigner_formwindow.h | 97 + src/designer/src/designer/qdesigner_pch.h | 59 + src/designer/src/designer/qdesigner_server.cpp | 156 + src/designer/src/designer/qdesigner_server.h | 89 + src/designer/src/designer/qdesigner_settings.cpp | 250 + src/designer/src/designer/qdesigner_settings.h | 94 + src/designer/src/designer/qdesigner_toolwindow.cpp | 438 + src/designer/src/designer/qdesigner_toolwindow.h | 123 + src/designer/src/designer/qdesigner_workbench.cpp | 1100 ++ src/designer/src/designer/qdesigner_workbench.h | 215 + src/designer/src/designer/saveformastemplate.cpp | 173 + src/designer/src/designer/saveformastemplate.h | 77 + src/designer/src/designer/saveformastemplate.ui | 166 + src/designer/src/designer/uifile.icns | Bin 0 -> 123696 bytes src/designer/src/designer/versiondialog.cpp | 191 + src/designer/src/designer/versiondialog.h | 58 + .../src/lib/components/qdesigner_components.h | 82 + .../lib/components/qdesigner_components_global.h | 66 + .../src/lib/extension/default_extensionfactory.cpp | 178 + .../src/lib/extension/default_extensionfactory.h | 86 + src/designer/src/lib/extension/extension.cpp | 186 + src/designer/src/lib/extension/extension.h | 109 + src/designer/src/lib/extension/extension.pri | 12 + src/designer/src/lib/extension/extension_global.h | 64 + .../src/lib/extension/qextensionmanager.cpp | 174 + src/designer/src/lib/extension/qextensionmanager.h | 79 + src/designer/src/lib/lib.pro | 78 + src/designer/src/lib/lib_pch.h | 65 + src/designer/src/lib/sdk/abstractactioneditor.cpp | 123 + src/designer/src/lib/sdk/abstractactioneditor.h | 76 + src/designer/src/lib/sdk/abstractbrushmanager.h | 83 + src/designer/src/lib/sdk/abstractdialoggui.cpp | 161 + src/designer/src/lib/sdk/abstractdialoggui_p.h | 107 + src/designer/src/lib/sdk/abstractdnditem.h | 75 + src/designer/src/lib/sdk/abstractdnditem.qdoc | 98 + src/designer/src/lib/sdk/abstractformeditor.cpp | 630 ++ src/designer/src/lib/sdk/abstractformeditor.h | 159 + .../src/lib/sdk/abstractformeditorplugin.cpp | 86 + .../src/lib/sdk/abstractformeditorplugin.h | 73 + src/designer/src/lib/sdk/abstractformwindow.cpp | 814 ++ src/designer/src/lib/sdk/abstractformwindow.h | 183 + .../src/lib/sdk/abstractformwindowcursor.cpp | 252 + .../src/lib/sdk/abstractformwindowcursor.h | 109 + .../src/lib/sdk/abstractformwindowmanager.cpp | 502 + .../src/lib/sdk/abstractformwindowmanager.h | 122 + .../src/lib/sdk/abstractformwindowtool.cpp | 106 + src/designer/src/lib/sdk/abstractformwindowtool.h | 85 + src/designer/src/lib/sdk/abstracticoncache.h | 83 + src/designer/src/lib/sdk/abstracticoncache.qdoc | 116 + src/designer/src/lib/sdk/abstractintegration.cpp | 105 + src/designer/src/lib/sdk/abstractintegration.h | 86 + src/designer/src/lib/sdk/abstractintrospection.cpp | 548 + src/designer/src/lib/sdk/abstractintrospection_p.h | 174 + src/designer/src/lib/sdk/abstractlanguage.h | 100 + src/designer/src/lib/sdk/abstractmetadatabase.cpp | 170 + src/designer/src/lib/sdk/abstractmetadatabase.h | 99 + src/designer/src/lib/sdk/abstractnewformwidget.cpp | 117 + src/designer/src/lib/sdk/abstractnewformwidget_p.h | 88 + .../src/lib/sdk/abstractobjectinspector.cpp | 110 + src/designer/src/lib/sdk/abstractobjectinspector.h | 73 + src/designer/src/lib/sdk/abstractoptionspage_p.h | 79 + .../src/lib/sdk/abstractpromotioninterface.cpp | 113 + .../src/lib/sdk/abstractpromotioninterface.h | 91 + .../src/lib/sdk/abstractpropertyeditor.cpp | 193 + src/designer/src/lib/sdk/abstractpropertyeditor.h | 84 + .../src/lib/sdk/abstractresourcebrowser.cpp | 57 + src/designer/src/lib/sdk/abstractresourcebrowser.h | 75 + src/designer/src/lib/sdk/abstractsettings_p.h | 87 + src/designer/src/lib/sdk/abstractwidgetbox.cpp | 340 + src/designer/src/lib/sdk/abstractwidgetbox.h | 142 + .../src/lib/sdk/abstractwidgetdatabase.cpp | 360 + src/designer/src/lib/sdk/abstractwidgetdatabase.h | 137 + src/designer/src/lib/sdk/abstractwidgetfactory.cpp | 112 + src/designer/src/lib/sdk/abstractwidgetfactory.h | 79 + src/designer/src/lib/sdk/dynamicpropertysheet.h | 81 + src/designer/src/lib/sdk/dynamicpropertysheet.qdoc | 80 + src/designer/src/lib/sdk/extrainfo.cpp | 116 + src/designer/src/lib/sdk/extrainfo.h | 84 + src/designer/src/lib/sdk/layoutdecoration.h | 99 + src/designer/src/lib/sdk/layoutdecoration.qdoc | 149 + src/designer/src/lib/sdk/membersheet.h | 89 + src/designer/src/lib/sdk/membersheet.qdoc | 249 + src/designer/src/lib/sdk/propertysheet.h | 90 + src/designer/src/lib/sdk/propertysheet.qdoc | 288 + src/designer/src/lib/sdk/script.cpp | 109 + src/designer/src/lib/sdk/script_p.h | 83 + src/designer/src/lib/sdk/sdk.pri | 58 + src/designer/src/lib/sdk/sdk_global.h | 64 + src/designer/src/lib/sdk/taskmenu.h | 72 + src/designer/src/lib/sdk/taskmenu.qdoc | 138 + src/designer/src/lib/shared/actioneditor.cpp | 823 ++ src/designer/src/lib/shared/actioneditor_p.h | 168 + src/designer/src/lib/shared/actionprovider_p.h | 108 + src/designer/src/lib/shared/actionrepository.cpp | 665 ++ src/designer/src/lib/shared/actionrepository_p.h | 269 + src/designer/src/lib/shared/addlinkdialog.ui | 112 + src/designer/src/lib/shared/codedialog.cpp | 262 + src/designer/src/lib/shared/codedialog_p.h | 100 + src/designer/src/lib/shared/connectionedit.cpp | 1612 +++ src/designer/src/lib/shared/connectionedit_p.h | 324 + src/designer/src/lib/shared/csshighlighter.cpp | 188 + src/designer/src/lib/shared/csshighlighter_p.h | 82 + src/designer/src/lib/shared/defaultgradients.xml | 498 + src/designer/src/lib/shared/deviceprofile.cpp | 467 + src/designer/src/lib/shared/deviceprofile_p.h | 152 + src/designer/src/lib/shared/dialoggui.cpp | 265 + src/designer/src/lib/shared/dialoggui_p.h | 107 + src/designer/src/lib/shared/extensionfactory_p.h | 120 + src/designer/src/lib/shared/filterwidget.cpp | 252 + src/designer/src/lib/shared/filterwidget_p.h | 151 + src/designer/src/lib/shared/formlayoutmenu.cpp | 534 + src/designer/src/lib/shared/formlayoutmenu_p.h | 100 + src/designer/src/lib/shared/formlayoutrowdialog.ui | 166 + src/designer/src/lib/shared/formwindowbase.cpp | 502 + src/designer/src/lib/shared/formwindowbase_p.h | 205 + src/designer/src/lib/shared/grid.cpp | 194 + src/designer/src/lib/shared/grid_p.h | 118 + src/designer/src/lib/shared/gridpanel.cpp | 121 + src/designer/src/lib/shared/gridpanel.ui | 144 + src/designer/src/lib/shared/gridpanel_p.h | 101 + src/designer/src/lib/shared/htmlhighlighter.cpp | 198 + src/designer/src/lib/shared/htmlhighlighter_p.h | 101 + src/designer/src/lib/shared/iconloader.cpp | 79 + src/designer/src/lib/shared/iconloader_p.h | 72 + src/designer/src/lib/shared/iconselector.cpp | 655 ++ src/designer/src/lib/shared/iconselector_p.h | 172 + src/designer/src/lib/shared/invisible_widget.cpp | 57 + src/designer/src/lib/shared/invisible_widget_p.h | 75 + src/designer/src/lib/shared/layout.cpp | 1332 +++ src/designer/src/lib/shared/layout_p.h | 152 + src/designer/src/lib/shared/layoutinfo.cpp | 312 + src/designer/src/lib/shared/layoutinfo_p.h | 114 + src/designer/src/lib/shared/metadatabase.cpp | 295 + src/designer/src/lib/shared/metadatabase_p.h | 142 + src/designer/src/lib/shared/morphmenu.cpp | 635 ++ src/designer/src/lib/shared/morphmenu_p.h | 97 + src/designer/src/lib/shared/newactiondialog.cpp | 199 + src/designer/src/lib/shared/newactiondialog.ui | 313 + src/designer/src/lib/shared/newactiondialog_p.h | 124 + src/designer/src/lib/shared/newformwidget.cpp | 586 + src/designer/src/lib/shared/newformwidget.ui | 192 + src/designer/src/lib/shared/newformwidget_p.h | 143 + src/designer/src/lib/shared/orderdialog.cpp | 188 + src/designer/src/lib/shared/orderdialog.ui | 198 + src/designer/src/lib/shared/orderdialog_p.h | 114 + src/designer/src/lib/shared/plaintexteditor.cpp | 119 + src/designer/src/lib/shared/plaintexteditor_p.h | 89 + src/designer/src/lib/shared/plugindialog.cpp | 207 + src/designer/src/lib/shared/plugindialog.ui | 136 + src/designer/src/lib/shared/plugindialog_p.h | 92 + src/designer/src/lib/shared/pluginmanager.cpp | 786 ++ src/designer/src/lib/shared/pluginmanager_p.h | 159 + .../src/lib/shared/previewconfigurationwidget.cpp | 366 + .../src/lib/shared/previewconfigurationwidget.ui | 91 + .../src/lib/shared/previewconfigurationwidget_p.h | 96 + src/designer/src/lib/shared/previewmanager.cpp | 943 ++ src/designer/src/lib/shared/previewmanager_p.h | 184 + src/designer/src/lib/shared/promotionmodel.cpp | 220 + src/designer/src/lib/shared/promotionmodel_p.h | 98 + src/designer/src/lib/shared/promotiontaskmenu.cpp | 361 + src/designer/src/lib/shared/promotiontaskmenu_p.h | 151 + src/designer/src/lib/shared/propertylineedit.cpp | 96 + src/designer/src/lib/shared/propertylineedit_p.h | 85 + src/designer/src/lib/shared/qdesigner_command.cpp | 2968 +++++ src/designer/src/lib/shared/qdesigner_command2.cpp | 221 + src/designer/src/lib/shared/qdesigner_command2_p.h | 123 + src/designer/src/lib/shared/qdesigner_command_p.h | 1136 ++ src/designer/src/lib/shared/qdesigner_dnditem.cpp | 300 + src/designer/src/lib/shared/qdesigner_dnditem_p.h | 147 + .../src/lib/shared/qdesigner_dockwidget.cpp | 140 + .../src/lib/shared/qdesigner_dockwidget_p.h | 87 + .../src/lib/shared/qdesigner_formbuilder.cpp | 498 + .../src/lib/shared/qdesigner_formbuilder_p.h | 181 + .../src/lib/shared/qdesigner_formeditorcommand.cpp | 64 + .../src/lib/shared/qdesigner_formeditorcommand_p.h | 83 + .../src/lib/shared/qdesigner_formwindowcommand.cpp | 151 + .../src/lib/shared/qdesigner_formwindowcommand_p.h | 98 + .../src/lib/shared/qdesigner_formwindowmanager.cpp | 167 + .../src/lib/shared/qdesigner_formwindowmanager_p.h | 99 + .../src/lib/shared/qdesigner_integration.cpp | 496 + .../src/lib/shared/qdesigner_integration_p.h | 152 + .../src/lib/shared/qdesigner_introspection.cpp | 372 + .../src/lib/shared/qdesigner_introspection_p.h | 84 + .../src/lib/shared/qdesigner_membersheet.cpp | 371 + .../src/lib/shared/qdesigner_membersheet_p.h | 120 + src/designer/src/lib/shared/qdesigner_menu.cpp | 1390 +++ src/designer/src/lib/shared/qdesigner_menu_p.h | 208 + src/designer/src/lib/shared/qdesigner_menubar.cpp | 979 ++ src/designer/src/lib/shared/qdesigner_menubar_p.h | 179 + .../src/lib/shared/qdesigner_objectinspector.cpp | 80 + .../src/lib/shared/qdesigner_objectinspector_p.h | 103 + .../src/lib/shared/qdesigner_promotion.cpp | 373 + .../src/lib/shared/qdesigner_promotion_p.h | 98 + .../src/lib/shared/qdesigner_promotiondialog.cpp | 456 + .../src/lib/shared/qdesigner_promotiondialog_p.h | 170 + .../src/lib/shared/qdesigner_propertycommand.cpp | 1503 +++ .../src/lib/shared/qdesigner_propertycommand_p.h | 313 + .../src/lib/shared/qdesigner_propertyeditor.cpp | 169 + .../src/lib/shared/qdesigner_propertyeditor_p.h | 112 + .../src/lib/shared/qdesigner_propertysheet.cpp | 1657 +++ .../src/lib/shared/qdesigner_propertysheet_p.h | 266 + .../src/lib/shared/qdesigner_qsettings.cpp | 94 + .../src/lib/shared/qdesigner_qsettings_p.h | 88 + .../src/lib/shared/qdesigner_stackedbox.cpp | 399 + .../src/lib/shared/qdesigner_stackedbox_p.h | 164 + .../src/lib/shared/qdesigner_tabwidget.cpp | 572 + .../src/lib/shared/qdesigner_tabwidget_p.h | 153 + src/designer/src/lib/shared/qdesigner_taskmenu.cpp | 912 ++ src/designer/src/lib/shared/qdesigner_taskmenu_p.h | 133 + src/designer/src/lib/shared/qdesigner_toolbar.cpp | 488 + src/designer/src/lib/shared/qdesigner_toolbar_p.h | 135 + src/designer/src/lib/shared/qdesigner_toolbox.cpp | 437 + src/designer/src/lib/shared/qdesigner_toolbox_p.h | 140 + src/designer/src/lib/shared/qdesigner_utils.cpp | 848 ++ src/designer/src/lib/shared/qdesigner_utils_p.h | 499 + src/designer/src/lib/shared/qdesigner_widget.cpp | 108 + src/designer/src/lib/shared/qdesigner_widget_p.h | 122 + .../src/lib/shared/qdesigner_widgetbox.cpp | 181 + .../src/lib/shared/qdesigner_widgetbox_p.h | 101 + .../src/lib/shared/qdesigner_widgetitem.cpp | 345 + .../src/lib/shared/qdesigner_widgetitem_p.h | 147 + src/designer/src/lib/shared/qlayout_widget.cpp | 2107 ++++ src/designer/src/lib/shared/qlayout_widget_p.h | 292 + src/designer/src/lib/shared/qscripthighlighter.cpp | 468 + src/designer/src/lib/shared/qscripthighlighter_p.h | 84 + src/designer/src/lib/shared/qsimpleresource.cpp | 418 + src/designer/src/lib/shared/qsimpleresource_p.h | 164 + .../src/lib/shared/qtresourceeditordialog.cpp | 2223 ++++ .../src/lib/shared/qtresourceeditordialog.ui | 177 + .../src/lib/shared/qtresourceeditordialog_p.h | 130 + src/designer/src/lib/shared/qtresourcemodel.cpp | 650 ++ src/designer/src/lib/shared/qtresourcemodel_p.h | 145 + src/designer/src/lib/shared/qtresourceview.cpp | 906 ++ src/designer/src/lib/shared/qtresourceview_p.h | 141 + src/designer/src/lib/shared/richtexteditor.cpp | 906 ++ src/designer/src/lib/shared/richtexteditor_p.h | 103 + src/designer/src/lib/shared/scriptcommand.cpp | 103 + src/designer/src/lib/shared/scriptcommand_p.h | 93 + src/designer/src/lib/shared/scriptdialog.cpp | 130 + src/designer/src/lib/shared/scriptdialog_p.h | 90 + src/designer/src/lib/shared/scripterrordialog.cpp | 108 + src/designer/src/lib/shared/scripterrordialog_p.h | 83 + src/designer/src/lib/shared/selectsignaldialog.ui | 93 + src/designer/src/lib/shared/shared.pri | 189 + src/designer/src/lib/shared/shared.qrc | 20 + src/designer/src/lib/shared/shared_enums_p.h | 99 + src/designer/src/lib/shared/shared_global_p.h | 76 + src/designer/src/lib/shared/shared_settings.cpp | 321 + src/designer/src/lib/shared/shared_settings_p.h | 142 + src/designer/src/lib/shared/sheet_delegate.cpp | 112 + src/designer/src/lib/shared/sheet_delegate_p.h | 85 + src/designer/src/lib/shared/signalslotdialog.cpp | 526 + src/designer/src/lib/shared/signalslotdialog.ui | 129 + src/designer/src/lib/shared/signalslotdialog_p.h | 173 + src/designer/src/lib/shared/spacer_widget.cpp | 280 + src/designer/src/lib/shared/spacer_widget_p.h | 117 + src/designer/src/lib/shared/stylesheeteditor.cpp | 409 + src/designer/src/lib/shared/stylesheeteditor_p.h | 144 + .../forms/240x320/Dialog_with_Buttons_Bottom.ui | 67 + .../forms/240x320/Dialog_with_Buttons_Right.ui | 67 + .../forms/320x240/Dialog_with_Buttons_Bottom.ui | 67 + .../forms/320x240/Dialog_with_Buttons_Right.ui | 67 + .../forms/480x640/Dialog_with_Buttons_Bottom.ui | 67 + .../forms/480x640/Dialog_with_Buttons_Right.ui | 67 + .../forms/640x480/Dialog_with_Buttons_Bottom.ui | 67 + .../forms/640x480/Dialog_with_Buttons_Right.ui | 67 + .../templates/forms/Dialog_with_Buttons_Bottom.ui | 71 + .../templates/forms/Dialog_with_Buttons_Right.ui | 71 + .../templates/forms/Dialog_without_Buttons.ui | 18 + .../src/lib/shared/templates/forms/Main_Window.ui | 24 + .../src/lib/shared/templates/forms/Widget.ui | 21 + src/designer/src/lib/shared/textpropertyeditor.cpp | 430 + src/designer/src/lib/shared/textpropertyeditor_p.h | 156 + src/designer/src/lib/shared/widgetdatabase.cpp | 865 ++ src/designer/src/lib/shared/widgetdatabase_p.h | 210 + src/designer/src/lib/shared/widgetfactory.cpp | 899 ++ src/designer/src/lib/shared/widgetfactory_p.h | 191 + src/designer/src/lib/shared/zoomwidget.cpp | 570 + src/designer/src/lib/shared/zoomwidget_p.h | 231 + src/designer/src/plugins/activeqt/activeqt.pro | 32 + .../src/plugins/activeqt/qaxwidgetextrainfo.cpp | 117 + .../src/plugins/activeqt/qaxwidgetextrainfo.h | 91 + .../src/plugins/activeqt/qaxwidgetplugin.cpp | 146 + .../src/plugins/activeqt/qaxwidgetplugin.h | 77 + .../plugins/activeqt/qaxwidgetpropertysheet.cpp | 189 + .../src/plugins/activeqt/qaxwidgetpropertysheet.h | 99 + .../src/plugins/activeqt/qaxwidgettaskmenu.cpp | 186 + .../src/plugins/activeqt/qaxwidgettaskmenu.h | 76 + .../src/plugins/activeqt/qdesigneraxwidget.cpp | 272 + .../src/plugins/activeqt/qdesigneraxwidget.h | 142 + .../plugins/phononwidgets/images/seekslider.png | Bin 0 -> 444 bytes .../plugins/phononwidgets/images/videoplayer.png | Bin 0 -> 644 bytes .../plugins/phononwidgets/images/videowidget.png | Bin 0 -> 794 bytes .../plugins/phononwidgets/images/volumeslider.png | Bin 0 -> 470 bytes .../src/plugins/phononwidgets/phononcollection.cpp | 82 + .../src/plugins/phononwidgets/phononwidgets.pro | 24 + .../src/plugins/phononwidgets/phononwidgets.qrc | 8 + .../src/plugins/phononwidgets/seeksliderplugin.cpp | 117 + .../src/plugins/phononwidgets/seeksliderplugin.h | 75 + .../plugins/phononwidgets/videoplayerplugin.cpp | 135 + .../src/plugins/phononwidgets/videoplayerplugin.h | 75 + .../plugins/phononwidgets/videoplayertaskmenu.cpp | 154 + .../plugins/phononwidgets/videoplayertaskmenu.h | 83 + .../plugins/phononwidgets/volumesliderplugin.cpp | 117 + .../src/plugins/phononwidgets/volumesliderplugin.h | 75 + src/designer/src/plugins/plugins.pri | 8 + src/designer/src/plugins/plugins.pro | 10 + .../plugins/qdeclarativeview/qdeclarativeview.pro | 13 + .../qdeclarativeview/qdeclarativeview_plugin.cpp | 132 + .../qdeclarativeview/qdeclarativeview_plugin.h | 74 + .../src/plugins/qwebview/images/qwebview.png | Bin 0 -> 1473 bytes src/designer/src/plugins/qwebview/qwebview.pro | 15 + .../src/plugins/qwebview/qwebview_plugin.cpp | 137 + .../src/plugins/qwebview/qwebview_plugin.h | 74 + .../src/plugins/qwebview/qwebview_plugin.qrc | 5 + src/designer/src/plugins/tools/view3d/view3d.cpp | 492 + src/designer/src/plugins/tools/view3d/view3d.h | 77 + src/designer/src/plugins/tools/view3d/view3d.pro | 17 + .../src/plugins/tools/view3d/view3d_global.h | 61 + .../src/plugins/tools/view3d/view3d_plugin.cpp | 115 + .../src/plugins/tools/view3d/view3d_plugin.h | 82 + .../src/plugins/tools/view3d/view3d_tool.cpp | 88 + .../src/plugins/tools/view3d/view3d_tool.h | 76 + .../widgets/q3iconview/q3iconview_extrainfo.cpp | 183 + .../widgets/q3iconview/q3iconview_extrainfo.h | 95 + .../widgets/q3iconview/q3iconview_plugin.cpp | 120 + .../plugins/widgets/q3iconview/q3iconview_plugin.h | 76 + .../widgets/q3listbox/q3listbox_extrainfo.cpp | 151 + .../widgets/q3listbox/q3listbox_extrainfo.h | 93 + .../plugins/widgets/q3listbox/q3listbox_plugin.cpp | 121 + .../plugins/widgets/q3listbox/q3listbox_plugin.h | 76 + .../widgets/q3listview/q3listview_extrainfo.cpp | 249 + .../widgets/q3listview/q3listview_extrainfo.h | 96 + .../widgets/q3listview/q3listview_plugin.cpp | 121 + .../plugins/widgets/q3listview/q3listview_plugin.h | 76 + .../q3mainwindow/q3mainwindow_container.cpp | 130 + .../widgets/q3mainwindow/q3mainwindow_container.h | 84 + .../widgets/q3mainwindow/q3mainwindow_plugin.cpp | 118 + .../widgets/q3mainwindow/q3mainwindow_plugin.h | 76 + .../plugins/widgets/q3table/q3table_extrainfo.cpp | 196 + .../plugins/widgets/q3table/q3table_extrainfo.h | 93 + .../src/plugins/widgets/q3table/q3table_plugin.cpp | 121 + .../src/plugins/widgets/q3table/q3table_plugin.h | 76 + .../widgets/q3textedit/q3textedit_extrainfo.cpp | 116 + .../widgets/q3textedit/q3textedit_extrainfo.h | 93 + .../widgets/q3textedit/q3textedit_plugin.cpp | 122 + .../plugins/widgets/q3textedit/q3textedit_plugin.h | 76 + .../widgets/q3toolbar/q3toolbar_extrainfo.cpp | 108 + .../widgets/q3toolbar/q3toolbar_extrainfo.h | 92 + .../plugins/widgets/q3toolbar/q3toolbar_plugin.cpp | 128 + .../plugins/widgets/q3toolbar/q3toolbar_plugin.h | 76 + .../plugins/widgets/q3widgets/q3widget_plugins.cpp | 601 + .../plugins/widgets/q3widgets/q3widget_plugins.h | 287 + .../q3widgetstack/q3widgetstack_container.cpp | 115 + .../q3widgetstack/q3widgetstack_container.h | 84 + .../widgets/q3widgetstack/q3widgetstack_plugin.cpp | 118 + .../widgets/q3widgetstack/q3widgetstack_plugin.h | 76 + .../q3widgetstack/qdesigner_q3widgetstack.cpp | 217 + .../q3widgetstack/qdesigner_q3widgetstack_p.h | 108 + .../widgets/q3wizard/q3wizard_container.cpp | 235 + .../plugins/widgets/q3wizard/q3wizard_container.h | 149 + .../plugins/widgets/q3wizard/q3wizard_plugin.cpp | 128 + .../src/plugins/widgets/q3wizard/q3wizard_plugin.h | 76 + .../src/plugins/widgets/qt3supportwidgets.cpp | 107 + src/designer/src/plugins/widgets/widgets.pro | 82 + src/designer/src/sharedcomponents.pri | 30 + src/designer/src/src.pro | 12 + src/doxygen/config/footer.html | 8 + src/doxygen/config/header.html | 30 + src/doxygen/config/phonon.css | 114 + src/doxygen/config/phonon.doxyfile | 220 + src/kmap2qmap/kmap2qmap.pro | 12 + src/kmap2qmap/main.cpp | 991 ++ src/linguist/lconvert/lconvert.pro | 22 + src/linguist/lconvert/main.cpp | 301 + src/linguist/linguist.pro | 6 + src/linguist/linguist/Info_mac.plist | 18 + src/linguist/linguist/batchtranslation.ui | 260 + src/linguist/linguist/batchtranslationdialog.cpp | 194 + src/linguist/linguist/batchtranslationdialog.h | 87 + src/linguist/linguist/errorsview.cpp | 118 + src/linguist/linguist/errorsview.h | 78 + src/linguist/linguist/finddialog.cpp | 94 + src/linguist/linguist/finddialog.h | 69 + src/linguist/linguist/finddialog.ui | 266 + src/linguist/linguist/formpreviewview.cpp | 537 + src/linguist/linguist/formpreviewview.h | 128 + src/linguist/linguist/globals.cpp | 55 + src/linguist/linguist/globals.h | 50 + src/linguist/linguist/images/appicon.png | Bin 0 -> 1382 bytes src/linguist/linguist/images/down.png | Bin 0 -> 594 bytes src/linguist/linguist/images/editdelete.png | Bin 0 -> 831 bytes .../linguist/images/icons/linguist-128-32.png | Bin 0 -> 5960 bytes .../linguist/images/icons/linguist-128-8.png | Bin 0 -> 5947 bytes .../linguist/images/icons/linguist-16-32.png | Bin 0 -> 537 bytes .../linguist/images/icons/linguist-16-8.png | Bin 0 -> 608 bytes .../linguist/images/icons/linguist-32-32.png | Bin 0 -> 1382 bytes .../linguist/images/icons/linguist-32-8.png | Bin 0 -> 1369 bytes .../linguist/images/icons/linguist-48-32.png | Bin 0 -> 2017 bytes .../linguist/images/icons/linguist-48-8.png | Bin 0 -> 1972 bytes .../linguist/images/icons/linguist-64-32.png | Bin 0 -> 2773 bytes .../linguist/images/icons/linguist-64-8.png | Bin 0 -> 2664 bytes src/linguist/linguist/images/mac/accelerator.png | Bin 0 -> 1921 bytes src/linguist/linguist/images/mac/book.png | Bin 0 -> 1477 bytes src/linguist/linguist/images/mac/doneandnext.png | Bin 0 -> 1590 bytes src/linguist/linguist/images/mac/editcopy.png | Bin 0 -> 1468 bytes src/linguist/linguist/images/mac/editcut.png | Bin 0 -> 1512 bytes src/linguist/linguist/images/mac/editpaste.png | Bin 0 -> 1906 bytes src/linguist/linguist/images/mac/filenew.png | Bin 0 -> 1172 bytes src/linguist/linguist/images/mac/fileopen.png | Bin 0 -> 2168 bytes src/linguist/linguist/images/mac/fileprint.png | Bin 0 -> 741 bytes src/linguist/linguist/images/mac/filesave.png | Bin 0 -> 1206 bytes src/linguist/linguist/images/mac/next.png | Bin 0 -> 1056 bytes .../linguist/images/mac/nextunfinished.png | Bin 0 -> 1756 bytes src/linguist/linguist/images/mac/phrase.png | Bin 0 -> 1932 bytes src/linguist/linguist/images/mac/prev.png | Bin 0 -> 1080 bytes .../linguist/images/mac/prevunfinished.png | Bin 0 -> 1682 bytes src/linguist/linguist/images/mac/print.png | Bin 0 -> 2087 bytes src/linguist/linguist/images/mac/punctuation.png | Bin 0 -> 1593 bytes src/linguist/linguist/images/mac/redo.png | Bin 0 -> 1752 bytes src/linguist/linguist/images/mac/searchfind.png | Bin 0 -> 1836 bytes src/linguist/linguist/images/mac/undo.png | Bin 0 -> 1746 bytes .../linguist/images/mac/validateplacemarkers.png | Bin 0 -> 1452 bytes src/linguist/linguist/images/mac/whatsthis.png | Bin 0 -> 1586 bytes src/linguist/linguist/images/minus.png | Bin 0 -> 296 bytes src/linguist/linguist/images/plus.png | Bin 0 -> 383 bytes src/linguist/linguist/images/s_check_danger.png | Bin 0 -> 304 bytes src/linguist/linguist/images/s_check_empty.png | Bin 0 -> 404 bytes src/linguist/linguist/images/s_check_obsolete.png | Bin 0 -> 192 bytes src/linguist/linguist/images/s_check_off.png | Bin 0 -> 434 bytes src/linguist/linguist/images/s_check_on.png | Bin 0 -> 192 bytes src/linguist/linguist/images/s_check_warning.png | Bin 0 -> 192 bytes src/linguist/linguist/images/splash.png | Bin 0 -> 15637 bytes src/linguist/linguist/images/up.png | Bin 0 -> 692 bytes src/linguist/linguist/images/win/accelerator.png | Bin 0 -> 1335 bytes src/linguist/linguist/images/win/book.png | Bin 0 -> 1109 bytes src/linguist/linguist/images/win/doneandnext.png | Bin 0 -> 1233 bytes src/linguist/linguist/images/win/editcopy.png | Bin 0 -> 1325 bytes src/linguist/linguist/images/win/editcut.png | Bin 0 -> 1384 bytes src/linguist/linguist/images/win/editpaste.png | Bin 0 -> 1482 bytes src/linguist/linguist/images/win/filenew.png | Bin 0 -> 768 bytes src/linguist/linguist/images/win/fileopen.png | Bin 0 -> 1662 bytes src/linguist/linguist/images/win/filesave.png | Bin 0 -> 1205 bytes src/linguist/linguist/images/win/next.png | Bin 0 -> 1038 bytes .../linguist/images/win/nextunfinished.png | Bin 0 -> 1257 bytes src/linguist/linguist/images/win/phrase.png | Bin 0 -> 1371 bytes src/linguist/linguist/images/win/prev.png | Bin 0 -> 898 bytes .../linguist/images/win/prevunfinished.png | Bin 0 -> 1260 bytes src/linguist/linguist/images/win/print.png | Bin 0 -> 1456 bytes src/linguist/linguist/images/win/punctuation.png | Bin 0 -> 1508 bytes src/linguist/linguist/images/win/redo.png | Bin 0 -> 1212 bytes src/linguist/linguist/images/win/searchfind.png | Bin 0 -> 1944 bytes src/linguist/linguist/images/win/undo.png | Bin 0 -> 1181 bytes .../linguist/images/win/validateplacemarkers.png | Bin 0 -> 1994 bytes src/linguist/linguist/images/win/whatsthis.png | Bin 0 -> 1040 bytes src/linguist/linguist/linguist.icns | Bin 0 -> 152596 bytes src/linguist/linguist/linguist.ico | Bin 0 -> 355574 bytes src/linguist/linguist/linguist.pro | 96 + src/linguist/linguist/linguist.qrc | 57 + src/linguist/linguist/linguist.rc | 32 + src/linguist/linguist/main.cpp | 121 + src/linguist/linguist/mainwindow.cpp | 2724 +++++ src/linguist/linguist/mainwindow.h | 267 + src/linguist/linguist/mainwindow.ui | 892 ++ src/linguist/linguist/messageeditor.cpp | 880 ++ src/linguist/linguist/messageeditor.h | 180 + src/linguist/linguist/messageeditorwidgets.cpp | 456 + src/linguist/linguist/messageeditorwidgets.h | 184 + src/linguist/linguist/messagehighlighter.cpp | 210 + src/linguist/linguist/messagehighlighter.h | 83 + src/linguist/linguist/messagemodel.cpp | 1426 +++ src/linguist/linguist/messagemodel.h | 535 + src/linguist/linguist/phrase.cpp | 355 + src/linguist/linguist/phrase.h | 138 + src/linguist/linguist/phrasebookbox.cpp | 242 + src/linguist/linguist/phrasebookbox.h | 89 + src/linguist/linguist/phrasebookbox.ui | 236 + src/linguist/linguist/phrasemodel.cpp | 200 + src/linguist/linguist/phrasemodel.h | 94 + src/linguist/linguist/phraseview.cpp | 272 + src/linguist/linguist/phraseview.h | 120 + src/linguist/linguist/printout.cpp | 210 + src/linguist/linguist/printout.h | 120 + src/linguist/linguist/recentfiles.cpp | 146 + src/linguist/linguist/recentfiles.h | 83 + src/linguist/linguist/sourcecodeview.cpp | 145 + src/linguist/linguist/sourcecodeview.h | 74 + src/linguist/linguist/statistics.cpp | 67 + src/linguist/linguist/statistics.h | 67 + src/linguist/linguist/statistics.ui | 211 + src/linguist/linguist/translatedialog.cpp | 90 + src/linguist/linguist/translatedialog.h | 89 + src/linguist/linguist/translatedialog.ui | 260 + src/linguist/linguist/translationsettings.ui | 137 + .../linguist/translationsettingsdialog.cpp | 166 + src/linguist/linguist/translationsettingsdialog.h | 81 + src/linguist/lrelease/lrelease.1 | 118 + src/linguist/lrelease/lrelease.pro | 23 + src/linguist/lrelease/main.cpp | 391 + src/linguist/lupdate/cpp.cpp | 2245 ++++ src/linguist/lupdate/java.cpp | 645 ++ src/linguist/lupdate/lupdate.1 | 153 + src/linguist/lupdate/lupdate.exe.manifest | 14 + src/linguist/lupdate/lupdate.h | 86 + src/linguist/lupdate/lupdate.pro | 49 + src/linguist/lupdate/main.cpp | 730 ++ src/linguist/lupdate/merge.cpp | 515 + src/linguist/lupdate/qdeclarative.cpp | 433 + src/linguist/lupdate/qscript.cpp | 2612 +++++ src/linguist/lupdate/qscript.g | 2261 ++++ src/linguist/lupdate/ui.cpp | 208 + src/linguist/lupdate/winmanifest.rc | 4 + src/linguist/phrasebooks/danish.qph | 1018 ++ src/linguist/phrasebooks/dutch.qph | 1044 ++ src/linguist/phrasebooks/finnish.qph | 1033 ++ src/linguist/phrasebooks/french.qph | 1493 +++ src/linguist/phrasebooks/german.qph | 1075 ++ src/linguist/phrasebooks/hungarian.qph | 752 ++ src/linguist/phrasebooks/italian.qph | 1105 ++ src/linguist/phrasebooks/japanese.qph | 1021 ++ src/linguist/phrasebooks/norwegian.qph | 1004 ++ src/linguist/phrasebooks/polish.qph | 527 + src/linguist/phrasebooks/russian.qph | 1219 ++ src/linguist/phrasebooks/spanish.qph | 1086 ++ src/linguist/phrasebooks/swedish.qph | 1010 ++ src/linguist/qdoc.conf | 15 + src/linguist/shared/abstractproitemvisitor.h | 74 + src/linguist/shared/formats.pri | 22 + src/linguist/shared/numerus.cpp | 404 + src/linguist/shared/po.cpp | 902 ++ src/linguist/shared/profileevaluator.cpp | 2627 +++++ src/linguist/shared/profileevaluator.h | 116 + src/linguist/shared/proitems.cpp | 358 + src/linguist/shared/proitems.h | 248 + src/linguist/shared/proparser.pri | 12 + src/linguist/shared/proparserutils.h | 324 + src/linguist/shared/qm.cpp | 803 ++ src/linguist/shared/qph.cpp | 207 + src/linguist/shared/simtexth.cpp | 277 + src/linguist/shared/simtexth.h | 100 + src/linguist/shared/translator.cpp | 759 ++ src/linguist/shared/translator.h | 246 + src/linguist/shared/translatormessage.cpp | 187 + src/linguist/shared/translatormessage.h | 181 + src/linguist/shared/ts.cpp | 781 ++ src/linguist/shared/ts.dtd | 100 + src/linguist/shared/xliff.cpp | 851 ++ src/linguist/tests/data/main.cpp | 75 + src/linguist/tests/data/test.pro | 9 + src/linguist/tests/tests.pro | 16 + src/linguist/tests/tst_linguist.cpp | 45 + src/linguist/tests/tst_linguist.h | 63 + src/linguist/tests/tst_lupdate.cpp | 195 + src/linguist/tests/tst_simtexth.cpp | 73 + src/macdeployqt/macchangeqt/macchangeqt.pro | 9 + src/macdeployqt/macchangeqt/main.cpp | 76 + src/macdeployqt/macdeployqt.pro | 7 + src/macdeployqt/macdeployqt/macdeployqt.pro | 13 + src/macdeployqt/macdeployqt/main.cpp | 135 + src/macdeployqt/shared/shared.cpp | 586 + src/macdeployqt/shared/shared.h | 110 + src/macdeployqt/tests/deployment_mac.pro | 10 + src/macdeployqt/tests/tst_deployment_mac.cpp | 233 + src/makeqpf/Blocks.txt | 185 + src/makeqpf/README | 1 + src/makeqpf/main.cpp | 183 + src/makeqpf/mainwindow.cpp | 322 + src/makeqpf/mainwindow.h | 80 + src/makeqpf/mainwindow.ui | 502 + src/makeqpf/makeqpf.pro | 20 + src/makeqpf/makeqpf.qrc | 5 + src/makeqpf/qpf2.cpp | 767 ++ src/makeqpf/qpf2.h | 119 + src/pixeltool/Info_mac.plist | 18 + src/pixeltool/main.cpp | 65 + src/pixeltool/pixeltool.pro | 25 + src/pixeltool/qpixeltool.cpp | 536 + src/pixeltool/qpixeltool.h | 118 + src/qconfig/feature.cpp | 240 + src/qconfig/feature.h | 125 + src/qconfig/featuretreemodel.cpp | 451 + src/qconfig/featuretreemodel.h | 104 + src/qconfig/graphics.h | 195 + src/qconfig/main.cpp | 544 + src/qconfig/qconfig.pro | 9 + src/qdbus/qdbus.pro | 3 + src/qdbus/qdbus/qdbus.cpp | 528 + src/qdbus/qdbus/qdbus.pro | 10 + src/qdbus/qdbuscpp2xml/qdbuscpp2xml.cpp | 446 + src/qdbus/qdbuscpp2xml/qdbuscpp2xml.pro | 10 + src/qdbus/qdbusviewer/Info_mac.plist | 18 + src/qdbus/qdbusviewer/images/qdbusviewer-128.png | Bin 0 -> 9850 bytes src/qdbus/qdbusviewer/images/qdbusviewer.icns | Bin 0 -> 146951 bytes src/qdbus/qdbusviewer/images/qdbusviewer.ico | Bin 0 -> 355574 bytes src/qdbus/qdbusviewer/images/qdbusviewer.png | Bin 0 -> 1231 bytes src/qdbus/qdbusviewer/main.cpp | 85 + src/qdbus/qdbusviewer/propertydialog.cpp | 114 + src/qdbus/qdbusviewer/propertydialog.h | 70 + src/qdbus/qdbusviewer/qdbusmodel.cpp | 350 + src/qdbus/qdbusviewer/qdbusmodel.h | 95 + src/qdbus/qdbusviewer/qdbusviewer.cpp | 521 + src/qdbus/qdbusviewer/qdbusviewer.h | 103 + src/qdbus/qdbusviewer/qdbusviewer.pro | 30 + src/qdbus/qdbusviewer/qdbusviewer.qrc | 6 + src/qdbus/qdbusviewer/qdbusviewer.rc | 1 + src/qdbus/qdbusxml2cpp/qdbusxml2cpp.cpp | 1144 ++ src/qdbus/qdbusxml2cpp/qdbusxml2cpp.pro | 10 + src/qev/README | 2 + src/qev/qev.cpp | 66 + src/qev/qev.pro | 11 + src/qmeegographicssystemhelper/qmeegofencesync.cpp | 79 + src/qmeegographicssystemhelper/qmeegofencesync.h | 101 + src/qmeegographicssystemhelper/qmeegofencesync_p.h | 60 + .../qmeegographicssystemhelper.cpp | 147 + .../qmeegographicssystemhelper.h | 235 + .../qmeegographicssystemhelper.pro | 10 + .../qmeegolivepixmap.cpp | 117 + src/qmeegographicssystemhelper/qmeegolivepixmap.h | 112 + .../qmeegolivepixmap_p.h | 57 + .../qmeegooverlaywidget.cpp | 102 + .../qmeegooverlaywidget.h | 86 + src/qmeegographicssystemhelper/qmeegoruntime.cpp | 302 + src/qmeegographicssystemhelper/qmeegoruntime.h | 76 + .../qmeegoswitchevent.cpp | 68 + src/qmeegographicssystemhelper/qmeegoswitchevent.h | 91 + src/qtconcurrent/codegenerator/codegenerator.pri | 5 + src/qtconcurrent/codegenerator/example/example.pro | 9 + src/qtconcurrent/codegenerator/example/main.cpp | 83 + .../codegenerator/src/codegenerator.cpp | 140 + src/qtconcurrent/codegenerator/src/codegenerator.h | 204 + src/qtconcurrent/generaterun/main.cpp | 418 + src/qtconcurrent/generaterun/run.pro | 9 + src/qtconfig/colorbutton.cpp | 207 + src/qtconfig/colorbutton.h | 90 + src/qtconfig/images/appicon.png | Bin 0 -> 2238 bytes src/qtconfig/main.cpp | 69 + src/qtconfig/mainwindow.cpp | 956 ++ src/qtconfig/mainwindow.h | 109 + src/qtconfig/mainwindow.ui | 1388 +++ src/qtconfig/paletteeditoradvanced.cpp | 401 + src/qtconfig/paletteeditoradvanced.h | 106 + src/qtconfig/paletteeditoradvanced.ui | 416 + src/qtconfig/previewframe.cpp | 104 + src/qtconfig/previewframe.h | 83 + src/qtconfig/previewwidget.cpp | 89 + src/qtconfig/previewwidget.h | 70 + src/qtconfig/previewwidget.ui | 252 + src/qtconfig/qtconfig.pro | 28 + src/qtconfig/qtconfig.qrc | 5 + src/qtestlib/qtestlib.pro | 4 + src/qtestlib/updater/main.cpp | 178 + src/qtestlib/updater/updater.pro | 10 + src/qtestlib/wince/cetcpsync/cetcpsync.pro | 22 + src/qtestlib/wince/cetcpsync/main.cpp | 191 + .../wince/cetcpsync/qtcesterconnection.cpp | 552 + src/qtestlib/wince/cetcpsync/qtcesterconnection.h | 86 + src/qtestlib/wince/cetcpsync/remoteconnection.cpp | 65 + src/qtestlib/wince/cetcpsync/remoteconnection.h | 81 + .../wince/cetcpsyncserver/cetcpsyncserver.pro | 17 + src/qtestlib/wince/cetcpsyncserver/commands.cpp | 686 ++ src/qtestlib/wince/cetcpsyncserver/commands.h | 292 + .../wince/cetcpsyncserver/connectionmanager.cpp | 138 + .../wince/cetcpsyncserver/connectionmanager.h | 83 + src/qtestlib/wince/cetcpsyncserver/main.cpp | 63 + .../wince/cetcpsyncserver/transfer_global.h | 159 + src/qtestlib/wince/cetest/activesyncconnection.cpp | 640 ++ src/qtestlib/wince/cetest/activesyncconnection.h | 89 + src/qtestlib/wince/cetest/bootstrapped.pri | 45 + src/qtestlib/wince/cetest/cetcpsyncconnection.cpp | 221 + src/qtestlib/wince/cetest/cetcpsyncconnection.h | 85 + src/qtestlib/wince/cetest/cetest.pro | 56 + src/qtestlib/wince/cetest/deployment.cpp | 293 + src/qtestlib/wince/cetest/deployment.h | 75 + src/qtestlib/wince/cetest/main.cpp | 445 + src/qtestlib/wince/cetest/qmake_include.pri | 13 + src/qtestlib/wince/cetest/remoteconnection.cpp | 100 + src/qtestlib/wince/cetest/remoteconnection.h | 84 + src/qtestlib/wince/remotelib/commands.cpp | 212 + src/qtestlib/wince/remotelib/commands.h | 54 + src/qtestlib/wince/remotelib/remotelib.pro | 15 + src/qtestlib/wince/wince.pro | 2 + src/qttracereplay/main.cpp | 351 + src/qttracereplay/qttracereplay.pro | 15 + src/qvfb/README | 51 + src/qvfb/config.ui | 2472 ++++ src/qvfb/gammaview.h | 59 + src/qvfb/images/logo-nt.png | Bin 0 -> 1965 bytes src/qvfb/images/logo.png | Bin 0 -> 2238 bytes src/qvfb/main.cpp | 168 + src/qvfb/qanimationwriter.cpp | 453 + src/qvfb/qanimationwriter.h | 71 + src/qvfb/qtopiakeysym.h | 68 + src/qvfb/qvfb.cpp | 1147 ++ src/qvfb/qvfb.h | 159 + src/qvfb/qvfb.pro | 64 + src/qvfb/qvfb.qrc | 7 + src/qvfb/qvfbmmap.cpp | 222 + src/qvfb/qvfbmmap.h | 91 + src/qvfb/qvfbprotocol.cpp | 195 + src/qvfb/qvfbprotocol.h | 173 + src/qvfb/qvfbratedlg.cpp | 103 + src/qvfb/qvfbratedlg.h | 74 + src/qvfb/qvfbshmem.cpp | 314 + src/qvfb/qvfbshmem.h | 90 + src/qvfb/qvfbview.cpp | 888 ++ src/qvfb/qvfbview.h | 214 + src/qvfb/qvfbx11view.cpp | 389 + src/qvfb/qvfbx11view.h | 122 + src/qvfb/x11keyfaker.cpp | 627 ++ src/qvfb/x11keyfaker.h | 81 + src/runonphone/main.cpp | 277 + src/runonphone/ossignalconverter.cpp | 121 + src/runonphone/ossignalconverter.h | 63 + src/runonphone/ossignalconverter_p.h | 71 + src/runonphone/runonphone.pro | 35 + src/runonphone/serenum.h | 56 + src/runonphone/serenum_stub.cpp | 53 + src/runonphone/serenum_unix.cpp | 224 + src/runonphone/serenum_win.cpp | 105 + src/runonphone/symbianutils/bluetoothlistener.cpp | 224 + src/runonphone/symbianutils/bluetoothlistener.h | 103 + .../symbianutils/bluetoothlistener_gui.cpp | 111 + .../symbianutils/bluetoothlistener_gui.h | 89 + src/runonphone/symbianutils/callback.h | 160 + .../symbianutils/communicationstarter.cpp | 251 + src/runonphone/symbianutils/communicationstarter.h | 160 + src/runonphone/symbianutils/json.cpp | 490 + src/runonphone/symbianutils/json.h | 149 + src/runonphone/symbianutils/launcher.cpp | 1036 ++ src/runonphone/symbianutils/launcher.h | 212 + .../symbianutils/symbiandevicemanager.cpp | 489 + src/runonphone/symbianutils/symbiandevicemanager.h | 178 + src/runonphone/symbianutils/symbianutils.pri | 35 + src/runonphone/symbianutils/symbianutils_global.h | 55 + src/runonphone/symbianutils/tcftrkdevice.cpp | 929 ++ src/runonphone/symbianutils/tcftrkdevice.h | 295 + src/runonphone/symbianutils/tcftrkmessage.cpp | 562 + src/runonphone/symbianutils/tcftrkmessage.h | 296 + src/runonphone/symbianutils/trkdevice.cpp | 1184 ++ src/runonphone/symbianutils/trkdevice.h | 143 + src/runonphone/symbianutils/trkutils.cpp | 603 + src/runonphone/symbianutils/trkutils.h | 261 + src/runonphone/symbianutils/trkutils_p.h | 62 + src/runonphone/trksignalhandler.cpp | 368 + src/runonphone/trksignalhandler.h | 88 + src/shared/deviceskin/deviceskin.cpp | 857 ++ src/shared/deviceskin/deviceskin.h | 174 + src/shared/deviceskin/deviceskin.pri | 12 + src/shared/deviceskin/skins/ClamshellPhone.qrc | 5 + .../skins/ClamshellPhone.skin/ClamshellPhone.skin | 30 + .../ClamshellPhone1-5-closed.png | Bin 0 -> 68200 bytes .../ClamshellPhone1-5-pressed.png | Bin 0 -> 113907 bytes .../ClamshellPhone.skin/ClamshellPhone1-5.png | Bin 0 -> 113450 bytes .../skins/ClamshellPhone.skin/defaultbuttons.conf | 78 + src/shared/deviceskin/skins/PortableMedia.qrc | 5 + .../skins/PortableMedia.skin/PortableMedia.skin | 14 + .../skins/PortableMedia.skin/defaultbuttons.conf | 23 + .../PortableMedia.skin/portablemedia-pressed.png | Bin 0 -> 6183 bytes .../skins/PortableMedia.skin/portablemedia.png | Bin 0 -> 6182 bytes .../skins/PortableMedia.skin/portablemedia.xcf | Bin 0 -> 41592 bytes src/shared/deviceskin/skins/S60-QVGA-Candybar.qrc | 5 + .../S60-QVGA-Candybar-down.png | Bin 0 -> 161184 bytes .../S60-QVGA-Candybar.skin/S60-QVGA-Candybar.png | Bin 0 -> 156789 bytes .../S60-QVGA-Candybar.skin/S60-QVGA-Candybar.skin | 15 + .../S60-QVGA-Candybar.skin/defaultbuttons.conf | 78 + .../deviceskin/skins/S60-nHD-Touchscreen.qrc | 5 + .../S60-nHD-Touchscreen-down.png | Bin 0 -> 241501 bytes .../S60-nHD-Touchscreen.png | Bin 0 -> 240615 bytes .../S60-nHD-Touchscreen.skin | 10 + .../S60-nHD-Touchscreen.skin/defaultbuttons.conf | 53 + src/shared/deviceskin/skins/SmartPhone.qrc | 5 + .../skins/SmartPhone.skin/SmartPhone-pressed.png | Bin 0 -> 111515 bytes .../skins/SmartPhone.skin/SmartPhone.png | Bin 0 -> 101750 bytes .../skins/SmartPhone.skin/SmartPhone.skin | 28 + .../skins/SmartPhone.skin/defaultbuttons.conf | 78 + src/shared/deviceskin/skins/SmartPhone2.qrc | 5 + .../skins/SmartPhone2.skin/SmartPhone2-pressed.png | Bin 0 -> 134749 bytes .../skins/SmartPhone2.skin/SmartPhone2.png | Bin 0 -> 121915 bytes .../skins/SmartPhone2.skin/SmartPhone2.skin | 25 + .../skins/SmartPhone2.skin/defaultbuttons.conf | 52 + .../deviceskin/skins/SmartPhoneWithButtons.qrc | 5 + .../SmartPhoneWithButtons-pressed.png | Bin 0 -> 103838 bytes .../SmartPhoneWithButtons.png | Bin 0 -> 88470 bytes .../SmartPhoneWithButtons.skin | 31 + .../SmartPhoneWithButtons.skin/defaultbuttons.conf | 103 + src/shared/deviceskin/skins/TouchscreenPhone.qrc | 5 + .../TouchscreenPhone-pressed.png | Bin 0 -> 88599 bytes .../TouchscreenPhone.skin/TouchscreenPhone.png | Bin 0 -> 61809 bytes .../TouchscreenPhone.skin/TouchscreenPhone.skin | 16 + .../TouchscreenPhone.skin/defaultbuttons.conf | 45 + src/shared/findwidget/abstractfindwidget.cpp | 295 + src/shared/findwidget/abstractfindwidget.h | 115 + src/shared/findwidget/findwidget.pri | 4 + src/shared/findwidget/findwidget.qrc | 14 + src/shared/findwidget/images/mac/closetab.png | Bin 0 -> 516 bytes src/shared/findwidget/images/mac/next.png | Bin 0 -> 1310 bytes src/shared/findwidget/images/mac/previous.png | Bin 0 -> 1080 bytes src/shared/findwidget/images/mac/searchfind.png | Bin 0 -> 1836 bytes src/shared/findwidget/images/win/closetab.png | Bin 0 -> 375 bytes src/shared/findwidget/images/win/next.png | Bin 0 -> 1038 bytes src/shared/findwidget/images/win/previous.png | Bin 0 -> 898 bytes src/shared/findwidget/images/win/searchfind.png | Bin 0 -> 1944 bytes src/shared/findwidget/images/wrap.png | Bin 0 -> 500 bytes src/shared/findwidget/itemviewfindwidget.cpp | 317 + src/shared/findwidget/itemviewfindwidget.h | 78 + src/shared/findwidget/texteditfindwidget.cpp | 169 + src/shared/findwidget/texteditfindwidget.h | 73 + src/shared/fontpanel/fontpanel.cpp | 308 + src/shared/fontpanel/fontpanel.h | 108 + src/shared/fontpanel/fontpanel.pri | 3 + src/shared/qtgradienteditor/images/down.png | Bin 0 -> 594 bytes src/shared/qtgradienteditor/images/edit.png | Bin 0 -> 503 bytes src/shared/qtgradienteditor/images/editdelete.png | Bin 0 -> 831 bytes src/shared/qtgradienteditor/images/minus.png | Bin 0 -> 250 bytes src/shared/qtgradienteditor/images/plus.png | Bin 0 -> 462 bytes src/shared/qtgradienteditor/images/spreadpad.png | Bin 0 -> 151 bytes .../qtgradienteditor/images/spreadreflect.png | Bin 0 -> 165 bytes .../qtgradienteditor/images/spreadrepeat.png | Bin 0 -> 156 bytes src/shared/qtgradienteditor/images/typeconical.png | Bin 0 -> 937 bytes src/shared/qtgradienteditor/images/typelinear.png | Bin 0 -> 145 bytes src/shared/qtgradienteditor/images/typeradial.png | Bin 0 -> 583 bytes src/shared/qtgradienteditor/images/up.png | Bin 0 -> 692 bytes src/shared/qtgradienteditor/images/zoomin.png | Bin 0 -> 1208 bytes src/shared/qtgradienteditor/images/zoomout.png | Bin 0 -> 1226 bytes src/shared/qtgradienteditor/qtcolorbutton.cpp | 272 + src/shared/qtgradienteditor/qtcolorbutton.h | 86 + src/shared/qtgradienteditor/qtcolorbutton.pri | 4 + src/shared/qtgradienteditor/qtcolorline.cpp | 1122 ++ src/shared/qtgradienteditor/qtcolorline.h | 124 + src/shared/qtgradienteditor/qtgradientdialog.cpp | 353 + src/shared/qtgradienteditor/qtgradientdialog.h | 87 + src/shared/qtgradienteditor/qtgradientdialog.ui | 121 + src/shared/qtgradienteditor/qtgradienteditor.cpp | 952 ++ src/shared/qtgradienteditor/qtgradienteditor.h | 111 + src/shared/qtgradienteditor/qtgradienteditor.pri | 33 + src/shared/qtgradienteditor/qtgradienteditor.qrc | 18 + src/shared/qtgradienteditor/qtgradienteditor.ui | 1377 +++ src/shared/qtgradienteditor/qtgradientmanager.cpp | 135 + src/shared/qtgradienteditor/qtgradientmanager.h | 92 + .../qtgradienteditor/qtgradientstopscontroller.cpp | 724 ++ .../qtgradienteditor/qtgradientstopscontroller.h | 106 + .../qtgradienteditor/qtgradientstopsmodel.cpp | 477 + src/shared/qtgradienteditor/qtgradientstopsmodel.h | 121 + .../qtgradienteditor/qtgradientstopswidget.cpp | 1154 ++ .../qtgradienteditor/qtgradientstopswidget.h | 115 + src/shared/qtgradienteditor/qtgradientutils.cpp | 420 + src/shared/qtgradienteditor/qtgradientutils.h | 66 + src/shared/qtgradienteditor/qtgradientview.cpp | 292 + src/shared/qtgradienteditor/qtgradientview.h | 99 + src/shared/qtgradienteditor/qtgradientview.ui | 135 + .../qtgradienteditor/qtgradientviewdialog.cpp | 89 + src/shared/qtgradienteditor/qtgradientviewdialog.h | 75 + .../qtgradienteditor/qtgradientviewdialog.ui | 121 + src/shared/qtgradienteditor/qtgradientwidget.cpp | 815 ++ src/shared/qtgradienteditor/qtgradientwidget.h | 120 + .../qtpropertybrowser/images/cursor-arrow.png | Bin 0 -> 171 bytes .../qtpropertybrowser/images/cursor-busy.png | Bin 0 -> 201 bytes .../qtpropertybrowser/images/cursor-closedhand.png | Bin 0 -> 147 bytes .../qtpropertybrowser/images/cursor-cross.png | Bin 0 -> 130 bytes .../qtpropertybrowser/images/cursor-forbidden.png | Bin 0 -> 199 bytes .../qtpropertybrowser/images/cursor-hand.png | Bin 0 -> 159 bytes .../qtpropertybrowser/images/cursor-hsplit.png | Bin 0 -> 155 bytes .../qtpropertybrowser/images/cursor-ibeam.png | Bin 0 -> 124 bytes .../qtpropertybrowser/images/cursor-openhand.png | Bin 0 -> 160 bytes .../qtpropertybrowser/images/cursor-sizeall.png | Bin 0 -> 174 bytes .../qtpropertybrowser/images/cursor-sizeb.png | Bin 0 -> 161 bytes .../qtpropertybrowser/images/cursor-sizef.png | Bin 0 -> 161 bytes .../qtpropertybrowser/images/cursor-sizeh.png | Bin 0 -> 145 bytes .../qtpropertybrowser/images/cursor-sizev.png | Bin 0 -> 141 bytes .../qtpropertybrowser/images/cursor-uparrow.png | Bin 0 -> 132 bytes .../qtpropertybrowser/images/cursor-vsplit.png | Bin 0 -> 161 bytes .../qtpropertybrowser/images/cursor-wait.png | Bin 0 -> 172 bytes .../qtpropertybrowser/images/cursor-whatsthis.png | Bin 0 -> 191 bytes .../qtpropertybrowser/qtbuttonpropertybrowser.cpp | 627 ++ .../qtpropertybrowser/qtbuttonpropertybrowser.h | 85 + src/shared/qtpropertybrowser/qteditorfactory.cpp | 2560 +++++ src/shared/qtpropertybrowser/qteditorfactory.h | 397 + .../qtgroupboxpropertybrowser.cpp | 529 + .../qtpropertybrowser/qtgroupboxpropertybrowser.h | 76 + src/shared/qtpropertybrowser/qtpropertybrowser.cpp | 1955 ++++ src/shared/qtpropertybrowser/qtpropertybrowser.h | 309 + src/shared/qtpropertybrowser/qtpropertybrowser.pri | 19 + src/shared/qtpropertybrowser/qtpropertybrowser.qrc | 23 + .../qtpropertybrowser/qtpropertybrowserutils.cpp | 456 + .../qtpropertybrowser/qtpropertybrowserutils.pri | 4 + .../qtpropertybrowser/qtpropertybrowserutils_p.h | 161 + src/shared/qtpropertybrowser/qtpropertymanager.cpp | 6451 +++++++++++ src/shared/qtpropertybrowser/qtpropertymanager.h | 746 ++ .../qtpropertybrowser/qttreepropertybrowser.cpp | 1042 ++ .../qtpropertybrowser/qttreepropertybrowser.h | 134 + src/shared/qtpropertybrowser/qtvariantproperty.cpp | 2268 ++++ src/shared/qtpropertybrowser/qtvariantproperty.h | 177 + src/shared/qttoolbardialog/images/back.png | Bin 0 -> 678 bytes src/shared/qttoolbardialog/images/down.png | Bin 0 -> 594 bytes src/shared/qttoolbardialog/images/forward.png | Bin 0 -> 655 bytes src/shared/qttoolbardialog/images/minus.png | Bin 0 -> 250 bytes src/shared/qttoolbardialog/images/plus.png | Bin 0 -> 462 bytes src/shared/qttoolbardialog/images/up.png | Bin 0 -> 692 bytes src/shared/qttoolbardialog/qttoolbardialog.cpp | 1871 +++ src/shared/qttoolbardialog/qttoolbardialog.h | 138 + src/shared/qttoolbardialog/qttoolbardialog.pri | 6 + src/shared/qttoolbardialog/qttoolbardialog.qrc | 10 + src/shared/qttoolbardialog/qttoolbardialog.ui | 207 + src/tools.pro | 49 + tests/README | 18 + tests/auto/auto.pro | 9 + tests/auto/bic/.gitignore | 2 + .../bic/data/QtDesigner.4.2.0.linux-gcc-ia32.txt | 1985 ++++ .../bic/data/QtDesigner.4.3.0.linux-gcc-ia32.txt | 2169 ++++ .../bic/data/QtDesigner.4.4.0.linux-gcc-ia32.txt | 4431 ++++++++ .../bic/data/QtDesigner.4.5.0.linux-gcc-amd64.txt | 4460 ++++++++ .../bic/data/QtDesigner.4.5.0.linux-gcc-ia32.txt | 4460 ++++++++ .../bic/data/QtDesigner.4.6.0.linux-gcc-amd64.txt | 4741 ++++++++ .../bic/data/QtDesigner.4.6.0.linux-gcc-ia32.txt | 4741 ++++++++ .../bic/data/QtDesigner.4.7.0.linux-gcc-ia32.txt | 4746 ++++++++ .../auto/bic/data/QtHelp.4.5.0.linux-gcc-amd64.txt | 6357 +++++++++++ .../auto/bic/data/QtHelp.4.5.0.linux-gcc-ia32.txt | 6357 +++++++++++ .../auto/bic/data/QtHelp.4.6.0.linux-gcc-amd64.txt | 5492 +++++++++ .../auto/bic/data/QtHelp.4.6.0.linux-gcc-ia32.txt | 5492 +++++++++ .../auto/bic/data/QtHelp.4.7.0.linux-gcc-ia32.txt | 5497 +++++++++ tests/auto/linguist/lconvert/.gitignore | 2 + tests/auto/linguist/lconvert/data/codec-cp1252.ts | 28 + tests/auto/linguist/lconvert/data/codec-utf8.ts | 28 + tests/auto/linguist/lconvert/data/dual-encoding.ts | 11 + .../auto/linguist/lconvert/data/endless-po-loop.ts | 16 + tests/auto/linguist/lconvert/data/makeplurals.pl | 86 + tests/auto/linguist/lconvert/data/msgid.ts | 27 + tests/auto/linguist/lconvert/data/phrasebook.qph | 21 + tests/auto/linguist/lconvert/data/plurals-cn.ts | 17 + tests/auto/linguist/lconvert/data/plurals-de.ts | 18 + tests/auto/linguist/lconvert/data/relative.ts | 74 + tests/auto/linguist/lconvert/data/singular.po | 42 + .../linguist/lconvert/data/test-broken-utf8.po | 9 + .../linguist/lconvert/data/test-broken-utf8.po.out | 12 + .../lconvert/data/test-developer-comment.po | 23 + .../linguist/lconvert/data/test-empty-comment.po | 24 + tests/auto/linguist/lconvert/data/test-escapes.po | 11 + .../linguist/lconvert/data/test-escapes.po.out | 16 + tests/auto/linguist/lconvert/data/test-kde-ctxt.po | 25 + .../auto/linguist/lconvert/data/test-kde-fuzzy.po | 31 + .../linguist/lconvert/data/test-kde-multiline.po | 32 + .../linguist/lconvert/data/test-kde-plurals.po | 27 + tests/auto/linguist/lconvert/data/test-refs.po | 23 + tests/auto/linguist/lconvert/data/test-slurp.po | 19 + .../auto/linguist/lconvert/data/test-slurp.po.out | 22 + .../lconvert/data/test-translator-comment.po | 41 + tests/auto/linguist/lconvert/data/test1-cn.po | 67 + tests/auto/linguist/lconvert/data/test1-de.po | 75 + tests/auto/linguist/lconvert/data/test11.ts | 32 + tests/auto/linguist/lconvert/data/test20.ts | 171 + tests/auto/linguist/lconvert/data/variants.ts | 24 + tests/auto/linguist/lconvert/data/wrapping.po | 57 + tests/auto/linguist/lconvert/lconvert.pro | 8 + tests/auto/linguist/lconvert/tst_lconvert.cpp | 347 + tests/auto/linguist/linguist.pro | 2 + tests/auto/linguist/lrelease/.gitignore | 2 + tests/auto/linguist/lrelease/lrelease.pro | 5 + .../auto/linguist/lrelease/testdata/compressed.ts | 46 + tests/auto/linguist/lrelease/testdata/dupes.errors | 4 + tests/auto/linguist/lrelease/testdata/dupes.ts | 25 + tests/auto/linguist/lrelease/testdata/idbased.ts | 28 + .../linguist/lrelease/testdata/mixedcodecs-ts11.ts | 18 + .../linguist/lrelease/testdata/mixedcodecs-ts20.ts | 18 + tests/auto/linguist/lrelease/testdata/translate.ts | 136 + tests/auto/linguist/lrelease/tst_lrelease.cpp | 241 + tests/auto/linguist/lupdate/.gitignore | 4 + tests/auto/linguist/lupdate/lupdate.pro | 6 + .../lupdate/testdata/good/backslashes/lupdatecmd | 1 + .../lupdate/testdata/good/backslashes/project.pro | 3 + .../lupdate/testdata/good/backslashes/src/main.cpp | 56 + .../testdata/good/backslashes/ts/project.ts.result | 13 + .../testdata/good/cmdline_deeppath/lupdatecmd | 2 + .../good/cmdline_deeppath/project.ts.result | 27 + .../lupdate/testdata/good/cmdline_order/a.h | 42 + .../lupdate/testdata/good/cmdline_order/b.h | 44 + .../lupdate/testdata/good/cmdline_order/lupdatecmd | 1 + .../testdata/good/cmdline_order/project.ts.result | 20 + .../testdata/good/cmdline_recurse/lupdatecmd | 2 + .../good/cmdline_recurse/project.ts.result | 115 + .../lupdate/testdata/good/codecforsrc/main.cpp | 68 + .../lupdate/testdata/good/codecforsrc/project.pro | 7 + .../testdata/good/codecforsrc/project.ts.result | 38 + .../lupdate/testdata/good/codecfortr/main.cpp | 65 + .../lupdate/testdata/good/codecfortr/project.pro | 6 + .../testdata/good/codecfortr/project.ts.result | 13 + .../lupdate/testdata/good/codecfortr1/main.cpp | 63 + .../lupdate/testdata/good/codecfortr1/project.pro | 6 + .../testdata/good/codecfortr1/project.ts.result | 38 + .../lupdate/testdata/good/codecfortr2/main.cpp | 62 + .../lupdate/testdata/good/codecfortr2/project.pro | 7 + .../testdata/good/codecfortr2/project.ts.result | 33 + .../testdata/good/codecfortr3/expectedoutput.txt | 1 + .../lupdate/testdata/good/codecfortr3/main.cpp | 45 + .../lupdate/testdata/good/codecfortr3/project.pro | 4 + .../testdata/good/codecfortr3/project.ts.before | 13 + .../testdata/good/codecfortr3/project.ts.result | 12 + .../testdata/good/codecfortr4/expectedoutput.txt | 0 .../lupdate/testdata/good/codecfortr4/main.cpp | 45 + .../lupdate/testdata/good/codecfortr4/project.pro | 4 + .../testdata/good/codecfortr4/project.ts.before | 13 + .../testdata/good/codecfortr4/project.ts.result | 13 + .../lupdate/testdata/good/from_subdir/lupdatecmd | 1 + .../testdata/good/from_subdir/project.ts.result | 17 + .../lupdate/testdata/good/from_subdir/src/main.cpp | 50 + .../lupdate/testdata/good/from_subdir/src/main.h | 45 + .../good/from_subdir/translations/translations.pro | 7 + .../testdata/good/heuristics/expectedoutput.txt | 5 + .../lupdate/testdata/good/heuristics/lupdatecmd | 2 + .../lupdate/testdata/good/heuristics/main.cpp | 62 + .../lupdate/testdata/good/heuristics/project.pro | 3 + .../testdata/good/heuristics/project.ts.before | 38 + .../testdata/good/heuristics/project.ts.result | 22 + .../testdata/good/lacksqobject/expectedoutput.txt | 4 + .../lupdate/testdata/good/lacksqobject/main.cpp | 88 + .../lupdate/testdata/good/lacksqobject/project.pro | 3 + .../testdata/good/lacksqobject/project.ts.result | 40 + .../lupdate/testdata/good/merge_ordering/foo.cpp | 69 + .../testdata/good/merge_ordering/lupdatecmd | 1 + .../testdata/good/merge_ordering/project.pro | 3 + .../testdata/good/merge_ordering/project.ts.before | 74 + .../testdata/good/merge_ordering/project.ts.result | 82 + .../testdata/good/merge_versions/project.pro | 3 + .../testdata/good/merge_versions/project.ts.before | 14 + .../testdata/good/merge_versions/project.ts.result | 15 + .../testdata/good/merge_versions/project.ui | 72 + .../testdata/good/merge_whitespace/main.cpp | 64 + .../testdata/good/merge_whitespace/project.pro | 3 + .../good/merge_whitespace/project.ts.before | 70 + .../good/merge_whitespace/project.ts.result | 71 + .../lupdate/testdata/good/mergecpp/finddialog.cpp | 82 + .../lupdate/testdata/good/mergecpp/project.pro | 3 + .../testdata/good/mergecpp/project.ts.before | 70 + .../testdata/good/mergecpp/project.ts.result | 74 + .../good/mergecpp_noobsolete/finddialog.cpp | 154 + .../testdata/good/mergecpp_noobsolete/lupdatecmd | 1 + .../testdata/good/mergecpp_noobsolete/project.pro | 3 + .../good/mergecpp_noobsolete/project.ts.before | 44 + .../good/mergecpp_noobsolete/project.ts.result | 35 + .../testdata/good/mergecpp_obsolete/finddialog.cpp | 177 + .../testdata/good/mergecpp_obsolete/project.pro | 3 + .../good/mergecpp_obsolete/project.ts.before | 39 + .../good/mergecpp_obsolete/project.ts.result | 43 + .../lupdate/testdata/good/mergeui/project.pro | 3 + .../testdata/good/mergeui/project.ts.before | 22 + .../testdata/good/mergeui/project.ts.result | 23 + .../lupdate/testdata/good/mergeui/project.ui | 77 + .../testdata/good/mergeui_obsolete/project.pro | 3 + .../good/mergeui_obsolete/project.ts.before | 16 + .../good/mergeui_obsolete/project.ts.result | 22 + .../testdata/good/mergeui_obsolete/project.ui | 26 + .../good/multiple_locations/finddialog.cpp | 47 + .../testdata/good/multiple_locations/main.cpp | 53 + .../testdata/good/multiple_locations/project.pro | 4 + .../good/multiple_locations/project.ts.result | 17 + .../lupdate/testdata/good/namespaces/main.cpp | 198 + .../lupdate/testdata/good/namespaces/project.pro | 3 + .../testdata/good/namespaces/project.ts.result | 106 + .../testdata/good/parse_special_chars/main.cpp | 59 + .../testdata/good/parse_special_chars/project.pro | 3 + .../good/parse_special_chars/project.ts.result | 17 + .../lupdate/testdata/good/parsecontexts/main.cpp | 279 + .../testdata/good/parsecontexts/project.pro | 3 + .../testdata/good/parsecontexts/project.ts.result | 201 + .../lupdate/testdata/good/parsecpp/finddialog.cpp | 184 + .../lupdate/testdata/good/parsecpp/main.cpp | 345 + .../lupdate/testdata/good/parsecpp/project.pro | 4 + .../testdata/good/parsecpp/project.ts.result | 370 + .../testdata/good/parsecpp2/expectedoutput.txt | 7 + .../lupdate/testdata/good/parsecpp2/main.cpp | 127 + .../lupdate/testdata/good/parsecpp2/main.h | 51 + .../lupdate/testdata/good/parsecpp2/main2.cpp | 69 + .../lupdate/testdata/good/parsecpp2/main3.cpp | 83 + .../lupdate/testdata/good/parsecpp2/project.pro | 3 + .../testdata/good/parsecpp2/project.ts.result | 40 + .../lupdate/testdata/good/parsejava/main.java | 95 + .../lupdate/testdata/good/parsejava/project.pro | 3 + .../testdata/good/parsejava/project.ts.result | 115 + .../linguist/lupdate/testdata/good/parsejs/main.js | 91 + .../lupdate/testdata/good/parsejs/project.pro | 3 + .../testdata/good/parsejs/project.ts.result | 195 + .../testdata/good/parsejs2/expectedoutput.txt | 29 + .../lupdate/testdata/good/parsejs2/main.js | 56 + .../lupdate/testdata/good/parsejs2/project.pro | 3 + .../testdata/good/parsejs2/project.ts.result | 30 + .../lupdate/testdata/good/parsejscontexts/main.js | 29 + .../testdata/good/parsejscontexts/project.pro | 3 + .../good/parsejscontexts/project.ts.result | 81 + .../lupdate/testdata/good/parseqml/main.qml | 100 + .../lupdate/testdata/good/parseqml/project.pro | 3 + .../testdata/good/parseqml/project.ts.result | 200 + .../lupdate/testdata/good/parseui/project.pro | 3 + .../testdata/good/parseui/project.ts.result | 17 + .../lupdate/testdata/good/parseui/project.ui | 72 + .../linguist/lupdate/testdata/good/prefix/main.cpp | 56 + .../lupdate/testdata/good/prefix/project.pro | 3 + .../lupdate/testdata/good/prefix/project.ts.result | 23 + .../lupdate/testdata/good/preprocess/main.cpp | 78 + .../lupdate/testdata/good/preprocess/project.pro | 3 + .../testdata/good/preprocess/project.ts.result | 35 + .../lupdate/testdata/good/proparsing/main.cpp | 50 + .../lupdate/testdata/good/proparsing/main_mac.cpp | 51 + .../lupdate/testdata/good/proparsing/main_unix.cpp | 51 + .../lupdate/testdata/good/proparsing/main_win.cpp | 51 + .../lupdate/testdata/good/proparsing/project.pro | 31 + .../testdata/good/proparsing/project.ts.result | 64 + .../vpaths/dependpath/main_dependpath.cpp | 51 + .../testdata/good/proparsing/wildcard/main1.cpp | 50 + .../testdata/good/proparsing/wildcard/mainfile.cpp | 50 + .../lupdate/testdata/good/proparsing/wildcard1.cpp | 50 + .../testdata/good/proparsing/wildcard99.cpp | 50 + .../linguist/lupdate/testdata/good/proparsing2/a | 45 + .../lupdate/testdata/good/proparsing2/a.cpp | 45 + .../linguist/lupdate/testdata/good/proparsing2/b | 45 + .../lupdate/testdata/good/proparsing2/b.cpp | 45 + .../linguist/lupdate/testdata/good/proparsing2/e | 45 + .../lupdate/testdata/good/proparsing2/f/g.cpp | 45 + .../lupdate/testdata/good/proparsing2/files-cc.txt | 1 + .../lupdate/testdata/good/proparsing2/project.pro | 33 + .../testdata/good/proparsing2/project.ts.result | 62 + .../lupdate/testdata/good/proparsing2/spaces/z | 45 + .../testdata/good/proparsing2/variable_with_spaces | 45 + .../lupdate/testdata/good/proparsing2/with | 45 + .../linguist/lupdate/testdata/good/proparsing2/x/d | 45 + .../lupdate/testdata/good/proparsing2/x/variable | 45 + .../testdata/good/proparsingpaths/file1.cpp | 50 + .../testdata/good/proparsingpaths/filter.cpp | 50 + .../testdata/good/proparsingpaths/project.pro | 5 + .../good/proparsingpaths/project.ts.result | 31 + .../testdata/good/proparsingpaths/sub/sub.pri | 3 + .../testdata/good/proparsingpaths/sub/subfile1.cpp | 50 + .../good/proparsingpaths/sub/subfilter.cpp | 50 + .../testdata/good/proparsingpri/common/common.pri | 1 + .../testdata/good/proparsingpri/common/main.cpp | 50 + .../testdata/good/proparsingpri/common/main.pri | 5 + .../testdata/good/proparsingpri/mac/mac.pri | 5 + .../testdata/good/proparsingpri/mac/main_mac.cpp | 51 + .../testdata/good/proparsingpri/project.pro | 9 + .../testdata/good/proparsingpri/project.ts.result | 37 + .../good/proparsingpri/relativity/relativity.cpp | 50 + .../good/proparsingpri/relativity/relativity.pri | 3 + .../good/proparsingpri/relativity/sub/sub.pri | 1 + .../good/proparsingpri/relativity/sub2/sub2.pri | 2 + .../testdata/good/proparsingpri/unix/main_unix.cpp | 51 + .../testdata/good/proparsingpri/unix/unix.pri | 5 + .../testdata/good/proparsingpri/win/main_win.cpp | 51 + .../testdata/good/proparsingpri/win/win.pri | 5 + .../testdata/good/proparsingsubdirs/project.pro | 2 + .../good/proparsingsubdirs/project.ts.result | 13 + .../testdata/good/proparsingsubdirs/sub1/main.cpp | 50 + .../testdata/good/proparsingsubdirs/sub1/sub1.pro | 3 + .../testdata/good/proparsingsubs/common/common.pro | 2 + .../testdata/good/proparsingsubs/common/main.cpp | 50 + .../testdata/good/proparsingsubs/lupdatecmd | 1 + .../testdata/good/proparsingsubs/mac/mac.pro | 1 + .../testdata/good/proparsingsubs/mac/main_mac.cpp | 51 + .../testdata/good/proparsingsubs/project.pro | 2 + .../testdata/good/proparsingsubs/project.ts.result | 31 + .../good/proparsingsubs/unix/main_unix.cpp | 51 + .../testdata/good/proparsingsubs/unix/unix.pro | 1 + .../testdata/good/proparsingsubs/win/main_win.cpp | 51 + .../testdata/good/proparsingsubs/win/win.pro | 1 + .../testdata/good/recurse_full/expectedoutput.txt | 0 .../lupdate/testdata/good/recurse_full/lupdatecmd | 2 + .../testdata/good/recurse_full/project.ts.result | 20 + .../good/recurse_full/project_sub.ts.result | 13 + .../good/recurse_full_ts/expectedoutput.txt | 2 + .../testdata/good/recurse_full_ts/lupdatecmd | 3 + .../good/recurse_full_ts/project.ts.result | 20 + .../good/recurse_full_ts/project_sub.ts.before | 0 .../good/recurse_full_ts/project_sub.ts.result | 0 .../good/recurse_full_ts_join/expectedoutput.txt | 0 .../testdata/good/recurse_full_ts_join/lupdatecmd | 2 + .../good/recurse_full_ts_join/project.ts.result | 20 + .../testdata/good/recurse_part/expectedoutput.txt | 1 + .../lupdate/testdata/good/recurse_part/lupdatecmd | 2 + .../testdata/good/recurse_part/project.ts.before | 0 .../testdata/good/recurse_part/project.ts.result | 0 .../good/recurse_part/project_sub.ts.result | 13 + .../good/recurse_part_ts/expectedoutput.txt | 1 + .../testdata/good/recurse_part_ts/lupdatecmd | 3 + .../good/recurse_part_ts/project.ts.result | 20 + .../good/recurse_part_ts/project_sub.ts.before | 0 .../good/recurse_part_ts/project_sub.ts.result | 0 .../lupdate/testdata/good/reloutput/lupdatecmd | 1 + .../lupdate/testdata/good/reloutput/main.cpp | 50 + .../lupdate/testdata/good/reloutput/project.pro | 3 + .../good/reloutput/translations/project.ts.result | 12 + .../lupdate/testdata/good/respfile/lupdatecmd | 2 + .../testdata/good/respfile/project.ts.result | 17 + .../lupdate/testdata/good/respfile/source1.cpp | 49 + .../lupdate/testdata/good/respfile/source2.cpp | 49 + .../lupdate/testdata/good/respfile/sources.lst | 2 + .../lupdate/testdata/good/respfile/tsfiles.lst | 1 + .../testdata/good/textsimilarity/project.pro | 3 + .../testdata/good/textsimilarity/project.ts.before | 16 + .../testdata/good/textsimilarity/project.ts.result | 22 + .../testdata/good/textsimilarity/project.ui | 26 + .../lupdate/testdata/recursivescan/main.cpp | 63 + .../lupdate/testdata/recursivescan/project.ui | 74 + .../testdata/recursivescan/sub/filetypes/main.c++ | 49 + .../testdata/recursivescan/sub/filetypes/main.cpp | 49 + .../testdata/recursivescan/sub/filetypes/main.cxx | 49 + .../testdata/recursivescan/sub/finddialog.cpp | 73 + .../lupdate/testdata/subdirs_full/project.pro | 4 + .../lupdate/testdata/subdirs_full/subdir1/main.cpp | 46 + .../testdata/subdirs_full/subdir1/subdir1.pro | 1 + .../testdata/subdirs_full/subdir2/subdir2.pro | 2 + .../testdata/subdirs_full/subdir2/subsub1/main.cpp | 46 + .../subdirs_full/subdir2/subsub1/subsub1.pro | 1 + .../testdata/subdirs_full/subdir2/subsub2/main.cpp | 46 + .../subdirs_full/subdir2/subsub2/subsub2.pro | 4 + .../lupdate/testdata/subdirs_part/project.pro | 2 + .../lupdate/testdata/subdirs_part/subdir1/main.cpp | 46 + .../testdata/subdirs_part/subdir1/subdir1.pro | 1 + .../testdata/subdirs_part/subdir2/subdir2.pro | 2 + .../testdata/subdirs_part/subdir2/subsub1/main.cpp | 46 + .../subdirs_part/subdir2/subsub1/subsub1.pro | 1 + .../testdata/subdirs_part/subdir2/subsub2/main.cpp | 46 + .../subdirs_part/subdir2/subsub2/subsub2.pro | 4 + tests/auto/linguist/lupdate/tst_lupdate.cpp | 350 + tests/auto/qhelpcontentmodel/.gitignore | 2 + tests/auto/qhelpcontentmodel/data/collection.qhc | Bin 0 -> 10240 bytes tests/auto/qhelpcontentmodel/data/qmake-3.3.8.qch | Bin 0 -> 61440 bytes tests/auto/qhelpcontentmodel/data/qmake-4.3.0.qch | Bin 0 -> 93184 bytes tests/auto/qhelpcontentmodel/data/test.qch | Bin 0 -> 22528 bytes tests/auto/qhelpcontentmodel/qhelpcontentmodel.pro | 22 + .../qhelpcontentmodel/tst_qhelpcontentmodel.cpp | 182 + tests/auto/qhelpenginecore/.gitignore | 3 + tests/auto/qhelpenginecore/data/collection.qhc | Bin 0 -> 10240 bytes tests/auto/qhelpenginecore/data/collection1.qhc | Bin 0 -> 10240 bytes tests/auto/qhelpenginecore/data/linguist-3.3.8.qch | Bin 0 -> 131072 bytes tests/auto/qhelpenginecore/data/qmake-3.3.8.qch | Bin 0 -> 61440 bytes tests/auto/qhelpenginecore/data/qmake-4.3.0.qch | Bin 0 -> 93184 bytes tests/auto/qhelpenginecore/data/test.html | 11 + tests/auto/qhelpenginecore/data/test.qch | Bin 0 -> 22528 bytes tests/auto/qhelpenginecore/qhelpenginecore.pro | 23 + tests/auto/qhelpenginecore/tst_qhelpenginecore.cpp | 462 + tests/auto/qhelpgenerator/.gitignore | 1 + tests/auto/qhelpgenerator/data/cars.html | 11 + tests/auto/qhelpgenerator/data/classic.css | 92 + tests/auto/qhelpgenerator/data/fancy.html | 11 + tests/auto/qhelpgenerator/data/people.html | 11 + tests/auto/qhelpgenerator/data/sub/about.html | 11 + tests/auto/qhelpgenerator/data/test.html | 11 + tests/auto/qhelpgenerator/data/test.qhp | 71 + tests/auto/qhelpgenerator/qhelpgenerator.pro | 9 + tests/auto/qhelpgenerator/tst_qhelpgenerator.cpp | 218 + tests/auto/qhelpindexmodel/.gitignore | 2 + tests/auto/qhelpindexmodel/data/collection.qhc | Bin 0 -> 10240 bytes tests/auto/qhelpindexmodel/data/collection1.qhc | Bin 0 -> 10240 bytes tests/auto/qhelpindexmodel/data/linguist-3.3.8.qch | Bin 0 -> 131072 bytes tests/auto/qhelpindexmodel/data/qmake-3.3.8.qch | Bin 0 -> 61440 bytes tests/auto/qhelpindexmodel/data/qmake-4.3.0.qch | Bin 0 -> 93184 bytes tests/auto/qhelpindexmodel/data/test.html | 11 + tests/auto/qhelpindexmodel/data/test.qch | Bin 0 -> 22528 bytes tests/auto/qhelpindexmodel/qhelpindexmodel.pro | 9 + tests/auto/qhelpindexmodel/tst_qhelpindexmodel.cpp | 219 + tests/auto/qhelpprojectdata/.gitignore | 1 + tests/auto/qhelpprojectdata/data/test.qhp | 72 + tests/auto/qhelpprojectdata/qhelpprojectdata.pro | 9 + .../auto/qhelpprojectdata/tst_qhelpprojectdata.cpp | 193 + tests/global/.gitignore | 2 + tests/tests.pro | 2 + 2343 files changed, 431332 insertions(+) create mode 100644 3rdparty/clucene/APACHE.license create mode 100644 3rdparty/clucene/AUTHORS create mode 100644 3rdparty/clucene/COPYING create mode 100644 3rdparty/clucene/ChangeLog create mode 100644 3rdparty/clucene/LGPL.license create mode 100644 3rdparty/clucene/README create mode 100644 3rdparty/clucene/src/CLucene.h create mode 100644 3rdparty/clucene/src/CLucene/CLBackwards.h create mode 100644 3rdparty/clucene/src/CLucene/CLConfig.h create mode 100644 3rdparty/clucene/src/CLucene/CLMonolithic.cpp create mode 100644 3rdparty/clucene/src/CLucene/LuceneThreads.h create mode 100644 3rdparty/clucene/src/CLucene/StdHeader.cpp create mode 100644 3rdparty/clucene/src/CLucene/StdHeader.h create mode 100644 3rdparty/clucene/src/CLucene/analysis/AnalysisHeader.cpp create mode 100644 3rdparty/clucene/src/CLucene/analysis/AnalysisHeader.h create mode 100644 3rdparty/clucene/src/CLucene/analysis/Analyzers.cpp create mode 100644 3rdparty/clucene/src/CLucene/analysis/Analyzers.h create mode 100644 3rdparty/clucene/src/CLucene/analysis/standard/StandardAnalyzer.cpp create mode 100644 3rdparty/clucene/src/CLucene/analysis/standard/StandardAnalyzer.h create mode 100644 3rdparty/clucene/src/CLucene/analysis/standard/StandardFilter.cpp create mode 100644 3rdparty/clucene/src/CLucene/analysis/standard/StandardFilter.h create mode 100644 3rdparty/clucene/src/CLucene/analysis/standard/StandardTokenizer.cpp create mode 100644 3rdparty/clucene/src/CLucene/analysis/standard/StandardTokenizer.h create mode 100644 3rdparty/clucene/src/CLucene/analysis/standard/StandardTokenizerConstants.h create mode 100644 3rdparty/clucene/src/CLucene/config/CompilerAcc.h create mode 100644 3rdparty/clucene/src/CLucene/config/CompilerBcb.h create mode 100644 3rdparty/clucene/src/CLucene/config/CompilerGcc.h create mode 100644 3rdparty/clucene/src/CLucene/config/CompilerMsvc.h create mode 100644 3rdparty/clucene/src/CLucene/config/PlatformMac.h create mode 100644 3rdparty/clucene/src/CLucene/config/PlatformUnix.h create mode 100644 3rdparty/clucene/src/CLucene/config/PlatformWin32.h create mode 100644 3rdparty/clucene/src/CLucene/config/compiler.h create mode 100644 3rdparty/clucene/src/CLucene/config/define_std.h create mode 100644 3rdparty/clucene/src/CLucene/config/gunichartables.cpp create mode 100644 3rdparty/clucene/src/CLucene/config/gunichartables.h create mode 100644 3rdparty/clucene/src/CLucene/config/repl_lltot.cpp create mode 100644 3rdparty/clucene/src/CLucene/config/repl_tchar.h create mode 100644 3rdparty/clucene/src/CLucene/config/repl_tcscasecmp.cpp create mode 100644 3rdparty/clucene/src/CLucene/config/repl_tcslwr.cpp create mode 100644 3rdparty/clucene/src/CLucene/config/repl_tcstod.cpp create mode 100644 3rdparty/clucene/src/CLucene/config/repl_tcstoll.cpp create mode 100644 3rdparty/clucene/src/CLucene/config/repl_tprintf.cpp create mode 100644 3rdparty/clucene/src/CLucene/config/repl_wchar.h create mode 100644 3rdparty/clucene/src/CLucene/config/threadCSection.h create mode 100644 3rdparty/clucene/src/CLucene/config/threadPthread.h create mode 100644 3rdparty/clucene/src/CLucene/config/threads.cpp create mode 100644 3rdparty/clucene/src/CLucene/config/utf8.cpp create mode 100644 3rdparty/clucene/src/CLucene/debug/condition.cpp create mode 100644 3rdparty/clucene/src/CLucene/debug/condition.h create mode 100644 3rdparty/clucene/src/CLucene/debug/error.cpp create mode 100644 3rdparty/clucene/src/CLucene/debug/error.h create mode 100644 3rdparty/clucene/src/CLucene/debug/lucenebase.h create mode 100644 3rdparty/clucene/src/CLucene/debug/mem.h create mode 100644 3rdparty/clucene/src/CLucene/debug/memtracking.cpp create mode 100644 3rdparty/clucene/src/CLucene/document/DateField.cpp create mode 100644 3rdparty/clucene/src/CLucene/document/DateField.h create mode 100644 3rdparty/clucene/src/CLucene/document/Document.cpp create mode 100644 3rdparty/clucene/src/CLucene/document/Document.h create mode 100644 3rdparty/clucene/src/CLucene/document/Field.cpp create mode 100644 3rdparty/clucene/src/CLucene/document/Field.h create mode 100644 3rdparty/clucene/src/CLucene/index/CompoundFile.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/CompoundFile.h create mode 100644 3rdparty/clucene/src/CLucene/index/DocumentWriter.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/DocumentWriter.h create mode 100644 3rdparty/clucene/src/CLucene/index/FieldInfo.h create mode 100644 3rdparty/clucene/src/CLucene/index/FieldInfos.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/FieldInfos.h create mode 100644 3rdparty/clucene/src/CLucene/index/FieldsReader.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/FieldsReader.h create mode 100644 3rdparty/clucene/src/CLucene/index/FieldsWriter.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/FieldsWriter.h create mode 100644 3rdparty/clucene/src/CLucene/index/IndexModifier.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/IndexModifier.h create mode 100644 3rdparty/clucene/src/CLucene/index/IndexReader.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/IndexReader.h create mode 100644 3rdparty/clucene/src/CLucene/index/IndexWriter.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/IndexWriter.h create mode 100644 3rdparty/clucene/src/CLucene/index/MultiReader.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/MultiReader.h create mode 100644 3rdparty/clucene/src/CLucene/index/SegmentHeader.h create mode 100644 3rdparty/clucene/src/CLucene/index/SegmentInfos.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/SegmentInfos.h create mode 100644 3rdparty/clucene/src/CLucene/index/SegmentMergeInfo.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/SegmentMergeInfo.h create mode 100644 3rdparty/clucene/src/CLucene/index/SegmentMergeQueue.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/SegmentMergeQueue.h create mode 100644 3rdparty/clucene/src/CLucene/index/SegmentMerger.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/SegmentMerger.h create mode 100644 3rdparty/clucene/src/CLucene/index/SegmentReader.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/SegmentTermDocs.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/SegmentTermEnum.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/SegmentTermEnum.h create mode 100644 3rdparty/clucene/src/CLucene/index/SegmentTermPositions.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/SegmentTermVector.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/Term.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/Term.h create mode 100644 3rdparty/clucene/src/CLucene/index/TermInfo.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/TermInfo.h create mode 100644 3rdparty/clucene/src/CLucene/index/TermInfosReader.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/TermInfosReader.h create mode 100644 3rdparty/clucene/src/CLucene/index/TermInfosWriter.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/TermInfosWriter.h create mode 100644 3rdparty/clucene/src/CLucene/index/TermVector.h create mode 100644 3rdparty/clucene/src/CLucene/index/TermVectorReader.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/TermVectorWriter.cpp create mode 100644 3rdparty/clucene/src/CLucene/index/Terms.h create mode 100644 3rdparty/clucene/src/CLucene/queryParser/Lexer.cpp create mode 100644 3rdparty/clucene/src/CLucene/queryParser/Lexer.h create mode 100644 3rdparty/clucene/src/CLucene/queryParser/MultiFieldQueryParser.cpp create mode 100644 3rdparty/clucene/src/CLucene/queryParser/MultiFieldQueryParser.h create mode 100644 3rdparty/clucene/src/CLucene/queryParser/QueryParser.cpp create mode 100644 3rdparty/clucene/src/CLucene/queryParser/QueryParser.h create mode 100644 3rdparty/clucene/src/CLucene/queryParser/QueryParserBase.cpp create mode 100644 3rdparty/clucene/src/CLucene/queryParser/QueryParserBase.h create mode 100644 3rdparty/clucene/src/CLucene/queryParser/QueryToken.cpp create mode 100644 3rdparty/clucene/src/CLucene/queryParser/QueryToken.h create mode 100644 3rdparty/clucene/src/CLucene/queryParser/TokenList.cpp create mode 100644 3rdparty/clucene/src/CLucene/queryParser/TokenList.h create mode 100644 3rdparty/clucene/src/CLucene/search/BooleanClause.h create mode 100644 3rdparty/clucene/src/CLucene/search/BooleanQuery.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/BooleanQuery.h create mode 100644 3rdparty/clucene/src/CLucene/search/BooleanScorer.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/BooleanScorer.h create mode 100644 3rdparty/clucene/src/CLucene/search/CachingWrapperFilter.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/CachingWrapperFilter.h create mode 100644 3rdparty/clucene/src/CLucene/search/ChainedFilter.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/ChainedFilter.h create mode 100644 3rdparty/clucene/src/CLucene/search/Compare.h create mode 100644 3rdparty/clucene/src/CLucene/search/ConjunctionScorer.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/ConjunctionScorer.h create mode 100644 3rdparty/clucene/src/CLucene/search/DateFilter.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/DateFilter.h create mode 100644 3rdparty/clucene/src/CLucene/search/ExactPhraseScorer.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/ExactPhraseScorer.h create mode 100644 3rdparty/clucene/src/CLucene/search/Explanation.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/Explanation.h create mode 100644 3rdparty/clucene/src/CLucene/search/FieldCache.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/FieldCache.h create mode 100644 3rdparty/clucene/src/CLucene/search/FieldCacheImpl.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/FieldCacheImpl.h create mode 100644 3rdparty/clucene/src/CLucene/search/FieldDoc.h create mode 100644 3rdparty/clucene/src/CLucene/search/FieldDocSortedHitQueue.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/FieldDocSortedHitQueue.h create mode 100644 3rdparty/clucene/src/CLucene/search/FieldSortedHitQueue.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/FieldSortedHitQueue.h create mode 100644 3rdparty/clucene/src/CLucene/search/Filter.h create mode 100644 3rdparty/clucene/src/CLucene/search/FilteredTermEnum.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/FilteredTermEnum.h create mode 100644 3rdparty/clucene/src/CLucene/search/FuzzyQuery.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/FuzzyQuery.h create mode 100644 3rdparty/clucene/src/CLucene/search/HitQueue.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/HitQueue.h create mode 100644 3rdparty/clucene/src/CLucene/search/Hits.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/IndexSearcher.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/IndexSearcher.h create mode 100644 3rdparty/clucene/src/CLucene/search/MultiSearcher.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/MultiSearcher.h create mode 100644 3rdparty/clucene/src/CLucene/search/MultiTermQuery.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/MultiTermQuery.h create mode 100644 3rdparty/clucene/src/CLucene/search/PhrasePositions.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/PhrasePositions.h create mode 100644 3rdparty/clucene/src/CLucene/search/PhraseQuery.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/PhraseQuery.h create mode 100644 3rdparty/clucene/src/CLucene/search/PhraseQueue.h create mode 100644 3rdparty/clucene/src/CLucene/search/PhraseScorer.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/PhraseScorer.h create mode 100644 3rdparty/clucene/src/CLucene/search/PrefixQuery.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/PrefixQuery.h create mode 100644 3rdparty/clucene/src/CLucene/search/QueryFilter.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/QueryFilter.h create mode 100644 3rdparty/clucene/src/CLucene/search/RangeFilter.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/RangeFilter.h create mode 100644 3rdparty/clucene/src/CLucene/search/RangeQuery.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/RangeQuery.h create mode 100644 3rdparty/clucene/src/CLucene/search/Scorer.h create mode 100644 3rdparty/clucene/src/CLucene/search/SearchHeader.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/SearchHeader.h create mode 100644 3rdparty/clucene/src/CLucene/search/Similarity.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/Similarity.h create mode 100644 3rdparty/clucene/src/CLucene/search/SloppyPhraseScorer.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/SloppyPhraseScorer.h create mode 100644 3rdparty/clucene/src/CLucene/search/Sort.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/Sort.h create mode 100644 3rdparty/clucene/src/CLucene/search/TermQuery.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/TermQuery.h create mode 100644 3rdparty/clucene/src/CLucene/search/TermScorer.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/TermScorer.h create mode 100644 3rdparty/clucene/src/CLucene/search/WildcardQuery.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/WildcardQuery.h create mode 100644 3rdparty/clucene/src/CLucene/search/WildcardTermEnum.cpp create mode 100644 3rdparty/clucene/src/CLucene/search/WildcardTermEnum.h create mode 100644 3rdparty/clucene/src/CLucene/store/Directory.h create mode 100644 3rdparty/clucene/src/CLucene/store/FSDirectory.cpp create mode 100644 3rdparty/clucene/src/CLucene/store/FSDirectory.h create mode 100644 3rdparty/clucene/src/CLucene/store/IndexInput.cpp create mode 100644 3rdparty/clucene/src/CLucene/store/IndexInput.h create mode 100644 3rdparty/clucene/src/CLucene/store/IndexOutput.cpp create mode 100644 3rdparty/clucene/src/CLucene/store/IndexOutput.h create mode 100644 3rdparty/clucene/src/CLucene/store/InputStream.h create mode 100644 3rdparty/clucene/src/CLucene/store/Lock.cpp create mode 100644 3rdparty/clucene/src/CLucene/store/Lock.h create mode 100644 3rdparty/clucene/src/CLucene/store/MMapInput.cpp create mode 100644 3rdparty/clucene/src/CLucene/store/OutputStream.h create mode 100644 3rdparty/clucene/src/CLucene/store/RAMDirectory.cpp create mode 100644 3rdparty/clucene/src/CLucene/store/RAMDirectory.h create mode 100644 3rdparty/clucene/src/CLucene/store/TransactionalRAMDirectory.cpp create mode 100644 3rdparty/clucene/src/CLucene/store/TransactionalRAMDirectory.h create mode 100644 3rdparty/clucene/src/CLucene/util/Arrays.h create mode 100644 3rdparty/clucene/src/CLucene/util/BitSet.cpp create mode 100644 3rdparty/clucene/src/CLucene/util/BitSet.h create mode 100644 3rdparty/clucene/src/CLucene/util/Equators.cpp create mode 100644 3rdparty/clucene/src/CLucene/util/Equators.h create mode 100644 3rdparty/clucene/src/CLucene/util/FastCharStream.cpp create mode 100644 3rdparty/clucene/src/CLucene/util/FastCharStream.h create mode 100644 3rdparty/clucene/src/CLucene/util/Misc.cpp create mode 100644 3rdparty/clucene/src/CLucene/util/Misc.h create mode 100644 3rdparty/clucene/src/CLucene/util/PriorityQueue.h create mode 100644 3rdparty/clucene/src/CLucene/util/Reader.cpp create mode 100644 3rdparty/clucene/src/CLucene/util/Reader.h create mode 100644 3rdparty/clucene/src/CLucene/util/StringBuffer.cpp create mode 100644 3rdparty/clucene/src/CLucene/util/StringBuffer.h create mode 100644 3rdparty/clucene/src/CLucene/util/StringIntern.cpp create mode 100644 3rdparty/clucene/src/CLucene/util/StringIntern.h create mode 100644 3rdparty/clucene/src/CLucene/util/ThreadLocal.cpp create mode 100644 3rdparty/clucene/src/CLucene/util/ThreadLocal.h create mode 100644 3rdparty/clucene/src/CLucene/util/VoidList.h create mode 100644 3rdparty/clucene/src/CLucene/util/VoidMap.h create mode 100644 3rdparty/clucene/src/CLucene/util/bufferedstream.h create mode 100644 3rdparty/clucene/src/CLucene/util/dirent.cpp create mode 100644 3rdparty/clucene/src/CLucene/util/dirent.h create mode 100644 3rdparty/clucene/src/CLucene/util/fileinputstream.cpp create mode 100644 3rdparty/clucene/src/CLucene/util/fileinputstream.h create mode 100644 3rdparty/clucene/src/CLucene/util/inputstreambuffer.h create mode 100644 3rdparty/clucene/src/CLucene/util/jstreamsconfig.h create mode 100644 3rdparty/clucene/src/CLucene/util/streambase.h create mode 100644 3rdparty/clucene/src/CLucene/util/stringreader.h create mode 100644 3rdparty/clucene/src/CLucene/util/subinputstream.h create mode 100644 demos/arthurplugin/arthur_plugin.qrc create mode 100644 demos/arthurplugin/arthurplugin.pro create mode 100644 demos/arthurplugin/bg1.jpg create mode 100644 demos/arthurplugin/flower.jpg create mode 100644 demos/arthurplugin/flower_alpha.jpg create mode 100644 demos/arthurplugin/plugin.cpp create mode 100644 demos/shared/arthurstyle.cpp create mode 100644 demos/shared/arthurstyle.h create mode 100644 demos/shared/arthurwidgets.cpp create mode 100644 demos/shared/arthurwidgets.h create mode 100644 demos/shared/hoverpoints.cpp create mode 100644 demos/shared/hoverpoints.h create mode 100644 demos/shared/images/bg_pattern.png create mode 100644 demos/shared/images/button_normal_cap_left.png create mode 100644 demos/shared/images/button_normal_cap_right.png create mode 100644 demos/shared/images/button_normal_stretch.png create mode 100644 demos/shared/images/button_pressed_cap_left.png create mode 100644 demos/shared/images/button_pressed_cap_right.png create mode 100644 demos/shared/images/button_pressed_stretch.png create mode 100644 demos/shared/images/curve_thing_edit-6.png create mode 100644 demos/shared/images/frame_bottom.png create mode 100644 demos/shared/images/frame_bottomleft.png create mode 100644 demos/shared/images/frame_bottomright.png create mode 100644 demos/shared/images/frame_left.png create mode 100644 demos/shared/images/frame_right.png create mode 100644 demos/shared/images/frame_top.png create mode 100644 demos/shared/images/frame_topleft.png create mode 100644 demos/shared/images/frame_topright.png create mode 100644 demos/shared/images/groupframe_bottom_left.png create mode 100644 demos/shared/images/groupframe_bottom_right.png create mode 100644 demos/shared/images/groupframe_bottom_stretch.png create mode 100644 demos/shared/images/groupframe_left_stretch.png create mode 100644 demos/shared/images/groupframe_right_stretch.png create mode 100644 demos/shared/images/groupframe_top_stretch.png create mode 100644 demos/shared/images/groupframe_topleft.png create mode 100644 demos/shared/images/groupframe_topright.png create mode 100644 demos/shared/images/line_dash_dot.png create mode 100644 demos/shared/images/line_dash_dot_dot.png create mode 100644 demos/shared/images/line_dashed.png create mode 100644 demos/shared/images/line_dotted.png create mode 100644 demos/shared/images/line_solid.png create mode 100644 demos/shared/images/radiobutton-off.png create mode 100644 demos/shared/images/radiobutton-on.png create mode 100644 demos/shared/images/radiobutton_off.png create mode 100644 demos/shared/images/radiobutton_on.png create mode 100644 demos/shared/images/slider_bar.png create mode 100644 demos/shared/images/slider_thumb_off.png create mode 100644 demos/shared/images/slider_thumb_on.png create mode 100644 demos/shared/images/title_cap_left.png create mode 100644 demos/shared/images/title_cap_right.png create mode 100644 demos/shared/images/title_stretch.png create mode 100644 demos/shared/shared.pri create mode 100644 demos/shared/shared.pro create mode 100644 demos/shared/shared.qrc create mode 100644 examples/designer/README create mode 100644 examples/designer/calculatorbuilder/calculatorbuilder.pro create mode 100644 examples/designer/calculatorbuilder/calculatorbuilder.qrc create mode 100644 examples/designer/calculatorbuilder/calculatorform.cpp create mode 100644 examples/designer/calculatorbuilder/calculatorform.h create mode 100644 examples/designer/calculatorbuilder/calculatorform.ui create mode 100644 examples/designer/calculatorbuilder/main.cpp create mode 100644 examples/designer/calculatorform/calculatorform.cpp create mode 100644 examples/designer/calculatorform/calculatorform.h create mode 100644 examples/designer/calculatorform/calculatorform.pro create mode 100644 examples/designer/calculatorform/calculatorform.ui create mode 100644 examples/designer/calculatorform/main.cpp create mode 100644 examples/designer/containerextension/containerextension.pro create mode 100644 examples/designer/containerextension/multipagewidget.cpp create mode 100644 examples/designer/containerextension/multipagewidget.h create mode 100644 examples/designer/containerextension/multipagewidgetcontainerextension.cpp create mode 100644 examples/designer/containerextension/multipagewidgetcontainerextension.h create mode 100644 examples/designer/containerextension/multipagewidgetextensionfactory.cpp create mode 100644 examples/designer/containerextension/multipagewidgetextensionfactory.h create mode 100644 examples/designer/containerextension/multipagewidgetplugin.cpp create mode 100644 examples/designer/containerextension/multipagewidgetplugin.h create mode 100644 examples/designer/customwidgetplugin/analogclock.cpp create mode 100644 examples/designer/customwidgetplugin/analogclock.h create mode 100644 examples/designer/customwidgetplugin/customwidgetplugin.cpp create mode 100644 examples/designer/customwidgetplugin/customwidgetplugin.h create mode 100644 examples/designer/customwidgetplugin/customwidgetplugin.pro create mode 100644 examples/designer/designer.pro create mode 100644 examples/designer/taskmenuextension/taskmenuextension.pro create mode 100644 examples/designer/taskmenuextension/tictactoe.cpp create mode 100644 examples/designer/taskmenuextension/tictactoe.h create mode 100644 examples/designer/taskmenuextension/tictactoedialog.cpp create mode 100644 examples/designer/taskmenuextension/tictactoedialog.h create mode 100644 examples/designer/taskmenuextension/tictactoeplugin.cpp create mode 100644 examples/designer/taskmenuextension/tictactoeplugin.h create mode 100644 examples/designer/taskmenuextension/tictactoetaskmenu.cpp create mode 100644 examples/designer/taskmenuextension/tictactoetaskmenu.h create mode 100644 examples/designer/worldtimeclockbuilder/form.ui create mode 100644 examples/designer/worldtimeclockbuilder/main.cpp create mode 100644 examples/designer/worldtimeclockbuilder/worldtimeclockbuilder.pro create mode 100644 examples/designer/worldtimeclockbuilder/worldtimeclockbuilder.qrc create mode 100644 examples/designer/worldtimeclockplugin/worldtimeclock.cpp create mode 100644 examples/designer/worldtimeclockplugin/worldtimeclock.h create mode 100644 examples/designer/worldtimeclockplugin/worldtimeclockplugin.cpp create mode 100644 examples/designer/worldtimeclockplugin/worldtimeclockplugin.h create mode 100644 examples/designer/worldtimeclockplugin/worldtimeclockplugin.pro create mode 100644 examples/examples.pro create mode 100644 examples/help/README create mode 100644 examples/help/contextsensitivehelp/contextsensitivehelp.pro create mode 100644 examples/help/contextsensitivehelp/doc/amount.html create mode 100644 examples/help/contextsensitivehelp/doc/filter.html create mode 100644 examples/help/contextsensitivehelp/doc/plants.html create mode 100644 examples/help/contextsensitivehelp/doc/rain.html create mode 100644 examples/help/contextsensitivehelp/doc/source.html create mode 100644 examples/help/contextsensitivehelp/doc/temperature.html create mode 100644 examples/help/contextsensitivehelp/doc/time.html create mode 100644 examples/help/contextsensitivehelp/doc/wateringmachine.qch create mode 100644 examples/help/contextsensitivehelp/doc/wateringmachine.qhc create mode 100644 examples/help/contextsensitivehelp/doc/wateringmachine.qhcp create mode 100644 examples/help/contextsensitivehelp/doc/wateringmachine.qhp create mode 100644 examples/help/contextsensitivehelp/helpbrowser.cpp create mode 100644 examples/help/contextsensitivehelp/helpbrowser.h create mode 100644 examples/help/contextsensitivehelp/main.cpp create mode 100644 examples/help/contextsensitivehelp/wateringconfigdialog.cpp create mode 100644 examples/help/contextsensitivehelp/wateringconfigdialog.h create mode 100644 examples/help/contextsensitivehelp/wateringconfigdialog.ui create mode 100644 examples/help/help.pro create mode 100644 examples/help/remotecontrol/enter.png create mode 100644 examples/help/remotecontrol/main.cpp create mode 100644 examples/help/remotecontrol/remotecontrol.cpp create mode 100644 examples/help/remotecontrol/remotecontrol.h create mode 100644 examples/help/remotecontrol/remotecontrol.pro create mode 100644 examples/help/remotecontrol/remotecontrol.qrc create mode 100644 examples/help/remotecontrol/remotecontrol.ui create mode 100644 examples/help/simpletextviewer/assistant.cpp create mode 100644 examples/help/simpletextviewer/assistant.h create mode 100644 examples/help/simpletextviewer/documentation/about.txt create mode 100644 examples/help/simpletextviewer/documentation/browse.html create mode 100644 examples/help/simpletextviewer/documentation/filedialog.html create mode 100644 examples/help/simpletextviewer/documentation/findfile.html create mode 100644 examples/help/simpletextviewer/documentation/images/browse.png create mode 100644 examples/help/simpletextviewer/documentation/images/fadedfilemenu.png create mode 100644 examples/help/simpletextviewer/documentation/images/filedialog.png create mode 100644 examples/help/simpletextviewer/documentation/images/handbook.png create mode 100644 examples/help/simpletextviewer/documentation/images/icon.png create mode 100644 examples/help/simpletextviewer/documentation/images/mainwindow.png create mode 100644 examples/help/simpletextviewer/documentation/images/open.png create mode 100644 examples/help/simpletextviewer/documentation/images/wildcard.png create mode 100644 examples/help/simpletextviewer/documentation/index.html create mode 100644 examples/help/simpletextviewer/documentation/intro.html create mode 100644 examples/help/simpletextviewer/documentation/openfile.html create mode 100644 examples/help/simpletextviewer/documentation/simpletextviewer.qch create mode 100644 examples/help/simpletextviewer/documentation/simpletextviewer.qhc create mode 100644 examples/help/simpletextviewer/documentation/simpletextviewer.qhcp create mode 100644 examples/help/simpletextviewer/documentation/simpletextviewer.qhp create mode 100644 examples/help/simpletextviewer/documentation/wildcardmatching.html create mode 100644 examples/help/simpletextviewer/findfiledialog.cpp create mode 100644 examples/help/simpletextviewer/findfiledialog.h create mode 100644 examples/help/simpletextviewer/main.cpp create mode 100644 examples/help/simpletextviewer/mainwindow.cpp create mode 100644 examples/help/simpletextviewer/mainwindow.h create mode 100644 examples/help/simpletextviewer/simpletextviewer.pro create mode 100644 examples/help/simpletextviewer/textedit.cpp create mode 100644 examples/help/simpletextviewer/textedit.h create mode 100644 qttools.pro create mode 100644 src/assistant/assistant.pro create mode 100644 src/assistant/lib/fulltextsearch/fulltextsearch.pri create mode 100644 src/assistant/lib/fulltextsearch/fulltextsearch.pro create mode 100644 src/assistant/lib/fulltextsearch/license.txt create mode 100644 src/assistant/lib/fulltextsearch/qanalyzer.cpp create mode 100644 src/assistant/lib/fulltextsearch/qanalyzer_p.h create mode 100644 src/assistant/lib/fulltextsearch/qclucene-config_p.h create mode 100644 src/assistant/lib/fulltextsearch/qclucene_global_p.h create mode 100644 src/assistant/lib/fulltextsearch/qdocument.cpp create mode 100644 src/assistant/lib/fulltextsearch/qdocument_p.h create mode 100644 src/assistant/lib/fulltextsearch/qfield.cpp create mode 100644 src/assistant/lib/fulltextsearch/qfield_p.h create mode 100644 src/assistant/lib/fulltextsearch/qfilter.cpp create mode 100644 src/assistant/lib/fulltextsearch/qfilter_p.h create mode 100644 src/assistant/lib/fulltextsearch/qhits.cpp create mode 100644 src/assistant/lib/fulltextsearch/qhits_p.h create mode 100644 src/assistant/lib/fulltextsearch/qindexreader.cpp create mode 100644 src/assistant/lib/fulltextsearch/qindexreader_p.h create mode 100644 src/assistant/lib/fulltextsearch/qindexwriter.cpp create mode 100644 src/assistant/lib/fulltextsearch/qindexwriter_p.h create mode 100644 src/assistant/lib/fulltextsearch/qquery.cpp create mode 100644 src/assistant/lib/fulltextsearch/qquery_p.h create mode 100644 src/assistant/lib/fulltextsearch/qqueryparser.cpp create mode 100644 src/assistant/lib/fulltextsearch/qqueryparser_p.h create mode 100644 src/assistant/lib/fulltextsearch/qreader.cpp create mode 100644 src/assistant/lib/fulltextsearch/qreader_p.h create mode 100644 src/assistant/lib/fulltextsearch/qsearchable.cpp create mode 100644 src/assistant/lib/fulltextsearch/qsearchable_p.h create mode 100644 src/assistant/lib/fulltextsearch/qsort.cpp create mode 100644 src/assistant/lib/fulltextsearch/qsort_p.h create mode 100644 src/assistant/lib/fulltextsearch/qterm.cpp create mode 100644 src/assistant/lib/fulltextsearch/qterm_p.h create mode 100644 src/assistant/lib/fulltextsearch/qtoken.cpp create mode 100644 src/assistant/lib/fulltextsearch/qtoken_p.h create mode 100644 src/assistant/lib/fulltextsearch/qtokenizer.cpp create mode 100644 src/assistant/lib/fulltextsearch/qtokenizer_p.h create mode 100644 src/assistant/lib/fulltextsearch/qtokenstream.cpp create mode 100644 src/assistant/lib/fulltextsearch/qtokenstream_p.h create mode 100644 src/assistant/lib/helpsystem.qrc create mode 100644 src/assistant/lib/images/1leftarrow.png create mode 100644 src/assistant/lib/images/1rightarrow.png create mode 100644 src/assistant/lib/images/3leftarrow.png create mode 100644 src/assistant/lib/images/3rightarrow.png create mode 100644 src/assistant/lib/lib.pro create mode 100644 src/assistant/lib/qclucenefieldnames.cpp create mode 100644 src/assistant/lib/qclucenefieldnames_p.h create mode 100644 src/assistant/lib/qhelp_global.cpp create mode 100644 src/assistant/lib/qhelp_global.h create mode 100644 src/assistant/lib/qhelpcollectionhandler.cpp create mode 100644 src/assistant/lib/qhelpcollectionhandler_p.h create mode 100644 src/assistant/lib/qhelpcontentwidget.cpp create mode 100644 src/assistant/lib/qhelpcontentwidget.h create mode 100644 src/assistant/lib/qhelpdatainterface.cpp create mode 100644 src/assistant/lib/qhelpdatainterface_p.h create mode 100644 src/assistant/lib/qhelpdbreader.cpp create mode 100644 src/assistant/lib/qhelpdbreader_p.h create mode 100644 src/assistant/lib/qhelpengine.cpp create mode 100644 src/assistant/lib/qhelpengine.h create mode 100644 src/assistant/lib/qhelpengine_p.h create mode 100644 src/assistant/lib/qhelpenginecore.cpp create mode 100644 src/assistant/lib/qhelpenginecore.h create mode 100644 src/assistant/lib/qhelpgenerator.cpp create mode 100644 src/assistant/lib/qhelpgenerator_p.h create mode 100644 src/assistant/lib/qhelpindexwidget.cpp create mode 100644 src/assistant/lib/qhelpindexwidget.h create mode 100644 src/assistant/lib/qhelpprojectdata.cpp create mode 100644 src/assistant/lib/qhelpprojectdata_p.h create mode 100644 src/assistant/lib/qhelpsearchengine.cpp create mode 100644 src/assistant/lib/qhelpsearchengine.h create mode 100644 src/assistant/lib/qhelpsearchindex_default.cpp create mode 100644 src/assistant/lib/qhelpsearchindex_default_p.h create mode 100644 src/assistant/lib/qhelpsearchindexreader.cpp create mode 100644 src/assistant/lib/qhelpsearchindexreader_clucene.cpp create mode 100644 src/assistant/lib/qhelpsearchindexreader_clucene_p.h create mode 100644 src/assistant/lib/qhelpsearchindexreader_default.cpp create mode 100644 src/assistant/lib/qhelpsearchindexreader_default_p.h create mode 100644 src/assistant/lib/qhelpsearchindexreader_p.h create mode 100644 src/assistant/lib/qhelpsearchindexwriter_clucene.cpp create mode 100644 src/assistant/lib/qhelpsearchindexwriter_clucene_p.h create mode 100644 src/assistant/lib/qhelpsearchindexwriter_default.cpp create mode 100644 src/assistant/lib/qhelpsearchindexwriter_default_p.h create mode 100644 src/assistant/lib/qhelpsearchquerywidget.cpp create mode 100644 src/assistant/lib/qhelpsearchquerywidget.h create mode 100644 src/assistant/lib/qhelpsearchresultwidget.cpp create mode 100644 src/assistant/lib/qhelpsearchresultwidget.h create mode 100644 src/assistant/tools/assistant/Info_mac.plist create mode 100644 src/assistant/tools/assistant/aboutdialog.cpp create mode 100644 src/assistant/tools/assistant/aboutdialog.h create mode 100644 src/assistant/tools/assistant/assistant.icns create mode 100644 src/assistant/tools/assistant/assistant.ico create mode 100644 src/assistant/tools/assistant/assistant.pro create mode 100644 src/assistant/tools/assistant/assistant.qch create mode 100644 src/assistant/tools/assistant/assistant.qrc create mode 100644 src/assistant/tools/assistant/assistant.rc create mode 100644 src/assistant/tools/assistant/assistant_images.qrc create mode 100644 src/assistant/tools/assistant/bookmarkdialog.cpp create mode 100644 src/assistant/tools/assistant/bookmarkdialog.h create mode 100644 src/assistant/tools/assistant/bookmarkdialog.ui create mode 100644 src/assistant/tools/assistant/bookmarkfiltermodel.cpp create mode 100644 src/assistant/tools/assistant/bookmarkfiltermodel.h create mode 100644 src/assistant/tools/assistant/bookmarkitem.cpp create mode 100644 src/assistant/tools/assistant/bookmarkitem.h create mode 100644 src/assistant/tools/assistant/bookmarkmanager.cpp create mode 100644 src/assistant/tools/assistant/bookmarkmanager.h create mode 100644 src/assistant/tools/assistant/bookmarkmanagerwidget.cpp create mode 100644 src/assistant/tools/assistant/bookmarkmanagerwidget.h create mode 100644 src/assistant/tools/assistant/bookmarkmanagerwidget.ui create mode 100644 src/assistant/tools/assistant/bookmarkmodel.cpp create mode 100644 src/assistant/tools/assistant/bookmarkmodel.h create mode 100644 src/assistant/tools/assistant/bookmarkwidget.ui create mode 100644 src/assistant/tools/assistant/centralwidget.cpp create mode 100644 src/assistant/tools/assistant/centralwidget.h create mode 100644 src/assistant/tools/assistant/cmdlineparser.cpp create mode 100644 src/assistant/tools/assistant/cmdlineparser.h create mode 100644 src/assistant/tools/assistant/contentwindow.cpp create mode 100644 src/assistant/tools/assistant/contentwindow.h create mode 100644 src/assistant/tools/assistant/doc/HOWTO create mode 100644 src/assistant/tools/assistant/doc/assistant.qdoc create mode 100644 src/assistant/tools/assistant/doc/assistant.qdocconf create mode 100644 src/assistant/tools/assistant/doc/assistant.qhp create mode 100644 src/assistant/tools/assistant/doc/classic.css create mode 100644 src/assistant/tools/assistant/doc/images/assistant-address-toolbar.png create mode 100644 src/assistant/tools/assistant/doc/images/assistant-assistant.png create mode 100644 src/assistant/tools/assistant/doc/images/assistant-dockwidgets.png create mode 100644 src/assistant/tools/assistant/doc/images/assistant-docwindow.png create mode 100644 src/assistant/tools/assistant/doc/images/assistant-examples.png create mode 100644 src/assistant/tools/assistant/doc/images/assistant-filter-toolbar.png create mode 100644 src/assistant/tools/assistant/doc/images/assistant-preferences-documentation.png create mode 100644 src/assistant/tools/assistant/doc/images/assistant-preferences-filters.png create mode 100644 src/assistant/tools/assistant/doc/images/assistant-preferences-fonts.png create mode 100644 src/assistant/tools/assistant/doc/images/assistant-preferences-options.png create mode 100644 src/assistant/tools/assistant/doc/images/assistant-search.png create mode 100644 src/assistant/tools/assistant/doc/images/assistant-toolbar.png create mode 100644 src/assistant/tools/assistant/filternamedialog.cpp create mode 100644 src/assistant/tools/assistant/filternamedialog.h create mode 100644 src/assistant/tools/assistant/filternamedialog.ui create mode 100644 src/assistant/tools/assistant/findwidget.cpp create mode 100644 src/assistant/tools/assistant/findwidget.h create mode 100644 src/assistant/tools/assistant/globalactions.cpp create mode 100644 src/assistant/tools/assistant/globalactions.h create mode 100644 src/assistant/tools/assistant/helpenginewrapper.cpp create mode 100644 src/assistant/tools/assistant/helpenginewrapper.h create mode 100644 src/assistant/tools/assistant/helpviewer.cpp create mode 100644 src/assistant/tools/assistant/helpviewer.h create mode 100644 src/assistant/tools/assistant/helpviewer_p.h create mode 100644 src/assistant/tools/assistant/helpviewer_qtb.cpp create mode 100644 src/assistant/tools/assistant/helpviewer_qwv.cpp create mode 100644 src/assistant/tools/assistant/images/assistant-128.png create mode 100644 src/assistant/tools/assistant/images/assistant.png create mode 100644 src/assistant/tools/assistant/images/bookmark.png create mode 100644 src/assistant/tools/assistant/images/closebutton.png create mode 100644 src/assistant/tools/assistant/images/darkclosebutton.png create mode 100644 src/assistant/tools/assistant/images/mac/addtab.png create mode 100644 src/assistant/tools/assistant/images/mac/book.png create mode 100644 src/assistant/tools/assistant/images/mac/closetab.png create mode 100644 src/assistant/tools/assistant/images/mac/editcopy.png create mode 100644 src/assistant/tools/assistant/images/mac/find.png create mode 100644 src/assistant/tools/assistant/images/mac/home.png create mode 100644 src/assistant/tools/assistant/images/mac/next.png create mode 100644 src/assistant/tools/assistant/images/mac/previous.png create mode 100644 src/assistant/tools/assistant/images/mac/print.png create mode 100644 src/assistant/tools/assistant/images/mac/resetzoom.png create mode 100644 src/assistant/tools/assistant/images/mac/synctoc.png create mode 100644 src/assistant/tools/assistant/images/mac/zoomin.png create mode 100644 src/assistant/tools/assistant/images/mac/zoomout.png create mode 100644 src/assistant/tools/assistant/images/trolltech-logo.png create mode 100644 src/assistant/tools/assistant/images/win/addtab.png create mode 100644 src/assistant/tools/assistant/images/win/book.png create mode 100644 src/assistant/tools/assistant/images/win/closetab.png create mode 100644 src/assistant/tools/assistant/images/win/editcopy.png create mode 100644 src/assistant/tools/assistant/images/win/find.png create mode 100644 src/assistant/tools/assistant/images/win/home.png create mode 100644 src/assistant/tools/assistant/images/win/next.png create mode 100644 src/assistant/tools/assistant/images/win/previous.png create mode 100644 src/assistant/tools/assistant/images/win/print.png create mode 100644 src/assistant/tools/assistant/images/win/resetzoom.png create mode 100644 src/assistant/tools/assistant/images/win/synctoc.png create mode 100644 src/assistant/tools/assistant/images/win/zoomin.png create mode 100644 src/assistant/tools/assistant/images/win/zoomout.png create mode 100644 src/assistant/tools/assistant/images/wrap.png create mode 100644 src/assistant/tools/assistant/indexwindow.cpp create mode 100644 src/assistant/tools/assistant/indexwindow.h create mode 100644 src/assistant/tools/assistant/installdialog.cpp create mode 100644 src/assistant/tools/assistant/installdialog.h create mode 100644 src/assistant/tools/assistant/installdialog.ui create mode 100644 src/assistant/tools/assistant/main.cpp create mode 100644 src/assistant/tools/assistant/mainwindow.cpp create mode 100644 src/assistant/tools/assistant/mainwindow.h create mode 100644 src/assistant/tools/assistant/openpagesmanager.cpp create mode 100644 src/assistant/tools/assistant/openpagesmanager.h create mode 100644 src/assistant/tools/assistant/openpagesmodel.cpp create mode 100644 src/assistant/tools/assistant/openpagesmodel.h create mode 100644 src/assistant/tools/assistant/openpagesswitcher.cpp create mode 100644 src/assistant/tools/assistant/openpagesswitcher.h create mode 100644 src/assistant/tools/assistant/openpageswidget.cpp create mode 100644 src/assistant/tools/assistant/openpageswidget.h create mode 100644 src/assistant/tools/assistant/preferencesdialog.cpp create mode 100644 src/assistant/tools/assistant/preferencesdialog.h create mode 100644 src/assistant/tools/assistant/preferencesdialog.ui create mode 100644 src/assistant/tools/assistant/qtdocinstaller.cpp create mode 100644 src/assistant/tools/assistant/qtdocinstaller.h create mode 100644 src/assistant/tools/assistant/remotecontrol.cpp create mode 100644 src/assistant/tools/assistant/remotecontrol.h create mode 100644 src/assistant/tools/assistant/remotecontrol_win.h create mode 100644 src/assistant/tools/assistant/searchwidget.cpp create mode 100644 src/assistant/tools/assistant/searchwidget.h create mode 100644 src/assistant/tools/assistant/topicchooser.cpp create mode 100644 src/assistant/tools/assistant/topicchooser.h create mode 100644 src/assistant/tools/assistant/topicchooser.ui create mode 100644 src/assistant/tools/assistant/tracer.h create mode 100644 src/assistant/tools/assistant/xbelsupport.cpp create mode 100644 src/assistant/tools/assistant/xbelsupport.h create mode 100644 src/assistant/tools/qcollectiongenerator/main.cpp create mode 100644 src/assistant/tools/qcollectiongenerator/qcollectiongenerator.pro create mode 100644 src/assistant/tools/qhelpconverter/adpreader.cpp create mode 100644 src/assistant/tools/qhelpconverter/adpreader.h create mode 100644 src/assistant/tools/qhelpconverter/assistant-128.png create mode 100644 src/assistant/tools/qhelpconverter/assistant.png create mode 100644 src/assistant/tools/qhelpconverter/conversionwizard.cpp create mode 100644 src/assistant/tools/qhelpconverter/conversionwizard.h create mode 100644 src/assistant/tools/qhelpconverter/doc/filespage.html create mode 100644 src/assistant/tools/qhelpconverter/doc/filterpage.html create mode 100644 src/assistant/tools/qhelpconverter/doc/generalpage.html create mode 100644 src/assistant/tools/qhelpconverter/doc/identifierpage.html create mode 100644 src/assistant/tools/qhelpconverter/doc/inputpage.html create mode 100644 src/assistant/tools/qhelpconverter/doc/outputpage.html create mode 100644 src/assistant/tools/qhelpconverter/doc/pathpage.html create mode 100644 src/assistant/tools/qhelpconverter/filespage.cpp create mode 100644 src/assistant/tools/qhelpconverter/filespage.h create mode 100644 src/assistant/tools/qhelpconverter/filespage.ui create mode 100644 src/assistant/tools/qhelpconverter/filterpage.cpp create mode 100644 src/assistant/tools/qhelpconverter/filterpage.h create mode 100644 src/assistant/tools/qhelpconverter/filterpage.ui create mode 100644 src/assistant/tools/qhelpconverter/finishpage.cpp create mode 100644 src/assistant/tools/qhelpconverter/finishpage.h create mode 100644 src/assistant/tools/qhelpconverter/generalpage.cpp create mode 100644 src/assistant/tools/qhelpconverter/generalpage.h create mode 100644 src/assistant/tools/qhelpconverter/generalpage.ui create mode 100644 src/assistant/tools/qhelpconverter/helpwindow.cpp create mode 100644 src/assistant/tools/qhelpconverter/helpwindow.h create mode 100644 src/assistant/tools/qhelpconverter/identifierpage.cpp create mode 100644 src/assistant/tools/qhelpconverter/identifierpage.h create mode 100644 src/assistant/tools/qhelpconverter/identifierpage.ui create mode 100644 src/assistant/tools/qhelpconverter/inputpage.cpp create mode 100644 src/assistant/tools/qhelpconverter/inputpage.h create mode 100644 src/assistant/tools/qhelpconverter/inputpage.ui create mode 100644 src/assistant/tools/qhelpconverter/main.cpp create mode 100644 src/assistant/tools/qhelpconverter/outputpage.cpp create mode 100644 src/assistant/tools/qhelpconverter/outputpage.h create mode 100644 src/assistant/tools/qhelpconverter/outputpage.ui create mode 100644 src/assistant/tools/qhelpconverter/pathpage.cpp create mode 100644 src/assistant/tools/qhelpconverter/pathpage.h create mode 100644 src/assistant/tools/qhelpconverter/pathpage.ui create mode 100644 src/assistant/tools/qhelpconverter/qhcpwriter.cpp create mode 100644 src/assistant/tools/qhelpconverter/qhcpwriter.h create mode 100644 src/assistant/tools/qhelpconverter/qhelpconverter.pro create mode 100644 src/assistant/tools/qhelpconverter/qhelpconverter.qrc create mode 100644 src/assistant/tools/qhelpconverter/qhpwriter.cpp create mode 100644 src/assistant/tools/qhelpconverter/qhpwriter.h create mode 100644 src/assistant/tools/qhelpgenerator/main.cpp create mode 100644 src/assistant/tools/qhelpgenerator/qhelpgenerator.pro create mode 100644 src/assistant/tools/shared/collectionconfiguration.cpp create mode 100644 src/assistant/tools/shared/collectionconfiguration.h create mode 100644 src/assistant/tools/shared/helpgenerator.cpp create mode 100644 src/assistant/tools/shared/helpgenerator.h create mode 100644 src/assistant/tools/tools.pro create mode 100644 src/checksdk/README create mode 100644 src/checksdk/cesdkhandler.cpp create mode 100644 src/checksdk/cesdkhandler.h create mode 100644 src/checksdk/checksdk.pro create mode 100644 src/checksdk/main.cpp create mode 100644 src/designer/data/generate_header.xsl create mode 100644 src/designer/data/generate_impl.xsl create mode 100644 src/designer/data/generate_shared.xsl create mode 100644 src/designer/data/ui3.xsd create mode 100644 src/designer/data/ui4.xsd create mode 100644 src/designer/designer.pro create mode 100644 src/designer/src/components/buddyeditor/buddyeditor.cpp create mode 100644 src/designer/src/components/buddyeditor/buddyeditor.h create mode 100644 src/designer/src/components/buddyeditor/buddyeditor.pri create mode 100644 src/designer/src/components/buddyeditor/buddyeditor_global.h create mode 100644 src/designer/src/components/buddyeditor/buddyeditor_instance.cpp create mode 100644 src/designer/src/components/buddyeditor/buddyeditor_plugin.cpp create mode 100644 src/designer/src/components/buddyeditor/buddyeditor_plugin.h create mode 100644 src/designer/src/components/buddyeditor/buddyeditor_tool.cpp create mode 100644 src/designer/src/components/buddyeditor/buddyeditor_tool.h create mode 100644 src/designer/src/components/component.pri create mode 100644 src/designer/src/components/components.pro create mode 100644 src/designer/src/components/formeditor/brushmanagerproxy.cpp create mode 100644 src/designer/src/components/formeditor/brushmanagerproxy.h create mode 100644 src/designer/src/components/formeditor/default_actionprovider.cpp create mode 100644 src/designer/src/components/formeditor/default_actionprovider.h create mode 100644 src/designer/src/components/formeditor/default_container.cpp create mode 100644 src/designer/src/components/formeditor/default_container.h create mode 100644 src/designer/src/components/formeditor/default_layoutdecoration.cpp create mode 100644 src/designer/src/components/formeditor/default_layoutdecoration.h create mode 100644 src/designer/src/components/formeditor/defaultbrushes.xml create mode 100644 src/designer/src/components/formeditor/deviceprofiledialog.cpp create mode 100644 src/designer/src/components/formeditor/deviceprofiledialog.h create mode 100644 src/designer/src/components/formeditor/deviceprofiledialog.ui create mode 100644 src/designer/src/components/formeditor/dpi_chooser.cpp create mode 100644 src/designer/src/components/formeditor/dpi_chooser.h create mode 100644 src/designer/src/components/formeditor/embeddedoptionspage.cpp create mode 100644 src/designer/src/components/formeditor/embeddedoptionspage.h create mode 100644 src/designer/src/components/formeditor/formeditor.cpp create mode 100644 src/designer/src/components/formeditor/formeditor.h create mode 100644 src/designer/src/components/formeditor/formeditor.pri create mode 100644 src/designer/src/components/formeditor/formeditor.qrc create mode 100644 src/designer/src/components/formeditor/formeditor_global.h create mode 100644 src/designer/src/components/formeditor/formeditor_optionspage.cpp create mode 100644 src/designer/src/components/formeditor/formeditor_optionspage.h create mode 100644 src/designer/src/components/formeditor/formwindow.cpp create mode 100644 src/designer/src/components/formeditor/formwindow.h create mode 100644 src/designer/src/components/formeditor/formwindow_dnditem.cpp create mode 100644 src/designer/src/components/formeditor/formwindow_dnditem.h create mode 100644 src/designer/src/components/formeditor/formwindow_widgetstack.cpp create mode 100644 src/designer/src/components/formeditor/formwindow_widgetstack.h create mode 100644 src/designer/src/components/formeditor/formwindowcursor.cpp create mode 100644 src/designer/src/components/formeditor/formwindowcursor.h create mode 100644 src/designer/src/components/formeditor/formwindowmanager.cpp create mode 100644 src/designer/src/components/formeditor/formwindowmanager.h create mode 100644 src/designer/src/components/formeditor/formwindowsettings.cpp create mode 100644 src/designer/src/components/formeditor/formwindowsettings.h create mode 100644 src/designer/src/components/formeditor/formwindowsettings.ui create mode 100644 src/designer/src/components/formeditor/iconcache.cpp create mode 100644 src/designer/src/components/formeditor/iconcache.h create mode 100644 src/designer/src/components/formeditor/images/cleartext.png create mode 100644 src/designer/src/components/formeditor/images/color.png create mode 100644 src/designer/src/components/formeditor/images/configure.png create mode 100644 src/designer/src/components/formeditor/images/cursors/arrow.png create mode 100644 src/designer/src/components/formeditor/images/cursors/busy.png create mode 100644 src/designer/src/components/formeditor/images/cursors/closedhand.png create mode 100644 src/designer/src/components/formeditor/images/cursors/cross.png create mode 100644 src/designer/src/components/formeditor/images/cursors/hand.png create mode 100644 src/designer/src/components/formeditor/images/cursors/hsplit.png create mode 100644 src/designer/src/components/formeditor/images/cursors/ibeam.png create mode 100644 src/designer/src/components/formeditor/images/cursors/no.png create mode 100644 src/designer/src/components/formeditor/images/cursors/openhand.png create mode 100644 src/designer/src/components/formeditor/images/cursors/sizeall.png create mode 100644 src/designer/src/components/formeditor/images/cursors/sizeb.png create mode 100644 src/designer/src/components/formeditor/images/cursors/sizef.png create mode 100644 src/designer/src/components/formeditor/images/cursors/sizeh.png create mode 100644 src/designer/src/components/formeditor/images/cursors/sizev.png create mode 100644 src/designer/src/components/formeditor/images/cursors/uparrow.png create mode 100644 src/designer/src/components/formeditor/images/cursors/vsplit.png create mode 100644 src/designer/src/components/formeditor/images/cursors/wait.png create mode 100644 src/designer/src/components/formeditor/images/cursors/whatsthis.png create mode 100644 src/designer/src/components/formeditor/images/downplus.png create mode 100644 src/designer/src/components/formeditor/images/dropdownbutton.png create mode 100644 src/designer/src/components/formeditor/images/edit.png create mode 100644 src/designer/src/components/formeditor/images/editdelete-16.png create mode 100644 src/designer/src/components/formeditor/images/emptyicon.png create mode 100644 src/designer/src/components/formeditor/images/filenew-16.png create mode 100644 src/designer/src/components/formeditor/images/fileopen-16.png create mode 100644 src/designer/src/components/formeditor/images/leveldown.png create mode 100644 src/designer/src/components/formeditor/images/levelup.png create mode 100644 src/designer/src/components/formeditor/images/mac/adjustsize.png create mode 100644 src/designer/src/components/formeditor/images/mac/back.png create mode 100644 src/designer/src/components/formeditor/images/mac/buddytool.png create mode 100644 src/designer/src/components/formeditor/images/mac/down.png create mode 100644 src/designer/src/components/formeditor/images/mac/editbreaklayout.png create mode 100644 src/designer/src/components/formeditor/images/mac/editcopy.png create mode 100644 src/designer/src/components/formeditor/images/mac/editcut.png create mode 100644 src/designer/src/components/formeditor/images/mac/editdelete.png create mode 100644 src/designer/src/components/formeditor/images/mac/editform.png create mode 100644 src/designer/src/components/formeditor/images/mac/editgrid.png create mode 100644 src/designer/src/components/formeditor/images/mac/edithlayout.png create mode 100644 src/designer/src/components/formeditor/images/mac/edithlayoutsplit.png create mode 100644 src/designer/src/components/formeditor/images/mac/editlower.png create mode 100644 src/designer/src/components/formeditor/images/mac/editpaste.png create mode 100644 src/designer/src/components/formeditor/images/mac/editraise.png create mode 100644 src/designer/src/components/formeditor/images/mac/editvlayout.png create mode 100644 src/designer/src/components/formeditor/images/mac/editvlayoutsplit.png create mode 100644 src/designer/src/components/formeditor/images/mac/filenew.png create mode 100644 src/designer/src/components/formeditor/images/mac/fileopen.png create mode 100644 src/designer/src/components/formeditor/images/mac/filesave.png create mode 100644 src/designer/src/components/formeditor/images/mac/forward.png create mode 100644 src/designer/src/components/formeditor/images/mac/insertimage.png create mode 100644 src/designer/src/components/formeditor/images/mac/minus.png create mode 100644 src/designer/src/components/formeditor/images/mac/plus.png create mode 100644 src/designer/src/components/formeditor/images/mac/redo.png create mode 100644 src/designer/src/components/formeditor/images/mac/resetproperty.png create mode 100644 src/designer/src/components/formeditor/images/mac/resourceeditortool.png create mode 100644 src/designer/src/components/formeditor/images/mac/signalslottool.png create mode 100644 src/designer/src/components/formeditor/images/mac/simplifyrichtext.png create mode 100644 src/designer/src/components/formeditor/images/mac/tabordertool.png create mode 100644 src/designer/src/components/formeditor/images/mac/textanchor.png create mode 100644 src/designer/src/components/formeditor/images/mac/textbold.png create mode 100644 src/designer/src/components/formeditor/images/mac/textcenter.png create mode 100644 src/designer/src/components/formeditor/images/mac/textitalic.png create mode 100644 src/designer/src/components/formeditor/images/mac/textjustify.png create mode 100644 src/designer/src/components/formeditor/images/mac/textleft.png create mode 100644 src/designer/src/components/formeditor/images/mac/textright.png create mode 100644 src/designer/src/components/formeditor/images/mac/textsubscript.png create mode 100644 src/designer/src/components/formeditor/images/mac/textsuperscript.png create mode 100644 src/designer/src/components/formeditor/images/mac/textunder.png create mode 100644 src/designer/src/components/formeditor/images/mac/undo.png create mode 100644 src/designer/src/components/formeditor/images/mac/up.png create mode 100644 src/designer/src/components/formeditor/images/mac/widgettool.png create mode 100644 src/designer/src/components/formeditor/images/minus-16.png create mode 100644 src/designer/src/components/formeditor/images/plus-16.png create mode 100644 src/designer/src/components/formeditor/images/prefix-add.png create mode 100644 src/designer/src/components/formeditor/images/qt3logo.png create mode 100644 src/designer/src/components/formeditor/images/qtlogo.png create mode 100644 src/designer/src/components/formeditor/images/reload.png create mode 100644 src/designer/src/components/formeditor/images/resetproperty.png create mode 100644 src/designer/src/components/formeditor/images/sort.png create mode 100644 src/designer/src/components/formeditor/images/submenu.png create mode 100644 src/designer/src/components/formeditor/images/widgets/calendarwidget.png create mode 100644 src/designer/src/components/formeditor/images/widgets/checkbox.png create mode 100644 src/designer/src/components/formeditor/images/widgets/columnview.png create mode 100644 src/designer/src/components/formeditor/images/widgets/combobox.png create mode 100644 src/designer/src/components/formeditor/images/widgets/commandlinkbutton.png create mode 100644 src/designer/src/components/formeditor/images/widgets/dateedit.png create mode 100644 src/designer/src/components/formeditor/images/widgets/datetimeedit.png create mode 100644 src/designer/src/components/formeditor/images/widgets/dial.png create mode 100644 src/designer/src/components/formeditor/images/widgets/dialogbuttonbox.png create mode 100644 src/designer/src/components/formeditor/images/widgets/dockwidget.png create mode 100644 src/designer/src/components/formeditor/images/widgets/doublespinbox.png create mode 100644 src/designer/src/components/formeditor/images/widgets/fontcombobox.png create mode 100644 src/designer/src/components/formeditor/images/widgets/frame.png create mode 100644 src/designer/src/components/formeditor/images/widgets/graphicsview.png create mode 100644 src/designer/src/components/formeditor/images/widgets/groupbox.png create mode 100644 src/designer/src/components/formeditor/images/widgets/groupboxcollapsible.png create mode 100644 src/designer/src/components/formeditor/images/widgets/hscrollbar.png create mode 100644 src/designer/src/components/formeditor/images/widgets/hslider.png create mode 100644 src/designer/src/components/formeditor/images/widgets/hsplit.png create mode 100644 src/designer/src/components/formeditor/images/widgets/label.png create mode 100644 src/designer/src/components/formeditor/images/widgets/lcdnumber.png create mode 100644 src/designer/src/components/formeditor/images/widgets/line.png create mode 100644 src/designer/src/components/formeditor/images/widgets/lineedit.png create mode 100644 src/designer/src/components/formeditor/images/widgets/listbox.png create mode 100644 src/designer/src/components/formeditor/images/widgets/listview.png create mode 100644 src/designer/src/components/formeditor/images/widgets/mdiarea.png create mode 100644 src/designer/src/components/formeditor/images/widgets/plaintextedit.png create mode 100644 src/designer/src/components/formeditor/images/widgets/progress.png create mode 100644 src/designer/src/components/formeditor/images/widgets/pushbutton.png create mode 100644 src/designer/src/components/formeditor/images/widgets/radiobutton.png create mode 100644 src/designer/src/components/formeditor/images/widgets/scrollarea.png create mode 100644 src/designer/src/components/formeditor/images/widgets/spacer.png create mode 100644 src/designer/src/components/formeditor/images/widgets/spinbox.png create mode 100644 src/designer/src/components/formeditor/images/widgets/tabbar.png create mode 100644 src/designer/src/components/formeditor/images/widgets/table.png create mode 100644 src/designer/src/components/formeditor/images/widgets/tabwidget.png create mode 100644 src/designer/src/components/formeditor/images/widgets/textedit.png create mode 100644 src/designer/src/components/formeditor/images/widgets/timeedit.png create mode 100644 src/designer/src/components/formeditor/images/widgets/toolbox.png create mode 100644 src/designer/src/components/formeditor/images/widgets/toolbutton.png create mode 100644 src/designer/src/components/formeditor/images/widgets/vline.png create mode 100644 src/designer/src/components/formeditor/images/widgets/vscrollbar.png create mode 100644 src/designer/src/components/formeditor/images/widgets/vslider.png create mode 100644 src/designer/src/components/formeditor/images/widgets/vspacer.png create mode 100644 src/designer/src/components/formeditor/images/widgets/widget.png create mode 100644 src/designer/src/components/formeditor/images/widgets/widgetstack.png create mode 100644 src/designer/src/components/formeditor/images/widgets/wizard.png create mode 100644 src/designer/src/components/formeditor/images/win/adjustsize.png create mode 100644 src/designer/src/components/formeditor/images/win/back.png create mode 100644 src/designer/src/components/formeditor/images/win/buddytool.png create mode 100644 src/designer/src/components/formeditor/images/win/down.png create mode 100644 src/designer/src/components/formeditor/images/win/editbreaklayout.png create mode 100644 src/designer/src/components/formeditor/images/win/editcopy.png create mode 100644 src/designer/src/components/formeditor/images/win/editcut.png create mode 100644 src/designer/src/components/formeditor/images/win/editdelete.png create mode 100644 src/designer/src/components/formeditor/images/win/editform.png create mode 100644 src/designer/src/components/formeditor/images/win/editgrid.png create mode 100644 src/designer/src/components/formeditor/images/win/edithlayout.png create mode 100644 src/designer/src/components/formeditor/images/win/edithlayoutsplit.png create mode 100644 src/designer/src/components/formeditor/images/win/editlower.png create mode 100644 src/designer/src/components/formeditor/images/win/editpaste.png create mode 100644 src/designer/src/components/formeditor/images/win/editraise.png create mode 100644 src/designer/src/components/formeditor/images/win/editvlayout.png create mode 100644 src/designer/src/components/formeditor/images/win/editvlayoutsplit.png create mode 100644 src/designer/src/components/formeditor/images/win/filenew.png create mode 100644 src/designer/src/components/formeditor/images/win/fileopen.png create mode 100644 src/designer/src/components/formeditor/images/win/filesave.png create mode 100644 src/designer/src/components/formeditor/images/win/forward.png create mode 100644 src/designer/src/components/formeditor/images/win/insertimage.png create mode 100644 src/designer/src/components/formeditor/images/win/minus.png create mode 100644 src/designer/src/components/formeditor/images/win/plus.png create mode 100644 src/designer/src/components/formeditor/images/win/redo.png create mode 100644 src/designer/src/components/formeditor/images/win/resourceeditortool.png create mode 100644 src/designer/src/components/formeditor/images/win/signalslottool.png create mode 100644 src/designer/src/components/formeditor/images/win/simplifyrichtext.png create mode 100644 src/designer/src/components/formeditor/images/win/tabordertool.png create mode 100644 src/designer/src/components/formeditor/images/win/textanchor.png create mode 100644 src/designer/src/components/formeditor/images/win/textbold.png create mode 100644 src/designer/src/components/formeditor/images/win/textcenter.png create mode 100644 src/designer/src/components/formeditor/images/win/textitalic.png create mode 100644 src/designer/src/components/formeditor/images/win/textjustify.png create mode 100644 src/designer/src/components/formeditor/images/win/textleft.png create mode 100644 src/designer/src/components/formeditor/images/win/textright.png create mode 100644 src/designer/src/components/formeditor/images/win/textsubscript.png create mode 100644 src/designer/src/components/formeditor/images/win/textsuperscript.png create mode 100644 src/designer/src/components/formeditor/images/win/textunder.png create mode 100644 src/designer/src/components/formeditor/images/win/undo.png create mode 100644 src/designer/src/components/formeditor/images/win/up.png create mode 100644 src/designer/src/components/formeditor/images/win/widgettool.png create mode 100644 src/designer/src/components/formeditor/itemview_propertysheet.cpp create mode 100644 src/designer/src/components/formeditor/itemview_propertysheet.h create mode 100644 src/designer/src/components/formeditor/layout_propertysheet.cpp create mode 100644 src/designer/src/components/formeditor/layout_propertysheet.h create mode 100644 src/designer/src/components/formeditor/line_propertysheet.cpp create mode 100644 src/designer/src/components/formeditor/line_propertysheet.h create mode 100644 src/designer/src/components/formeditor/previewactiongroup.cpp create mode 100644 src/designer/src/components/formeditor/previewactiongroup.h create mode 100644 src/designer/src/components/formeditor/qdesigner_resource.cpp create mode 100644 src/designer/src/components/formeditor/qdesigner_resource.h create mode 100644 src/designer/src/components/formeditor/qdesignerundostack.cpp create mode 100644 src/designer/src/components/formeditor/qdesignerundostack.h create mode 100644 src/designer/src/components/formeditor/qlayoutwidget_propertysheet.cpp create mode 100644 src/designer/src/components/formeditor/qlayoutwidget_propertysheet.h create mode 100644 src/designer/src/components/formeditor/qmainwindow_container.cpp create mode 100644 src/designer/src/components/formeditor/qmainwindow_container.h create mode 100644 src/designer/src/components/formeditor/qmdiarea_container.cpp create mode 100644 src/designer/src/components/formeditor/qmdiarea_container.h create mode 100644 src/designer/src/components/formeditor/qtbrushmanager.cpp create mode 100644 src/designer/src/components/formeditor/qtbrushmanager.h create mode 100644 src/designer/src/components/formeditor/qwizard_container.cpp create mode 100644 src/designer/src/components/formeditor/qwizard_container.h create mode 100644 src/designer/src/components/formeditor/qworkspace_container.cpp create mode 100644 src/designer/src/components/formeditor/qworkspace_container.h create mode 100644 src/designer/src/components/formeditor/spacer_propertysheet.cpp create mode 100644 src/designer/src/components/formeditor/spacer_propertysheet.h create mode 100644 src/designer/src/components/formeditor/templateoptionspage.cpp create mode 100644 src/designer/src/components/formeditor/templateoptionspage.h create mode 100644 src/designer/src/components/formeditor/templateoptionspage.ui create mode 100644 src/designer/src/components/formeditor/tool_widgeteditor.cpp create mode 100644 src/designer/src/components/formeditor/tool_widgeteditor.h create mode 100644 src/designer/src/components/formeditor/widgetselection.cpp create mode 100644 src/designer/src/components/formeditor/widgetselection.h create mode 100644 src/designer/src/components/lib/lib.pro create mode 100644 src/designer/src/components/lib/lib_pch.h create mode 100644 src/designer/src/components/lib/qdesigner_components.cpp create mode 100644 src/designer/src/components/objectinspector/objectinspector.cpp create mode 100644 src/designer/src/components/objectinspector/objectinspector.h create mode 100644 src/designer/src/components/objectinspector/objectinspector.pri create mode 100644 src/designer/src/components/objectinspector/objectinspector_global.h create mode 100644 src/designer/src/components/objectinspector/objectinspectormodel.cpp create mode 100644 src/designer/src/components/objectinspector/objectinspectormodel_p.h create mode 100644 src/designer/src/components/propertyeditor/brushpropertymanager.cpp create mode 100644 src/designer/src/components/propertyeditor/brushpropertymanager.h create mode 100644 src/designer/src/components/propertyeditor/designerpropertymanager.cpp create mode 100644 src/designer/src/components/propertyeditor/designerpropertymanager.h create mode 100644 src/designer/src/components/propertyeditor/fontmapping.xml create mode 100644 src/designer/src/components/propertyeditor/fontpropertymanager.cpp create mode 100644 src/designer/src/components/propertyeditor/fontpropertymanager.h create mode 100644 src/designer/src/components/propertyeditor/newdynamicpropertydialog.cpp create mode 100644 src/designer/src/components/propertyeditor/newdynamicpropertydialog.h create mode 100644 src/designer/src/components/propertyeditor/newdynamicpropertydialog.ui create mode 100644 src/designer/src/components/propertyeditor/paletteeditor.cpp create mode 100644 src/designer/src/components/propertyeditor/paletteeditor.h create mode 100644 src/designer/src/components/propertyeditor/paletteeditor.ui create mode 100644 src/designer/src/components/propertyeditor/paletteeditorbutton.cpp create mode 100644 src/designer/src/components/propertyeditor/paletteeditorbutton.h create mode 100644 src/designer/src/components/propertyeditor/previewframe.cpp create mode 100644 src/designer/src/components/propertyeditor/previewframe.h create mode 100644 src/designer/src/components/propertyeditor/previewwidget.cpp create mode 100644 src/designer/src/components/propertyeditor/previewwidget.h create mode 100644 src/designer/src/components/propertyeditor/previewwidget.ui create mode 100644 src/designer/src/components/propertyeditor/propertyeditor.cpp create mode 100644 src/designer/src/components/propertyeditor/propertyeditor.h create mode 100644 src/designer/src/components/propertyeditor/propertyeditor.pri create mode 100644 src/designer/src/components/propertyeditor/propertyeditor.qrc create mode 100644 src/designer/src/components/propertyeditor/propertyeditor_global.h create mode 100644 src/designer/src/components/propertyeditor/qlonglongvalidator.cpp create mode 100644 src/designer/src/components/propertyeditor/qlonglongvalidator.h create mode 100644 src/designer/src/components/propertyeditor/stringlisteditor.cpp create mode 100644 src/designer/src/components/propertyeditor/stringlisteditor.h create mode 100644 src/designer/src/components/propertyeditor/stringlisteditor.ui create mode 100644 src/designer/src/components/propertyeditor/stringlisteditorbutton.cpp create mode 100644 src/designer/src/components/propertyeditor/stringlisteditorbutton.h create mode 100644 src/designer/src/components/signalsloteditor/connectdialog.cpp create mode 100644 src/designer/src/components/signalsloteditor/connectdialog.ui create mode 100644 src/designer/src/components/signalsloteditor/connectdialog_p.h create mode 100644 src/designer/src/components/signalsloteditor/signalslot_utils.cpp create mode 100644 src/designer/src/components/signalsloteditor/signalslot_utils_p.h create mode 100644 src/designer/src/components/signalsloteditor/signalsloteditor.cpp create mode 100644 src/designer/src/components/signalsloteditor/signalsloteditor.h create mode 100644 src/designer/src/components/signalsloteditor/signalsloteditor.pri create mode 100644 src/designer/src/components/signalsloteditor/signalsloteditor_global.h create mode 100644 src/designer/src/components/signalsloteditor/signalsloteditor_instance.cpp create mode 100644 src/designer/src/components/signalsloteditor/signalsloteditor_p.h create mode 100644 src/designer/src/components/signalsloteditor/signalsloteditor_plugin.cpp create mode 100644 src/designer/src/components/signalsloteditor/signalsloteditor_plugin.h create mode 100644 src/designer/src/components/signalsloteditor/signalsloteditor_tool.cpp create mode 100644 src/designer/src/components/signalsloteditor/signalsloteditor_tool.h create mode 100644 src/designer/src/components/signalsloteditor/signalsloteditorwindow.cpp create mode 100644 src/designer/src/components/signalsloteditor/signalsloteditorwindow.h create mode 100644 src/designer/src/components/tabordereditor/tabordereditor.cpp create mode 100644 src/designer/src/components/tabordereditor/tabordereditor.h create mode 100644 src/designer/src/components/tabordereditor/tabordereditor.pri create mode 100644 src/designer/src/components/tabordereditor/tabordereditor_global.h create mode 100644 src/designer/src/components/tabordereditor/tabordereditor_instance.cpp create mode 100644 src/designer/src/components/tabordereditor/tabordereditor_plugin.cpp create mode 100644 src/designer/src/components/tabordereditor/tabordereditor_plugin.h create mode 100644 src/designer/src/components/tabordereditor/tabordereditor_tool.cpp create mode 100644 src/designer/src/components/tabordereditor/tabordereditor_tool.h create mode 100644 src/designer/src/components/taskmenu/button_taskmenu.cpp create mode 100644 src/designer/src/components/taskmenu/button_taskmenu.h create mode 100644 src/designer/src/components/taskmenu/combobox_taskmenu.cpp create mode 100644 src/designer/src/components/taskmenu/combobox_taskmenu.h create mode 100644 src/designer/src/components/taskmenu/containerwidget_taskmenu.cpp create mode 100644 src/designer/src/components/taskmenu/containerwidget_taskmenu.h create mode 100644 src/designer/src/components/taskmenu/groupbox_taskmenu.cpp create mode 100644 src/designer/src/components/taskmenu/groupbox_taskmenu.h create mode 100644 src/designer/src/components/taskmenu/inplace_editor.cpp create mode 100644 src/designer/src/components/taskmenu/inplace_editor.h create mode 100644 src/designer/src/components/taskmenu/inplace_widget_helper.cpp create mode 100644 src/designer/src/components/taskmenu/inplace_widget_helper.h create mode 100644 src/designer/src/components/taskmenu/itemlisteditor.cpp create mode 100644 src/designer/src/components/taskmenu/itemlisteditor.h create mode 100644 src/designer/src/components/taskmenu/itemlisteditor.ui create mode 100644 src/designer/src/components/taskmenu/label_taskmenu.cpp create mode 100644 src/designer/src/components/taskmenu/label_taskmenu.h create mode 100644 src/designer/src/components/taskmenu/layouttaskmenu.cpp create mode 100644 src/designer/src/components/taskmenu/layouttaskmenu.h create mode 100644 src/designer/src/components/taskmenu/lineedit_taskmenu.cpp create mode 100644 src/designer/src/components/taskmenu/lineedit_taskmenu.h create mode 100644 src/designer/src/components/taskmenu/listwidget_taskmenu.cpp create mode 100644 src/designer/src/components/taskmenu/listwidget_taskmenu.h create mode 100644 src/designer/src/components/taskmenu/listwidgeteditor.cpp create mode 100644 src/designer/src/components/taskmenu/listwidgeteditor.h create mode 100644 src/designer/src/components/taskmenu/menutaskmenu.cpp create mode 100644 src/designer/src/components/taskmenu/menutaskmenu.h create mode 100644 src/designer/src/components/taskmenu/tablewidget_taskmenu.cpp create mode 100644 src/designer/src/components/taskmenu/tablewidget_taskmenu.h create mode 100644 src/designer/src/components/taskmenu/tablewidgeteditor.cpp create mode 100644 src/designer/src/components/taskmenu/tablewidgeteditor.h create mode 100644 src/designer/src/components/taskmenu/tablewidgeteditor.ui create mode 100644 src/designer/src/components/taskmenu/taskmenu.pri create mode 100644 src/designer/src/components/taskmenu/taskmenu_component.cpp create mode 100644 src/designer/src/components/taskmenu/taskmenu_component.h create mode 100644 src/designer/src/components/taskmenu/taskmenu_global.h create mode 100644 src/designer/src/components/taskmenu/textedit_taskmenu.cpp create mode 100644 src/designer/src/components/taskmenu/textedit_taskmenu.h create mode 100644 src/designer/src/components/taskmenu/toolbar_taskmenu.cpp create mode 100644 src/designer/src/components/taskmenu/toolbar_taskmenu.h create mode 100644 src/designer/src/components/taskmenu/treewidget_taskmenu.cpp create mode 100644 src/designer/src/components/taskmenu/treewidget_taskmenu.h create mode 100644 src/designer/src/components/taskmenu/treewidgeteditor.cpp create mode 100644 src/designer/src/components/taskmenu/treewidgeteditor.h create mode 100644 src/designer/src/components/taskmenu/treewidgeteditor.ui create mode 100644 src/designer/src/components/widgetbox/widgetbox.cpp create mode 100644 src/designer/src/components/widgetbox/widgetbox.h create mode 100644 src/designer/src/components/widgetbox/widgetbox.pri create mode 100644 src/designer/src/components/widgetbox/widgetbox.qrc create mode 100644 src/designer/src/components/widgetbox/widgetbox.xml create mode 100644 src/designer/src/components/widgetbox/widgetbox_dnditem.cpp create mode 100644 src/designer/src/components/widgetbox/widgetbox_dnditem.h create mode 100644 src/designer/src/components/widgetbox/widgetbox_global.h create mode 100644 src/designer/src/components/widgetbox/widgetboxcategorylistview.cpp create mode 100644 src/designer/src/components/widgetbox/widgetboxcategorylistview.h create mode 100644 src/designer/src/components/widgetbox/widgetboxtreewidget.cpp create mode 100644 src/designer/src/components/widgetbox/widgetboxtreewidget.h create mode 100644 src/designer/src/designer/Info_mac.plist create mode 100644 src/designer/src/designer/appfontdialog.cpp create mode 100644 src/designer/src/designer/appfontdialog.h create mode 100644 src/designer/src/designer/assistantclient.cpp create mode 100644 src/designer/src/designer/assistantclient.h create mode 100644 src/designer/src/designer/designer.icns create mode 100644 src/designer/src/designer/designer.ico create mode 100644 src/designer/src/designer/designer.pro create mode 100644 src/designer/src/designer/designer.qrc create mode 100644 src/designer/src/designer/designer.rc create mode 100644 src/designer/src/designer/designer_enums.h create mode 100644 src/designer/src/designer/images/designer.png create mode 100644 src/designer/src/designer/images/mdi.png create mode 100644 src/designer/src/designer/images/sdi.png create mode 100644 src/designer/src/designer/images/workbench.png create mode 100644 src/designer/src/designer/main.cpp create mode 100644 src/designer/src/designer/mainwindow.cpp create mode 100644 src/designer/src/designer/mainwindow.h create mode 100644 src/designer/src/designer/newform.cpp create mode 100644 src/designer/src/designer/newform.h create mode 100644 src/designer/src/designer/preferencesdialog.cpp create mode 100644 src/designer/src/designer/preferencesdialog.h create mode 100644 src/designer/src/designer/preferencesdialog.ui create mode 100644 src/designer/src/designer/qdesigner.cpp create mode 100644 src/designer/src/designer/qdesigner.h create mode 100644 src/designer/src/designer/qdesigner_actions.cpp create mode 100644 src/designer/src/designer/qdesigner_actions.h create mode 100644 src/designer/src/designer/qdesigner_appearanceoptions.cpp create mode 100644 src/designer/src/designer/qdesigner_appearanceoptions.h create mode 100644 src/designer/src/designer/qdesigner_appearanceoptions.ui create mode 100644 src/designer/src/designer/qdesigner_formwindow.cpp create mode 100644 src/designer/src/designer/qdesigner_formwindow.h create mode 100644 src/designer/src/designer/qdesigner_pch.h create mode 100644 src/designer/src/designer/qdesigner_server.cpp create mode 100644 src/designer/src/designer/qdesigner_server.h create mode 100644 src/designer/src/designer/qdesigner_settings.cpp create mode 100644 src/designer/src/designer/qdesigner_settings.h create mode 100644 src/designer/src/designer/qdesigner_toolwindow.cpp create mode 100644 src/designer/src/designer/qdesigner_toolwindow.h create mode 100644 src/designer/src/designer/qdesigner_workbench.cpp create mode 100644 src/designer/src/designer/qdesigner_workbench.h create mode 100644 src/designer/src/designer/saveformastemplate.cpp create mode 100644 src/designer/src/designer/saveformastemplate.h create mode 100644 src/designer/src/designer/saveformastemplate.ui create mode 100644 src/designer/src/designer/uifile.icns create mode 100644 src/designer/src/designer/versiondialog.cpp create mode 100644 src/designer/src/designer/versiondialog.h create mode 100644 src/designer/src/lib/components/qdesigner_components.h create mode 100644 src/designer/src/lib/components/qdesigner_components_global.h create mode 100644 src/designer/src/lib/extension/default_extensionfactory.cpp create mode 100644 src/designer/src/lib/extension/default_extensionfactory.h create mode 100644 src/designer/src/lib/extension/extension.cpp create mode 100644 src/designer/src/lib/extension/extension.h create mode 100644 src/designer/src/lib/extension/extension.pri create mode 100644 src/designer/src/lib/extension/extension_global.h create mode 100644 src/designer/src/lib/extension/qextensionmanager.cpp create mode 100644 src/designer/src/lib/extension/qextensionmanager.h create mode 100644 src/designer/src/lib/lib.pro create mode 100644 src/designer/src/lib/lib_pch.h create mode 100644 src/designer/src/lib/sdk/abstractactioneditor.cpp create mode 100644 src/designer/src/lib/sdk/abstractactioneditor.h create mode 100644 src/designer/src/lib/sdk/abstractbrushmanager.h create mode 100644 src/designer/src/lib/sdk/abstractdialoggui.cpp create mode 100644 src/designer/src/lib/sdk/abstractdialoggui_p.h create mode 100644 src/designer/src/lib/sdk/abstractdnditem.h create mode 100644 src/designer/src/lib/sdk/abstractdnditem.qdoc create mode 100644 src/designer/src/lib/sdk/abstractformeditor.cpp create mode 100644 src/designer/src/lib/sdk/abstractformeditor.h create mode 100644 src/designer/src/lib/sdk/abstractformeditorplugin.cpp create mode 100644 src/designer/src/lib/sdk/abstractformeditorplugin.h create mode 100644 src/designer/src/lib/sdk/abstractformwindow.cpp create mode 100644 src/designer/src/lib/sdk/abstractformwindow.h create mode 100644 src/designer/src/lib/sdk/abstractformwindowcursor.cpp create mode 100644 src/designer/src/lib/sdk/abstractformwindowcursor.h create mode 100644 src/designer/src/lib/sdk/abstractformwindowmanager.cpp create mode 100644 src/designer/src/lib/sdk/abstractformwindowmanager.h create mode 100644 src/designer/src/lib/sdk/abstractformwindowtool.cpp create mode 100644 src/designer/src/lib/sdk/abstractformwindowtool.h create mode 100644 src/designer/src/lib/sdk/abstracticoncache.h create mode 100644 src/designer/src/lib/sdk/abstracticoncache.qdoc create mode 100644 src/designer/src/lib/sdk/abstractintegration.cpp create mode 100644 src/designer/src/lib/sdk/abstractintegration.h create mode 100644 src/designer/src/lib/sdk/abstractintrospection.cpp create mode 100644 src/designer/src/lib/sdk/abstractintrospection_p.h create mode 100644 src/designer/src/lib/sdk/abstractlanguage.h create mode 100644 src/designer/src/lib/sdk/abstractmetadatabase.cpp create mode 100644 src/designer/src/lib/sdk/abstractmetadatabase.h create mode 100644 src/designer/src/lib/sdk/abstractnewformwidget.cpp create mode 100644 src/designer/src/lib/sdk/abstractnewformwidget_p.h create mode 100644 src/designer/src/lib/sdk/abstractobjectinspector.cpp create mode 100644 src/designer/src/lib/sdk/abstractobjectinspector.h create mode 100644 src/designer/src/lib/sdk/abstractoptionspage_p.h create mode 100644 src/designer/src/lib/sdk/abstractpromotioninterface.cpp create mode 100644 src/designer/src/lib/sdk/abstractpromotioninterface.h create mode 100644 src/designer/src/lib/sdk/abstractpropertyeditor.cpp create mode 100644 src/designer/src/lib/sdk/abstractpropertyeditor.h create mode 100644 src/designer/src/lib/sdk/abstractresourcebrowser.cpp create mode 100644 src/designer/src/lib/sdk/abstractresourcebrowser.h create mode 100644 src/designer/src/lib/sdk/abstractsettings_p.h create mode 100644 src/designer/src/lib/sdk/abstractwidgetbox.cpp create mode 100644 src/designer/src/lib/sdk/abstractwidgetbox.h create mode 100644 src/designer/src/lib/sdk/abstractwidgetdatabase.cpp create mode 100644 src/designer/src/lib/sdk/abstractwidgetdatabase.h create mode 100644 src/designer/src/lib/sdk/abstractwidgetfactory.cpp create mode 100644 src/designer/src/lib/sdk/abstractwidgetfactory.h create mode 100644 src/designer/src/lib/sdk/dynamicpropertysheet.h create mode 100644 src/designer/src/lib/sdk/dynamicpropertysheet.qdoc create mode 100644 src/designer/src/lib/sdk/extrainfo.cpp create mode 100644 src/designer/src/lib/sdk/extrainfo.h create mode 100644 src/designer/src/lib/sdk/layoutdecoration.h create mode 100644 src/designer/src/lib/sdk/layoutdecoration.qdoc create mode 100644 src/designer/src/lib/sdk/membersheet.h create mode 100644 src/designer/src/lib/sdk/membersheet.qdoc create mode 100644 src/designer/src/lib/sdk/propertysheet.h create mode 100644 src/designer/src/lib/sdk/propertysheet.qdoc create mode 100644 src/designer/src/lib/sdk/script.cpp create mode 100644 src/designer/src/lib/sdk/script_p.h create mode 100644 src/designer/src/lib/sdk/sdk.pri create mode 100644 src/designer/src/lib/sdk/sdk_global.h create mode 100644 src/designer/src/lib/sdk/taskmenu.h create mode 100644 src/designer/src/lib/sdk/taskmenu.qdoc create mode 100644 src/designer/src/lib/shared/actioneditor.cpp create mode 100644 src/designer/src/lib/shared/actioneditor_p.h create mode 100644 src/designer/src/lib/shared/actionprovider_p.h create mode 100644 src/designer/src/lib/shared/actionrepository.cpp create mode 100644 src/designer/src/lib/shared/actionrepository_p.h create mode 100644 src/designer/src/lib/shared/addlinkdialog.ui create mode 100644 src/designer/src/lib/shared/codedialog.cpp create mode 100644 src/designer/src/lib/shared/codedialog_p.h create mode 100644 src/designer/src/lib/shared/connectionedit.cpp create mode 100644 src/designer/src/lib/shared/connectionedit_p.h create mode 100644 src/designer/src/lib/shared/csshighlighter.cpp create mode 100644 src/designer/src/lib/shared/csshighlighter_p.h create mode 100644 src/designer/src/lib/shared/defaultgradients.xml create mode 100644 src/designer/src/lib/shared/deviceprofile.cpp create mode 100644 src/designer/src/lib/shared/deviceprofile_p.h create mode 100644 src/designer/src/lib/shared/dialoggui.cpp create mode 100644 src/designer/src/lib/shared/dialoggui_p.h create mode 100644 src/designer/src/lib/shared/extensionfactory_p.h create mode 100644 src/designer/src/lib/shared/filterwidget.cpp create mode 100644 src/designer/src/lib/shared/filterwidget_p.h create mode 100644 src/designer/src/lib/shared/formlayoutmenu.cpp create mode 100644 src/designer/src/lib/shared/formlayoutmenu_p.h create mode 100644 src/designer/src/lib/shared/formlayoutrowdialog.ui create mode 100644 src/designer/src/lib/shared/formwindowbase.cpp create mode 100644 src/designer/src/lib/shared/formwindowbase_p.h create mode 100644 src/designer/src/lib/shared/grid.cpp create mode 100644 src/designer/src/lib/shared/grid_p.h create mode 100644 src/designer/src/lib/shared/gridpanel.cpp create mode 100644 src/designer/src/lib/shared/gridpanel.ui create mode 100644 src/designer/src/lib/shared/gridpanel_p.h create mode 100644 src/designer/src/lib/shared/htmlhighlighter.cpp create mode 100644 src/designer/src/lib/shared/htmlhighlighter_p.h create mode 100644 src/designer/src/lib/shared/iconloader.cpp create mode 100644 src/designer/src/lib/shared/iconloader_p.h create mode 100644 src/designer/src/lib/shared/iconselector.cpp create mode 100644 src/designer/src/lib/shared/iconselector_p.h create mode 100644 src/designer/src/lib/shared/invisible_widget.cpp create mode 100644 src/designer/src/lib/shared/invisible_widget_p.h create mode 100644 src/designer/src/lib/shared/layout.cpp create mode 100644 src/designer/src/lib/shared/layout_p.h create mode 100644 src/designer/src/lib/shared/layoutinfo.cpp create mode 100644 src/designer/src/lib/shared/layoutinfo_p.h create mode 100644 src/designer/src/lib/shared/metadatabase.cpp create mode 100644 src/designer/src/lib/shared/metadatabase_p.h create mode 100644 src/designer/src/lib/shared/morphmenu.cpp create mode 100644 src/designer/src/lib/shared/morphmenu_p.h create mode 100644 src/designer/src/lib/shared/newactiondialog.cpp create mode 100644 src/designer/src/lib/shared/newactiondialog.ui create mode 100644 src/designer/src/lib/shared/newactiondialog_p.h create mode 100644 src/designer/src/lib/shared/newformwidget.cpp create mode 100644 src/designer/src/lib/shared/newformwidget.ui create mode 100644 src/designer/src/lib/shared/newformwidget_p.h create mode 100644 src/designer/src/lib/shared/orderdialog.cpp create mode 100644 src/designer/src/lib/shared/orderdialog.ui create mode 100644 src/designer/src/lib/shared/orderdialog_p.h create mode 100644 src/designer/src/lib/shared/plaintexteditor.cpp create mode 100644 src/designer/src/lib/shared/plaintexteditor_p.h create mode 100644 src/designer/src/lib/shared/plugindialog.cpp create mode 100644 src/designer/src/lib/shared/plugindialog.ui create mode 100644 src/designer/src/lib/shared/plugindialog_p.h create mode 100644 src/designer/src/lib/shared/pluginmanager.cpp create mode 100644 src/designer/src/lib/shared/pluginmanager_p.h create mode 100644 src/designer/src/lib/shared/previewconfigurationwidget.cpp create mode 100644 src/designer/src/lib/shared/previewconfigurationwidget.ui create mode 100644 src/designer/src/lib/shared/previewconfigurationwidget_p.h create mode 100644 src/designer/src/lib/shared/previewmanager.cpp create mode 100644 src/designer/src/lib/shared/previewmanager_p.h create mode 100644 src/designer/src/lib/shared/promotionmodel.cpp create mode 100644 src/designer/src/lib/shared/promotionmodel_p.h create mode 100644 src/designer/src/lib/shared/promotiontaskmenu.cpp create mode 100644 src/designer/src/lib/shared/promotiontaskmenu_p.h create mode 100644 src/designer/src/lib/shared/propertylineedit.cpp create mode 100644 src/designer/src/lib/shared/propertylineedit_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_command.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_command2.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_command2_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_command_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_dnditem.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_dnditem_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_dockwidget.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_dockwidget_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_formbuilder.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_formbuilder_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_formeditorcommand.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_formeditorcommand_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_formwindowcommand.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_formwindowcommand_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_formwindowmanager.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_formwindowmanager_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_integration.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_integration_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_introspection.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_introspection_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_membersheet.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_membersheet_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_menu.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_menu_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_menubar.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_menubar_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_objectinspector.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_objectinspector_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_promotion.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_promotion_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_promotiondialog.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_promotiondialog_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_propertycommand.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_propertycommand_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_propertyeditor.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_propertyeditor_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_propertysheet.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_propertysheet_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_qsettings.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_qsettings_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_stackedbox.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_stackedbox_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_tabwidget.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_tabwidget_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_taskmenu.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_taskmenu_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_toolbar.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_toolbar_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_toolbox.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_toolbox_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_utils.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_utils_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_widget.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_widget_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_widgetbox.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_widgetbox_p.h create mode 100644 src/designer/src/lib/shared/qdesigner_widgetitem.cpp create mode 100644 src/designer/src/lib/shared/qdesigner_widgetitem_p.h create mode 100644 src/designer/src/lib/shared/qlayout_widget.cpp create mode 100644 src/designer/src/lib/shared/qlayout_widget_p.h create mode 100644 src/designer/src/lib/shared/qscripthighlighter.cpp create mode 100644 src/designer/src/lib/shared/qscripthighlighter_p.h create mode 100644 src/designer/src/lib/shared/qsimpleresource.cpp create mode 100644 src/designer/src/lib/shared/qsimpleresource_p.h create mode 100644 src/designer/src/lib/shared/qtresourceeditordialog.cpp create mode 100644 src/designer/src/lib/shared/qtresourceeditordialog.ui create mode 100644 src/designer/src/lib/shared/qtresourceeditordialog_p.h create mode 100644 src/designer/src/lib/shared/qtresourcemodel.cpp create mode 100644 src/designer/src/lib/shared/qtresourcemodel_p.h create mode 100644 src/designer/src/lib/shared/qtresourceview.cpp create mode 100644 src/designer/src/lib/shared/qtresourceview_p.h create mode 100644 src/designer/src/lib/shared/richtexteditor.cpp create mode 100644 src/designer/src/lib/shared/richtexteditor_p.h create mode 100644 src/designer/src/lib/shared/scriptcommand.cpp create mode 100644 src/designer/src/lib/shared/scriptcommand_p.h create mode 100644 src/designer/src/lib/shared/scriptdialog.cpp create mode 100644 src/designer/src/lib/shared/scriptdialog_p.h create mode 100644 src/designer/src/lib/shared/scripterrordialog.cpp create mode 100644 src/designer/src/lib/shared/scripterrordialog_p.h create mode 100644 src/designer/src/lib/shared/selectsignaldialog.ui create mode 100644 src/designer/src/lib/shared/shared.pri create mode 100644 src/designer/src/lib/shared/shared.qrc create mode 100644 src/designer/src/lib/shared/shared_enums_p.h create mode 100644 src/designer/src/lib/shared/shared_global_p.h create mode 100644 src/designer/src/lib/shared/shared_settings.cpp create mode 100644 src/designer/src/lib/shared/shared_settings_p.h create mode 100644 src/designer/src/lib/shared/sheet_delegate.cpp create mode 100644 src/designer/src/lib/shared/sheet_delegate_p.h create mode 100644 src/designer/src/lib/shared/signalslotdialog.cpp create mode 100644 src/designer/src/lib/shared/signalslotdialog.ui create mode 100644 src/designer/src/lib/shared/signalslotdialog_p.h create mode 100644 src/designer/src/lib/shared/spacer_widget.cpp create mode 100644 src/designer/src/lib/shared/spacer_widget_p.h create mode 100644 src/designer/src/lib/shared/stylesheeteditor.cpp create mode 100644 src/designer/src/lib/shared/stylesheeteditor_p.h create mode 100644 src/designer/src/lib/shared/templates/forms/240x320/Dialog_with_Buttons_Bottom.ui create mode 100644 src/designer/src/lib/shared/templates/forms/240x320/Dialog_with_Buttons_Right.ui create mode 100644 src/designer/src/lib/shared/templates/forms/320x240/Dialog_with_Buttons_Bottom.ui create mode 100644 src/designer/src/lib/shared/templates/forms/320x240/Dialog_with_Buttons_Right.ui create mode 100644 src/designer/src/lib/shared/templates/forms/480x640/Dialog_with_Buttons_Bottom.ui create mode 100644 src/designer/src/lib/shared/templates/forms/480x640/Dialog_with_Buttons_Right.ui create mode 100644 src/designer/src/lib/shared/templates/forms/640x480/Dialog_with_Buttons_Bottom.ui create mode 100644 src/designer/src/lib/shared/templates/forms/640x480/Dialog_with_Buttons_Right.ui create mode 100644 src/designer/src/lib/shared/templates/forms/Dialog_with_Buttons_Bottom.ui create mode 100644 src/designer/src/lib/shared/templates/forms/Dialog_with_Buttons_Right.ui create mode 100644 src/designer/src/lib/shared/templates/forms/Dialog_without_Buttons.ui create mode 100644 src/designer/src/lib/shared/templates/forms/Main_Window.ui create mode 100644 src/designer/src/lib/shared/templates/forms/Widget.ui create mode 100644 src/designer/src/lib/shared/textpropertyeditor.cpp create mode 100644 src/designer/src/lib/shared/textpropertyeditor_p.h create mode 100644 src/designer/src/lib/shared/widgetdatabase.cpp create mode 100644 src/designer/src/lib/shared/widgetdatabase_p.h create mode 100644 src/designer/src/lib/shared/widgetfactory.cpp create mode 100644 src/designer/src/lib/shared/widgetfactory_p.h create mode 100644 src/designer/src/lib/shared/zoomwidget.cpp create mode 100644 src/designer/src/lib/shared/zoomwidget_p.h create mode 100644 src/designer/src/plugins/activeqt/activeqt.pro create mode 100644 src/designer/src/plugins/activeqt/qaxwidgetextrainfo.cpp create mode 100644 src/designer/src/plugins/activeqt/qaxwidgetextrainfo.h create mode 100644 src/designer/src/plugins/activeqt/qaxwidgetplugin.cpp create mode 100644 src/designer/src/plugins/activeqt/qaxwidgetplugin.h create mode 100644 src/designer/src/plugins/activeqt/qaxwidgetpropertysheet.cpp create mode 100644 src/designer/src/plugins/activeqt/qaxwidgetpropertysheet.h create mode 100644 src/designer/src/plugins/activeqt/qaxwidgettaskmenu.cpp create mode 100644 src/designer/src/plugins/activeqt/qaxwidgettaskmenu.h create mode 100644 src/designer/src/plugins/activeqt/qdesigneraxwidget.cpp create mode 100644 src/designer/src/plugins/activeqt/qdesigneraxwidget.h create mode 100644 src/designer/src/plugins/phononwidgets/images/seekslider.png create mode 100644 src/designer/src/plugins/phononwidgets/images/videoplayer.png create mode 100644 src/designer/src/plugins/phononwidgets/images/videowidget.png create mode 100644 src/designer/src/plugins/phononwidgets/images/volumeslider.png create mode 100644 src/designer/src/plugins/phononwidgets/phononcollection.cpp create mode 100644 src/designer/src/plugins/phononwidgets/phononwidgets.pro create mode 100644 src/designer/src/plugins/phononwidgets/phononwidgets.qrc create mode 100644 src/designer/src/plugins/phononwidgets/seeksliderplugin.cpp create mode 100644 src/designer/src/plugins/phononwidgets/seeksliderplugin.h create mode 100644 src/designer/src/plugins/phononwidgets/videoplayerplugin.cpp create mode 100644 src/designer/src/plugins/phononwidgets/videoplayerplugin.h create mode 100644 src/designer/src/plugins/phononwidgets/videoplayertaskmenu.cpp create mode 100644 src/designer/src/plugins/phononwidgets/videoplayertaskmenu.h create mode 100644 src/designer/src/plugins/phononwidgets/volumesliderplugin.cpp create mode 100644 src/designer/src/plugins/phononwidgets/volumesliderplugin.h create mode 100644 src/designer/src/plugins/plugins.pri create mode 100644 src/designer/src/plugins/plugins.pro create mode 100644 src/designer/src/plugins/qdeclarativeview/qdeclarativeview.pro create mode 100644 src/designer/src/plugins/qdeclarativeview/qdeclarativeview_plugin.cpp create mode 100644 src/designer/src/plugins/qdeclarativeview/qdeclarativeview_plugin.h create mode 100644 src/designer/src/plugins/qwebview/images/qwebview.png create mode 100644 src/designer/src/plugins/qwebview/qwebview.pro create mode 100644 src/designer/src/plugins/qwebview/qwebview_plugin.cpp create mode 100644 src/designer/src/plugins/qwebview/qwebview_plugin.h create mode 100644 src/designer/src/plugins/qwebview/qwebview_plugin.qrc create mode 100644 src/designer/src/plugins/tools/view3d/view3d.cpp create mode 100644 src/designer/src/plugins/tools/view3d/view3d.h create mode 100644 src/designer/src/plugins/tools/view3d/view3d.pro create mode 100644 src/designer/src/plugins/tools/view3d/view3d_global.h create mode 100644 src/designer/src/plugins/tools/view3d/view3d_plugin.cpp create mode 100644 src/designer/src/plugins/tools/view3d/view3d_plugin.h create mode 100644 src/designer/src/plugins/tools/view3d/view3d_tool.cpp create mode 100644 src/designer/src/plugins/tools/view3d/view3d_tool.h create mode 100644 src/designer/src/plugins/widgets/q3iconview/q3iconview_extrainfo.cpp create mode 100644 src/designer/src/plugins/widgets/q3iconview/q3iconview_extrainfo.h create mode 100644 src/designer/src/plugins/widgets/q3iconview/q3iconview_plugin.cpp create mode 100644 src/designer/src/plugins/widgets/q3iconview/q3iconview_plugin.h create mode 100644 src/designer/src/plugins/widgets/q3listbox/q3listbox_extrainfo.cpp create mode 100644 src/designer/src/plugins/widgets/q3listbox/q3listbox_extrainfo.h create mode 100644 src/designer/src/plugins/widgets/q3listbox/q3listbox_plugin.cpp create mode 100644 src/designer/src/plugins/widgets/q3listbox/q3listbox_plugin.h create mode 100644 src/designer/src/plugins/widgets/q3listview/q3listview_extrainfo.cpp create mode 100644 src/designer/src/plugins/widgets/q3listview/q3listview_extrainfo.h create mode 100644 src/designer/src/plugins/widgets/q3listview/q3listview_plugin.cpp create mode 100644 src/designer/src/plugins/widgets/q3listview/q3listview_plugin.h create mode 100644 src/designer/src/plugins/widgets/q3mainwindow/q3mainwindow_container.cpp create mode 100644 src/designer/src/plugins/widgets/q3mainwindow/q3mainwindow_container.h create mode 100644 src/designer/src/plugins/widgets/q3mainwindow/q3mainwindow_plugin.cpp create mode 100644 src/designer/src/plugins/widgets/q3mainwindow/q3mainwindow_plugin.h create mode 100644 src/designer/src/plugins/widgets/q3table/q3table_extrainfo.cpp create mode 100644 src/designer/src/plugins/widgets/q3table/q3table_extrainfo.h create mode 100644 src/designer/src/plugins/widgets/q3table/q3table_plugin.cpp create mode 100644 src/designer/src/plugins/widgets/q3table/q3table_plugin.h create mode 100644 src/designer/src/plugins/widgets/q3textedit/q3textedit_extrainfo.cpp create mode 100644 src/designer/src/plugins/widgets/q3textedit/q3textedit_extrainfo.h create mode 100644 src/designer/src/plugins/widgets/q3textedit/q3textedit_plugin.cpp create mode 100644 src/designer/src/plugins/widgets/q3textedit/q3textedit_plugin.h create mode 100644 src/designer/src/plugins/widgets/q3toolbar/q3toolbar_extrainfo.cpp create mode 100644 src/designer/src/plugins/widgets/q3toolbar/q3toolbar_extrainfo.h create mode 100644 src/designer/src/plugins/widgets/q3toolbar/q3toolbar_plugin.cpp create mode 100644 src/designer/src/plugins/widgets/q3toolbar/q3toolbar_plugin.h create mode 100644 src/designer/src/plugins/widgets/q3widgets/q3widget_plugins.cpp create mode 100644 src/designer/src/plugins/widgets/q3widgets/q3widget_plugins.h create mode 100644 src/designer/src/plugins/widgets/q3widgetstack/q3widgetstack_container.cpp create mode 100644 src/designer/src/plugins/widgets/q3widgetstack/q3widgetstack_container.h create mode 100644 src/designer/src/plugins/widgets/q3widgetstack/q3widgetstack_plugin.cpp create mode 100644 src/designer/src/plugins/widgets/q3widgetstack/q3widgetstack_plugin.h create mode 100644 src/designer/src/plugins/widgets/q3widgetstack/qdesigner_q3widgetstack.cpp create mode 100644 src/designer/src/plugins/widgets/q3widgetstack/qdesigner_q3widgetstack_p.h create mode 100644 src/designer/src/plugins/widgets/q3wizard/q3wizard_container.cpp create mode 100644 src/designer/src/plugins/widgets/q3wizard/q3wizard_container.h create mode 100644 src/designer/src/plugins/widgets/q3wizard/q3wizard_plugin.cpp create mode 100644 src/designer/src/plugins/widgets/q3wizard/q3wizard_plugin.h create mode 100644 src/designer/src/plugins/widgets/qt3supportwidgets.cpp create mode 100644 src/designer/src/plugins/widgets/widgets.pro create mode 100644 src/designer/src/sharedcomponents.pri create mode 100644 src/designer/src/src.pro create mode 100644 src/doxygen/config/footer.html create mode 100644 src/doxygen/config/header.html create mode 100644 src/doxygen/config/phonon.css create mode 100644 src/doxygen/config/phonon.doxyfile create mode 100644 src/kmap2qmap/kmap2qmap.pro create mode 100644 src/kmap2qmap/main.cpp create mode 100644 src/linguist/lconvert/lconvert.pro create mode 100644 src/linguist/lconvert/main.cpp create mode 100644 src/linguist/linguist.pro create mode 100644 src/linguist/linguist/Info_mac.plist create mode 100644 src/linguist/linguist/batchtranslation.ui create mode 100644 src/linguist/linguist/batchtranslationdialog.cpp create mode 100644 src/linguist/linguist/batchtranslationdialog.h create mode 100644 src/linguist/linguist/errorsview.cpp create mode 100644 src/linguist/linguist/errorsview.h create mode 100644 src/linguist/linguist/finddialog.cpp create mode 100644 src/linguist/linguist/finddialog.h create mode 100644 src/linguist/linguist/finddialog.ui create mode 100644 src/linguist/linguist/formpreviewview.cpp create mode 100644 src/linguist/linguist/formpreviewview.h create mode 100644 src/linguist/linguist/globals.cpp create mode 100644 src/linguist/linguist/globals.h create mode 100644 src/linguist/linguist/images/appicon.png create mode 100644 src/linguist/linguist/images/down.png create mode 100644 src/linguist/linguist/images/editdelete.png create mode 100644 src/linguist/linguist/images/icons/linguist-128-32.png create mode 100644 src/linguist/linguist/images/icons/linguist-128-8.png create mode 100644 src/linguist/linguist/images/icons/linguist-16-32.png create mode 100644 src/linguist/linguist/images/icons/linguist-16-8.png create mode 100644 src/linguist/linguist/images/icons/linguist-32-32.png create mode 100644 src/linguist/linguist/images/icons/linguist-32-8.png create mode 100644 src/linguist/linguist/images/icons/linguist-48-32.png create mode 100644 src/linguist/linguist/images/icons/linguist-48-8.png create mode 100644 src/linguist/linguist/images/icons/linguist-64-32.png create mode 100644 src/linguist/linguist/images/icons/linguist-64-8.png create mode 100644 src/linguist/linguist/images/mac/accelerator.png create mode 100644 src/linguist/linguist/images/mac/book.png create mode 100644 src/linguist/linguist/images/mac/doneandnext.png create mode 100644 src/linguist/linguist/images/mac/editcopy.png create mode 100644 src/linguist/linguist/images/mac/editcut.png create mode 100644 src/linguist/linguist/images/mac/editpaste.png create mode 100644 src/linguist/linguist/images/mac/filenew.png create mode 100644 src/linguist/linguist/images/mac/fileopen.png create mode 100644 src/linguist/linguist/images/mac/fileprint.png create mode 100644 src/linguist/linguist/images/mac/filesave.png create mode 100644 src/linguist/linguist/images/mac/next.png create mode 100644 src/linguist/linguist/images/mac/nextunfinished.png create mode 100644 src/linguist/linguist/images/mac/phrase.png create mode 100644 src/linguist/linguist/images/mac/prev.png create mode 100644 src/linguist/linguist/images/mac/prevunfinished.png create mode 100644 src/linguist/linguist/images/mac/print.png create mode 100644 src/linguist/linguist/images/mac/punctuation.png create mode 100644 src/linguist/linguist/images/mac/redo.png create mode 100644 src/linguist/linguist/images/mac/searchfind.png create mode 100644 src/linguist/linguist/images/mac/undo.png create mode 100644 src/linguist/linguist/images/mac/validateplacemarkers.png create mode 100644 src/linguist/linguist/images/mac/whatsthis.png create mode 100644 src/linguist/linguist/images/minus.png create mode 100644 src/linguist/linguist/images/plus.png create mode 100644 src/linguist/linguist/images/s_check_danger.png create mode 100644 src/linguist/linguist/images/s_check_empty.png create mode 100644 src/linguist/linguist/images/s_check_obsolete.png create mode 100644 src/linguist/linguist/images/s_check_off.png create mode 100644 src/linguist/linguist/images/s_check_on.png create mode 100644 src/linguist/linguist/images/s_check_warning.png create mode 100644 src/linguist/linguist/images/splash.png create mode 100644 src/linguist/linguist/images/up.png create mode 100644 src/linguist/linguist/images/win/accelerator.png create mode 100644 src/linguist/linguist/images/win/book.png create mode 100644 src/linguist/linguist/images/win/doneandnext.png create mode 100644 src/linguist/linguist/images/win/editcopy.png create mode 100644 src/linguist/linguist/images/win/editcut.png create mode 100644 src/linguist/linguist/images/win/editpaste.png create mode 100644 src/linguist/linguist/images/win/filenew.png create mode 100644 src/linguist/linguist/images/win/fileopen.png create mode 100644 src/linguist/linguist/images/win/filesave.png create mode 100644 src/linguist/linguist/images/win/next.png create mode 100644 src/linguist/linguist/images/win/nextunfinished.png create mode 100644 src/linguist/linguist/images/win/phrase.png create mode 100644 src/linguist/linguist/images/win/prev.png create mode 100644 src/linguist/linguist/images/win/prevunfinished.png create mode 100644 src/linguist/linguist/images/win/print.png create mode 100644 src/linguist/linguist/images/win/punctuation.png create mode 100644 src/linguist/linguist/images/win/redo.png create mode 100644 src/linguist/linguist/images/win/searchfind.png create mode 100644 src/linguist/linguist/images/win/undo.png create mode 100644 src/linguist/linguist/images/win/validateplacemarkers.png create mode 100644 src/linguist/linguist/images/win/whatsthis.png create mode 100644 src/linguist/linguist/linguist.icns create mode 100644 src/linguist/linguist/linguist.ico create mode 100644 src/linguist/linguist/linguist.pro create mode 100644 src/linguist/linguist/linguist.qrc create mode 100644 src/linguist/linguist/linguist.rc create mode 100644 src/linguist/linguist/main.cpp create mode 100644 src/linguist/linguist/mainwindow.cpp create mode 100644 src/linguist/linguist/mainwindow.h create mode 100644 src/linguist/linguist/mainwindow.ui create mode 100644 src/linguist/linguist/messageeditor.cpp create mode 100644 src/linguist/linguist/messageeditor.h create mode 100644 src/linguist/linguist/messageeditorwidgets.cpp create mode 100644 src/linguist/linguist/messageeditorwidgets.h create mode 100644 src/linguist/linguist/messagehighlighter.cpp create mode 100644 src/linguist/linguist/messagehighlighter.h create mode 100644 src/linguist/linguist/messagemodel.cpp create mode 100644 src/linguist/linguist/messagemodel.h create mode 100644 src/linguist/linguist/phrase.cpp create mode 100644 src/linguist/linguist/phrase.h create mode 100644 src/linguist/linguist/phrasebookbox.cpp create mode 100644 src/linguist/linguist/phrasebookbox.h create mode 100644 src/linguist/linguist/phrasebookbox.ui create mode 100644 src/linguist/linguist/phrasemodel.cpp create mode 100644 src/linguist/linguist/phrasemodel.h create mode 100644 src/linguist/linguist/phraseview.cpp create mode 100644 src/linguist/linguist/phraseview.h create mode 100644 src/linguist/linguist/printout.cpp create mode 100644 src/linguist/linguist/printout.h create mode 100644 src/linguist/linguist/recentfiles.cpp create mode 100644 src/linguist/linguist/recentfiles.h create mode 100644 src/linguist/linguist/sourcecodeview.cpp create mode 100644 src/linguist/linguist/sourcecodeview.h create mode 100644 src/linguist/linguist/statistics.cpp create mode 100644 src/linguist/linguist/statistics.h create mode 100644 src/linguist/linguist/statistics.ui create mode 100644 src/linguist/linguist/translatedialog.cpp create mode 100644 src/linguist/linguist/translatedialog.h create mode 100644 src/linguist/linguist/translatedialog.ui create mode 100644 src/linguist/linguist/translationsettings.ui create mode 100644 src/linguist/linguist/translationsettingsdialog.cpp create mode 100644 src/linguist/linguist/translationsettingsdialog.h create mode 100644 src/linguist/lrelease/lrelease.1 create mode 100644 src/linguist/lrelease/lrelease.pro create mode 100644 src/linguist/lrelease/main.cpp create mode 100644 src/linguist/lupdate/cpp.cpp create mode 100644 src/linguist/lupdate/java.cpp create mode 100644 src/linguist/lupdate/lupdate.1 create mode 100644 src/linguist/lupdate/lupdate.exe.manifest create mode 100644 src/linguist/lupdate/lupdate.h create mode 100644 src/linguist/lupdate/lupdate.pro create mode 100644 src/linguist/lupdate/main.cpp create mode 100644 src/linguist/lupdate/merge.cpp create mode 100644 src/linguist/lupdate/qdeclarative.cpp create mode 100644 src/linguist/lupdate/qscript.cpp create mode 100644 src/linguist/lupdate/qscript.g create mode 100644 src/linguist/lupdate/ui.cpp create mode 100644 src/linguist/lupdate/winmanifest.rc create mode 100644 src/linguist/phrasebooks/danish.qph create mode 100644 src/linguist/phrasebooks/dutch.qph create mode 100644 src/linguist/phrasebooks/finnish.qph create mode 100644 src/linguist/phrasebooks/french.qph create mode 100644 src/linguist/phrasebooks/german.qph create mode 100644 src/linguist/phrasebooks/hungarian.qph create mode 100644 src/linguist/phrasebooks/italian.qph create mode 100644 src/linguist/phrasebooks/japanese.qph create mode 100644 src/linguist/phrasebooks/norwegian.qph create mode 100644 src/linguist/phrasebooks/polish.qph create mode 100644 src/linguist/phrasebooks/russian.qph create mode 100644 src/linguist/phrasebooks/spanish.qph create mode 100644 src/linguist/phrasebooks/swedish.qph create mode 100644 src/linguist/qdoc.conf create mode 100644 src/linguist/shared/abstractproitemvisitor.h create mode 100644 src/linguist/shared/formats.pri create mode 100644 src/linguist/shared/numerus.cpp create mode 100644 src/linguist/shared/po.cpp create mode 100644 src/linguist/shared/profileevaluator.cpp create mode 100644 src/linguist/shared/profileevaluator.h create mode 100644 src/linguist/shared/proitems.cpp create mode 100644 src/linguist/shared/proitems.h create mode 100644 src/linguist/shared/proparser.pri create mode 100644 src/linguist/shared/proparserutils.h create mode 100644 src/linguist/shared/qm.cpp create mode 100644 src/linguist/shared/qph.cpp create mode 100644 src/linguist/shared/simtexth.cpp create mode 100644 src/linguist/shared/simtexth.h create mode 100644 src/linguist/shared/translator.cpp create mode 100644 src/linguist/shared/translator.h create mode 100644 src/linguist/shared/translatormessage.cpp create mode 100644 src/linguist/shared/translatormessage.h create mode 100644 src/linguist/shared/ts.cpp create mode 100644 src/linguist/shared/ts.dtd create mode 100644 src/linguist/shared/xliff.cpp create mode 100644 src/linguist/tests/data/main.cpp create mode 100644 src/linguist/tests/data/test.pro create mode 100644 src/linguist/tests/tests.pro create mode 100644 src/linguist/tests/tst_linguist.cpp create mode 100644 src/linguist/tests/tst_linguist.h create mode 100644 src/linguist/tests/tst_lupdate.cpp create mode 100644 src/linguist/tests/tst_simtexth.cpp create mode 100644 src/macdeployqt/macchangeqt/macchangeqt.pro create mode 100644 src/macdeployqt/macchangeqt/main.cpp create mode 100644 src/macdeployqt/macdeployqt.pro create mode 100644 src/macdeployqt/macdeployqt/macdeployqt.pro create mode 100644 src/macdeployqt/macdeployqt/main.cpp create mode 100644 src/macdeployqt/shared/shared.cpp create mode 100644 src/macdeployqt/shared/shared.h create mode 100644 src/macdeployqt/tests/deployment_mac.pro create mode 100644 src/macdeployqt/tests/tst_deployment_mac.cpp create mode 100644 src/makeqpf/Blocks.txt create mode 100644 src/makeqpf/README create mode 100644 src/makeqpf/main.cpp create mode 100644 src/makeqpf/mainwindow.cpp create mode 100644 src/makeqpf/mainwindow.h create mode 100644 src/makeqpf/mainwindow.ui create mode 100644 src/makeqpf/makeqpf.pro create mode 100644 src/makeqpf/makeqpf.qrc create mode 100644 src/makeqpf/qpf2.cpp create mode 100644 src/makeqpf/qpf2.h create mode 100644 src/pixeltool/Info_mac.plist create mode 100644 src/pixeltool/main.cpp create mode 100644 src/pixeltool/pixeltool.pro create mode 100644 src/pixeltool/qpixeltool.cpp create mode 100644 src/pixeltool/qpixeltool.h create mode 100644 src/qconfig/feature.cpp create mode 100644 src/qconfig/feature.h create mode 100644 src/qconfig/featuretreemodel.cpp create mode 100644 src/qconfig/featuretreemodel.h create mode 100644 src/qconfig/graphics.h create mode 100644 src/qconfig/main.cpp create mode 100644 src/qconfig/qconfig.pro create mode 100644 src/qdbus/qdbus.pro create mode 100644 src/qdbus/qdbus/qdbus.cpp create mode 100644 src/qdbus/qdbus/qdbus.pro create mode 100644 src/qdbus/qdbuscpp2xml/qdbuscpp2xml.cpp create mode 100644 src/qdbus/qdbuscpp2xml/qdbuscpp2xml.pro create mode 100644 src/qdbus/qdbusviewer/Info_mac.plist create mode 100644 src/qdbus/qdbusviewer/images/qdbusviewer-128.png create mode 100644 src/qdbus/qdbusviewer/images/qdbusviewer.icns create mode 100644 src/qdbus/qdbusviewer/images/qdbusviewer.ico create mode 100644 src/qdbus/qdbusviewer/images/qdbusviewer.png create mode 100644 src/qdbus/qdbusviewer/main.cpp create mode 100644 src/qdbus/qdbusviewer/propertydialog.cpp create mode 100644 src/qdbus/qdbusviewer/propertydialog.h create mode 100644 src/qdbus/qdbusviewer/qdbusmodel.cpp create mode 100644 src/qdbus/qdbusviewer/qdbusmodel.h create mode 100644 src/qdbus/qdbusviewer/qdbusviewer.cpp create mode 100644 src/qdbus/qdbusviewer/qdbusviewer.h create mode 100644 src/qdbus/qdbusviewer/qdbusviewer.pro create mode 100644 src/qdbus/qdbusviewer/qdbusviewer.qrc create mode 100644 src/qdbus/qdbusviewer/qdbusviewer.rc create mode 100644 src/qdbus/qdbusxml2cpp/qdbusxml2cpp.cpp create mode 100644 src/qdbus/qdbusxml2cpp/qdbusxml2cpp.pro create mode 100644 src/qev/README create mode 100644 src/qev/qev.cpp create mode 100644 src/qev/qev.pro create mode 100644 src/qmeegographicssystemhelper/qmeegofencesync.cpp create mode 100644 src/qmeegographicssystemhelper/qmeegofencesync.h create mode 100644 src/qmeegographicssystemhelper/qmeegofencesync_p.h create mode 100644 src/qmeegographicssystemhelper/qmeegographicssystemhelper.cpp create mode 100644 src/qmeegographicssystemhelper/qmeegographicssystemhelper.h create mode 100644 src/qmeegographicssystemhelper/qmeegographicssystemhelper.pro create mode 100644 src/qmeegographicssystemhelper/qmeegolivepixmap.cpp create mode 100644 src/qmeegographicssystemhelper/qmeegolivepixmap.h create mode 100644 src/qmeegographicssystemhelper/qmeegolivepixmap_p.h create mode 100644 src/qmeegographicssystemhelper/qmeegooverlaywidget.cpp create mode 100644 src/qmeegographicssystemhelper/qmeegooverlaywidget.h create mode 100644 src/qmeegographicssystemhelper/qmeegoruntime.cpp create mode 100644 src/qmeegographicssystemhelper/qmeegoruntime.h create mode 100644 src/qmeegographicssystemhelper/qmeegoswitchevent.cpp create mode 100644 src/qmeegographicssystemhelper/qmeegoswitchevent.h create mode 100644 src/qtconcurrent/codegenerator/codegenerator.pri create mode 100644 src/qtconcurrent/codegenerator/example/example.pro create mode 100644 src/qtconcurrent/codegenerator/example/main.cpp create mode 100644 src/qtconcurrent/codegenerator/src/codegenerator.cpp create mode 100644 src/qtconcurrent/codegenerator/src/codegenerator.h create mode 100644 src/qtconcurrent/generaterun/main.cpp create mode 100644 src/qtconcurrent/generaterun/run.pro create mode 100644 src/qtconfig/colorbutton.cpp create mode 100644 src/qtconfig/colorbutton.h create mode 100644 src/qtconfig/images/appicon.png create mode 100644 src/qtconfig/main.cpp create mode 100644 src/qtconfig/mainwindow.cpp create mode 100644 src/qtconfig/mainwindow.h create mode 100644 src/qtconfig/mainwindow.ui create mode 100644 src/qtconfig/paletteeditoradvanced.cpp create mode 100644 src/qtconfig/paletteeditoradvanced.h create mode 100644 src/qtconfig/paletteeditoradvanced.ui create mode 100644 src/qtconfig/previewframe.cpp create mode 100644 src/qtconfig/previewframe.h create mode 100644 src/qtconfig/previewwidget.cpp create mode 100644 src/qtconfig/previewwidget.h create mode 100644 src/qtconfig/previewwidget.ui create mode 100644 src/qtconfig/qtconfig.pro create mode 100644 src/qtconfig/qtconfig.qrc create mode 100644 src/qtestlib/qtestlib.pro create mode 100644 src/qtestlib/updater/main.cpp create mode 100644 src/qtestlib/updater/updater.pro create mode 100644 src/qtestlib/wince/cetcpsync/cetcpsync.pro create mode 100644 src/qtestlib/wince/cetcpsync/main.cpp create mode 100644 src/qtestlib/wince/cetcpsync/qtcesterconnection.cpp create mode 100644 src/qtestlib/wince/cetcpsync/qtcesterconnection.h create mode 100644 src/qtestlib/wince/cetcpsync/remoteconnection.cpp create mode 100644 src/qtestlib/wince/cetcpsync/remoteconnection.h create mode 100644 src/qtestlib/wince/cetcpsyncserver/cetcpsyncserver.pro create mode 100644 src/qtestlib/wince/cetcpsyncserver/commands.cpp create mode 100644 src/qtestlib/wince/cetcpsyncserver/commands.h create mode 100644 src/qtestlib/wince/cetcpsyncserver/connectionmanager.cpp create mode 100644 src/qtestlib/wince/cetcpsyncserver/connectionmanager.h create mode 100644 src/qtestlib/wince/cetcpsyncserver/main.cpp create mode 100644 src/qtestlib/wince/cetcpsyncserver/transfer_global.h create mode 100644 src/qtestlib/wince/cetest/activesyncconnection.cpp create mode 100644 src/qtestlib/wince/cetest/activesyncconnection.h create mode 100644 src/qtestlib/wince/cetest/bootstrapped.pri create mode 100644 src/qtestlib/wince/cetest/cetcpsyncconnection.cpp create mode 100644 src/qtestlib/wince/cetest/cetcpsyncconnection.h create mode 100644 src/qtestlib/wince/cetest/cetest.pro create mode 100644 src/qtestlib/wince/cetest/deployment.cpp create mode 100644 src/qtestlib/wince/cetest/deployment.h create mode 100644 src/qtestlib/wince/cetest/main.cpp create mode 100644 src/qtestlib/wince/cetest/qmake_include.pri create mode 100644 src/qtestlib/wince/cetest/remoteconnection.cpp create mode 100644 src/qtestlib/wince/cetest/remoteconnection.h create mode 100644 src/qtestlib/wince/remotelib/commands.cpp create mode 100644 src/qtestlib/wince/remotelib/commands.h create mode 100644 src/qtestlib/wince/remotelib/remotelib.pro create mode 100644 src/qtestlib/wince/wince.pro create mode 100644 src/qttracereplay/main.cpp create mode 100644 src/qttracereplay/qttracereplay.pro create mode 100644 src/qvfb/README create mode 100644 src/qvfb/config.ui create mode 100644 src/qvfb/gammaview.h create mode 100644 src/qvfb/images/logo-nt.png create mode 100644 src/qvfb/images/logo.png create mode 100644 src/qvfb/main.cpp create mode 100644 src/qvfb/qanimationwriter.cpp create mode 100644 src/qvfb/qanimationwriter.h create mode 100644 src/qvfb/qtopiakeysym.h create mode 100644 src/qvfb/qvfb.cpp create mode 100644 src/qvfb/qvfb.h create mode 100644 src/qvfb/qvfb.pro create mode 100644 src/qvfb/qvfb.qrc create mode 100644 src/qvfb/qvfbmmap.cpp create mode 100644 src/qvfb/qvfbmmap.h create mode 100644 src/qvfb/qvfbprotocol.cpp create mode 100644 src/qvfb/qvfbprotocol.h create mode 100644 src/qvfb/qvfbratedlg.cpp create mode 100644 src/qvfb/qvfbratedlg.h create mode 100644 src/qvfb/qvfbshmem.cpp create mode 100644 src/qvfb/qvfbshmem.h create mode 100644 src/qvfb/qvfbview.cpp create mode 100644 src/qvfb/qvfbview.h create mode 100644 src/qvfb/qvfbx11view.cpp create mode 100644 src/qvfb/qvfbx11view.h create mode 100644 src/qvfb/x11keyfaker.cpp create mode 100644 src/qvfb/x11keyfaker.h create mode 100644 src/runonphone/main.cpp create mode 100644 src/runonphone/ossignalconverter.cpp create mode 100644 src/runonphone/ossignalconverter.h create mode 100644 src/runonphone/ossignalconverter_p.h create mode 100644 src/runonphone/runonphone.pro create mode 100644 src/runonphone/serenum.h create mode 100644 src/runonphone/serenum_stub.cpp create mode 100644 src/runonphone/serenum_unix.cpp create mode 100644 src/runonphone/serenum_win.cpp create mode 100644 src/runonphone/symbianutils/bluetoothlistener.cpp create mode 100644 src/runonphone/symbianutils/bluetoothlistener.h create mode 100644 src/runonphone/symbianutils/bluetoothlistener_gui.cpp create mode 100644 src/runonphone/symbianutils/bluetoothlistener_gui.h create mode 100644 src/runonphone/symbianutils/callback.h create mode 100644 src/runonphone/symbianutils/communicationstarter.cpp create mode 100644 src/runonphone/symbianutils/communicationstarter.h create mode 100644 src/runonphone/symbianutils/json.cpp create mode 100644 src/runonphone/symbianutils/json.h create mode 100644 src/runonphone/symbianutils/launcher.cpp create mode 100644 src/runonphone/symbianutils/launcher.h create mode 100644 src/runonphone/symbianutils/symbiandevicemanager.cpp create mode 100644 src/runonphone/symbianutils/symbiandevicemanager.h create mode 100644 src/runonphone/symbianutils/symbianutils.pri create mode 100644 src/runonphone/symbianutils/symbianutils_global.h create mode 100644 src/runonphone/symbianutils/tcftrkdevice.cpp create mode 100644 src/runonphone/symbianutils/tcftrkdevice.h create mode 100644 src/runonphone/symbianutils/tcftrkmessage.cpp create mode 100644 src/runonphone/symbianutils/tcftrkmessage.h create mode 100644 src/runonphone/symbianutils/trkdevice.cpp create mode 100644 src/runonphone/symbianutils/trkdevice.h create mode 100644 src/runonphone/symbianutils/trkutils.cpp create mode 100644 src/runonphone/symbianutils/trkutils.h create mode 100644 src/runonphone/symbianutils/trkutils_p.h create mode 100644 src/runonphone/trksignalhandler.cpp create mode 100644 src/runonphone/trksignalhandler.h create mode 100644 src/shared/deviceskin/deviceskin.cpp create mode 100644 src/shared/deviceskin/deviceskin.h create mode 100644 src/shared/deviceskin/deviceskin.pri create mode 100644 src/shared/deviceskin/skins/ClamshellPhone.qrc create mode 100644 src/shared/deviceskin/skins/ClamshellPhone.skin/ClamshellPhone.skin create mode 100644 src/shared/deviceskin/skins/ClamshellPhone.skin/ClamshellPhone1-5-closed.png create mode 100644 src/shared/deviceskin/skins/ClamshellPhone.skin/ClamshellPhone1-5-pressed.png create mode 100644 src/shared/deviceskin/skins/ClamshellPhone.skin/ClamshellPhone1-5.png create mode 100644 src/shared/deviceskin/skins/ClamshellPhone.skin/defaultbuttons.conf create mode 100644 src/shared/deviceskin/skins/PortableMedia.qrc create mode 100644 src/shared/deviceskin/skins/PortableMedia.skin/PortableMedia.skin create mode 100644 src/shared/deviceskin/skins/PortableMedia.skin/defaultbuttons.conf create mode 100644 src/shared/deviceskin/skins/PortableMedia.skin/portablemedia-pressed.png create mode 100644 src/shared/deviceskin/skins/PortableMedia.skin/portablemedia.png create mode 100644 src/shared/deviceskin/skins/PortableMedia.skin/portablemedia.xcf create mode 100644 src/shared/deviceskin/skins/S60-QVGA-Candybar.qrc create mode 100644 src/shared/deviceskin/skins/S60-QVGA-Candybar.skin/S60-QVGA-Candybar-down.png create mode 100644 src/shared/deviceskin/skins/S60-QVGA-Candybar.skin/S60-QVGA-Candybar.png create mode 100644 src/shared/deviceskin/skins/S60-QVGA-Candybar.skin/S60-QVGA-Candybar.skin create mode 100644 src/shared/deviceskin/skins/S60-QVGA-Candybar.skin/defaultbuttons.conf create mode 100644 src/shared/deviceskin/skins/S60-nHD-Touchscreen.qrc create mode 100644 src/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen-down.png create mode 100644 src/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen.png create mode 100644 src/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/S60-nHD-Touchscreen.skin create mode 100644 src/shared/deviceskin/skins/S60-nHD-Touchscreen.skin/defaultbuttons.conf create mode 100644 src/shared/deviceskin/skins/SmartPhone.qrc create mode 100644 src/shared/deviceskin/skins/SmartPhone.skin/SmartPhone-pressed.png create mode 100644 src/shared/deviceskin/skins/SmartPhone.skin/SmartPhone.png create mode 100644 src/shared/deviceskin/skins/SmartPhone.skin/SmartPhone.skin create mode 100644 src/shared/deviceskin/skins/SmartPhone.skin/defaultbuttons.conf create mode 100644 src/shared/deviceskin/skins/SmartPhone2.qrc create mode 100644 src/shared/deviceskin/skins/SmartPhone2.skin/SmartPhone2-pressed.png create mode 100644 src/shared/deviceskin/skins/SmartPhone2.skin/SmartPhone2.png create mode 100644 src/shared/deviceskin/skins/SmartPhone2.skin/SmartPhone2.skin create mode 100644 src/shared/deviceskin/skins/SmartPhone2.skin/defaultbuttons.conf create mode 100644 src/shared/deviceskin/skins/SmartPhoneWithButtons.qrc create mode 100644 src/shared/deviceskin/skins/SmartPhoneWithButtons.skin/SmartPhoneWithButtons-pressed.png create mode 100644 src/shared/deviceskin/skins/SmartPhoneWithButtons.skin/SmartPhoneWithButtons.png create mode 100644 src/shared/deviceskin/skins/SmartPhoneWithButtons.skin/SmartPhoneWithButtons.skin create mode 100644 src/shared/deviceskin/skins/SmartPhoneWithButtons.skin/defaultbuttons.conf create mode 100644 src/shared/deviceskin/skins/TouchscreenPhone.qrc create mode 100644 src/shared/deviceskin/skins/TouchscreenPhone.skin/TouchscreenPhone-pressed.png create mode 100644 src/shared/deviceskin/skins/TouchscreenPhone.skin/TouchscreenPhone.png create mode 100644 src/shared/deviceskin/skins/TouchscreenPhone.skin/TouchscreenPhone.skin create mode 100644 src/shared/deviceskin/skins/TouchscreenPhone.skin/defaultbuttons.conf create mode 100644 src/shared/findwidget/abstractfindwidget.cpp create mode 100644 src/shared/findwidget/abstractfindwidget.h create mode 100644 src/shared/findwidget/findwidget.pri create mode 100644 src/shared/findwidget/findwidget.qrc create mode 100644 src/shared/findwidget/images/mac/closetab.png create mode 100644 src/shared/findwidget/images/mac/next.png create mode 100644 src/shared/findwidget/images/mac/previous.png create mode 100644 src/shared/findwidget/images/mac/searchfind.png create mode 100644 src/shared/findwidget/images/win/closetab.png create mode 100644 src/shared/findwidget/images/win/next.png create mode 100644 src/shared/findwidget/images/win/previous.png create mode 100644 src/shared/findwidget/images/win/searchfind.png create mode 100644 src/shared/findwidget/images/wrap.png create mode 100644 src/shared/findwidget/itemviewfindwidget.cpp create mode 100644 src/shared/findwidget/itemviewfindwidget.h create mode 100644 src/shared/findwidget/texteditfindwidget.cpp create mode 100644 src/shared/findwidget/texteditfindwidget.h create mode 100644 src/shared/fontpanel/fontpanel.cpp create mode 100644 src/shared/fontpanel/fontpanel.h create mode 100644 src/shared/fontpanel/fontpanel.pri create mode 100644 src/shared/qtgradienteditor/images/down.png create mode 100644 src/shared/qtgradienteditor/images/edit.png create mode 100644 src/shared/qtgradienteditor/images/editdelete.png create mode 100644 src/shared/qtgradienteditor/images/minus.png create mode 100644 src/shared/qtgradienteditor/images/plus.png create mode 100644 src/shared/qtgradienteditor/images/spreadpad.png create mode 100644 src/shared/qtgradienteditor/images/spreadreflect.png create mode 100644 src/shared/qtgradienteditor/images/spreadrepeat.png create mode 100644 src/shared/qtgradienteditor/images/typeconical.png create mode 100644 src/shared/qtgradienteditor/images/typelinear.png create mode 100644 src/shared/qtgradienteditor/images/typeradial.png create mode 100644 src/shared/qtgradienteditor/images/up.png create mode 100644 src/shared/qtgradienteditor/images/zoomin.png create mode 100644 src/shared/qtgradienteditor/images/zoomout.png create mode 100644 src/shared/qtgradienteditor/qtcolorbutton.cpp create mode 100644 src/shared/qtgradienteditor/qtcolorbutton.h create mode 100644 src/shared/qtgradienteditor/qtcolorbutton.pri create mode 100644 src/shared/qtgradienteditor/qtcolorline.cpp create mode 100644 src/shared/qtgradienteditor/qtcolorline.h create mode 100644 src/shared/qtgradienteditor/qtgradientdialog.cpp create mode 100644 src/shared/qtgradienteditor/qtgradientdialog.h create mode 100644 src/shared/qtgradienteditor/qtgradientdialog.ui create mode 100644 src/shared/qtgradienteditor/qtgradienteditor.cpp create mode 100644 src/shared/qtgradienteditor/qtgradienteditor.h create mode 100644 src/shared/qtgradienteditor/qtgradienteditor.pri create mode 100644 src/shared/qtgradienteditor/qtgradienteditor.qrc create mode 100644 src/shared/qtgradienteditor/qtgradienteditor.ui create mode 100644 src/shared/qtgradienteditor/qtgradientmanager.cpp create mode 100644 src/shared/qtgradienteditor/qtgradientmanager.h create mode 100644 src/shared/qtgradienteditor/qtgradientstopscontroller.cpp create mode 100644 src/shared/qtgradienteditor/qtgradientstopscontroller.h create mode 100644 src/shared/qtgradienteditor/qtgradientstopsmodel.cpp create mode 100644 src/shared/qtgradienteditor/qtgradientstopsmodel.h create mode 100644 src/shared/qtgradienteditor/qtgradientstopswidget.cpp create mode 100644 src/shared/qtgradienteditor/qtgradientstopswidget.h create mode 100644 src/shared/qtgradienteditor/qtgradientutils.cpp create mode 100644 src/shared/qtgradienteditor/qtgradientutils.h create mode 100644 src/shared/qtgradienteditor/qtgradientview.cpp create mode 100644 src/shared/qtgradienteditor/qtgradientview.h create mode 100644 src/shared/qtgradienteditor/qtgradientview.ui create mode 100644 src/shared/qtgradienteditor/qtgradientviewdialog.cpp create mode 100644 src/shared/qtgradienteditor/qtgradientviewdialog.h create mode 100644 src/shared/qtgradienteditor/qtgradientviewdialog.ui create mode 100644 src/shared/qtgradienteditor/qtgradientwidget.cpp create mode 100644 src/shared/qtgradienteditor/qtgradientwidget.h create mode 100644 src/shared/qtpropertybrowser/images/cursor-arrow.png create mode 100644 src/shared/qtpropertybrowser/images/cursor-busy.png create mode 100644 src/shared/qtpropertybrowser/images/cursor-closedhand.png create mode 100644 src/shared/qtpropertybrowser/images/cursor-cross.png create mode 100644 src/shared/qtpropertybrowser/images/cursor-forbidden.png create mode 100644 src/shared/qtpropertybrowser/images/cursor-hand.png create mode 100644 src/shared/qtpropertybrowser/images/cursor-hsplit.png create mode 100644 src/shared/qtpropertybrowser/images/cursor-ibeam.png create mode 100644 src/shared/qtpropertybrowser/images/cursor-openhand.png create mode 100644 src/shared/qtpropertybrowser/images/cursor-sizeall.png create mode 100644 src/shared/qtpropertybrowser/images/cursor-sizeb.png create mode 100644 src/shared/qtpropertybrowser/images/cursor-sizef.png create mode 100644 src/shared/qtpropertybrowser/images/cursor-sizeh.png create mode 100644 src/shared/qtpropertybrowser/images/cursor-sizev.png create mode 100644 src/shared/qtpropertybrowser/images/cursor-uparrow.png create mode 100644 src/shared/qtpropertybrowser/images/cursor-vsplit.png create mode 100644 src/shared/qtpropertybrowser/images/cursor-wait.png create mode 100644 src/shared/qtpropertybrowser/images/cursor-whatsthis.png create mode 100644 src/shared/qtpropertybrowser/qtbuttonpropertybrowser.cpp create mode 100644 src/shared/qtpropertybrowser/qtbuttonpropertybrowser.h create mode 100644 src/shared/qtpropertybrowser/qteditorfactory.cpp create mode 100644 src/shared/qtpropertybrowser/qteditorfactory.h create mode 100644 src/shared/qtpropertybrowser/qtgroupboxpropertybrowser.cpp create mode 100644 src/shared/qtpropertybrowser/qtgroupboxpropertybrowser.h create mode 100644 src/shared/qtpropertybrowser/qtpropertybrowser.cpp create mode 100644 src/shared/qtpropertybrowser/qtpropertybrowser.h create mode 100644 src/shared/qtpropertybrowser/qtpropertybrowser.pri create mode 100644 src/shared/qtpropertybrowser/qtpropertybrowser.qrc create mode 100644 src/shared/qtpropertybrowser/qtpropertybrowserutils.cpp create mode 100644 src/shared/qtpropertybrowser/qtpropertybrowserutils.pri create mode 100644 src/shared/qtpropertybrowser/qtpropertybrowserutils_p.h create mode 100644 src/shared/qtpropertybrowser/qtpropertymanager.cpp create mode 100644 src/shared/qtpropertybrowser/qtpropertymanager.h create mode 100644 src/shared/qtpropertybrowser/qttreepropertybrowser.cpp create mode 100644 src/shared/qtpropertybrowser/qttreepropertybrowser.h create mode 100644 src/shared/qtpropertybrowser/qtvariantproperty.cpp create mode 100644 src/shared/qtpropertybrowser/qtvariantproperty.h create mode 100644 src/shared/qttoolbardialog/images/back.png create mode 100644 src/shared/qttoolbardialog/images/down.png create mode 100644 src/shared/qttoolbardialog/images/forward.png create mode 100644 src/shared/qttoolbardialog/images/minus.png create mode 100644 src/shared/qttoolbardialog/images/plus.png create mode 100644 src/shared/qttoolbardialog/images/up.png create mode 100644 src/shared/qttoolbardialog/qttoolbardialog.cpp create mode 100644 src/shared/qttoolbardialog/qttoolbardialog.h create mode 100644 src/shared/qttoolbardialog/qttoolbardialog.pri create mode 100644 src/shared/qttoolbardialog/qttoolbardialog.qrc create mode 100644 src/shared/qttoolbardialog/qttoolbardialog.ui create mode 100644 src/tools.pro create mode 100644 tests/README create mode 100644 tests/auto/auto.pro create mode 100644 tests/auto/bic/.gitignore create mode 100644 tests/auto/bic/data/QtDesigner.4.2.0.linux-gcc-ia32.txt create mode 100644 tests/auto/bic/data/QtDesigner.4.3.0.linux-gcc-ia32.txt create mode 100644 tests/auto/bic/data/QtDesigner.4.4.0.linux-gcc-ia32.txt create mode 100644 tests/auto/bic/data/QtDesigner.4.5.0.linux-gcc-amd64.txt create mode 100644 tests/auto/bic/data/QtDesigner.4.5.0.linux-gcc-ia32.txt create mode 100644 tests/auto/bic/data/QtDesigner.4.6.0.linux-gcc-amd64.txt create mode 100644 tests/auto/bic/data/QtDesigner.4.6.0.linux-gcc-ia32.txt create mode 100644 tests/auto/bic/data/QtDesigner.4.7.0.linux-gcc-ia32.txt create mode 100644 tests/auto/bic/data/QtHelp.4.5.0.linux-gcc-amd64.txt create mode 100644 tests/auto/bic/data/QtHelp.4.5.0.linux-gcc-ia32.txt create mode 100644 tests/auto/bic/data/QtHelp.4.6.0.linux-gcc-amd64.txt create mode 100644 tests/auto/bic/data/QtHelp.4.6.0.linux-gcc-ia32.txt create mode 100644 tests/auto/bic/data/QtHelp.4.7.0.linux-gcc-ia32.txt create mode 100644 tests/auto/linguist/lconvert/.gitignore create mode 100644 tests/auto/linguist/lconvert/data/codec-cp1252.ts create mode 100644 tests/auto/linguist/lconvert/data/codec-utf8.ts create mode 100644 tests/auto/linguist/lconvert/data/dual-encoding.ts create mode 100644 tests/auto/linguist/lconvert/data/endless-po-loop.ts create mode 100755 tests/auto/linguist/lconvert/data/makeplurals.pl create mode 100644 tests/auto/linguist/lconvert/data/msgid.ts create mode 100644 tests/auto/linguist/lconvert/data/phrasebook.qph create mode 100644 tests/auto/linguist/lconvert/data/plurals-cn.ts create mode 100644 tests/auto/linguist/lconvert/data/plurals-de.ts create mode 100644 tests/auto/linguist/lconvert/data/relative.ts create mode 100644 tests/auto/linguist/lconvert/data/singular.po create mode 100644 tests/auto/linguist/lconvert/data/test-broken-utf8.po create mode 100644 tests/auto/linguist/lconvert/data/test-broken-utf8.po.out create mode 100644 tests/auto/linguist/lconvert/data/test-developer-comment.po create mode 100644 tests/auto/linguist/lconvert/data/test-empty-comment.po create mode 100644 tests/auto/linguist/lconvert/data/test-escapes.po create mode 100644 tests/auto/linguist/lconvert/data/test-escapes.po.out create mode 100644 tests/auto/linguist/lconvert/data/test-kde-ctxt.po create mode 100644 tests/auto/linguist/lconvert/data/test-kde-fuzzy.po create mode 100644 tests/auto/linguist/lconvert/data/test-kde-multiline.po create mode 100644 tests/auto/linguist/lconvert/data/test-kde-plurals.po create mode 100644 tests/auto/linguist/lconvert/data/test-refs.po create mode 100644 tests/auto/linguist/lconvert/data/test-slurp.po create mode 100644 tests/auto/linguist/lconvert/data/test-slurp.po.out create mode 100644 tests/auto/linguist/lconvert/data/test-translator-comment.po create mode 100644 tests/auto/linguist/lconvert/data/test1-cn.po create mode 100644 tests/auto/linguist/lconvert/data/test1-de.po create mode 100644 tests/auto/linguist/lconvert/data/test11.ts create mode 100644 tests/auto/linguist/lconvert/data/test20.ts create mode 100644 tests/auto/linguist/lconvert/data/variants.ts create mode 100644 tests/auto/linguist/lconvert/data/wrapping.po create mode 100644 tests/auto/linguist/lconvert/lconvert.pro create mode 100644 tests/auto/linguist/lconvert/tst_lconvert.cpp create mode 100644 tests/auto/linguist/linguist.pro create mode 100644 tests/auto/linguist/lrelease/.gitignore create mode 100644 tests/auto/linguist/lrelease/lrelease.pro create mode 100644 tests/auto/linguist/lrelease/testdata/compressed.ts create mode 100644 tests/auto/linguist/lrelease/testdata/dupes.errors create mode 100644 tests/auto/linguist/lrelease/testdata/dupes.ts create mode 100644 tests/auto/linguist/lrelease/testdata/idbased.ts create mode 100644 tests/auto/linguist/lrelease/testdata/mixedcodecs-ts11.ts create mode 100644 tests/auto/linguist/lrelease/testdata/mixedcodecs-ts20.ts create mode 100644 tests/auto/linguist/lrelease/testdata/translate.ts create mode 100644 tests/auto/linguist/lrelease/tst_lrelease.cpp create mode 100644 tests/auto/linguist/lupdate/.gitignore create mode 100644 tests/auto/linguist/lupdate/lupdate.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/backslashes/lupdatecmd create mode 100644 tests/auto/linguist/lupdate/testdata/good/backslashes/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/backslashes/src/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/backslashes/ts/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/cmdline_deeppath/lupdatecmd create mode 100644 tests/auto/linguist/lupdate/testdata/good/cmdline_deeppath/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/cmdline_order/a.h create mode 100644 tests/auto/linguist/lupdate/testdata/good/cmdline_order/b.h create mode 100644 tests/auto/linguist/lupdate/testdata/good/cmdline_order/lupdatecmd create mode 100644 tests/auto/linguist/lupdate/testdata/good/cmdline_order/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/cmdline_recurse/lupdatecmd create mode 100644 tests/auto/linguist/lupdate/testdata/good/cmdline_recurse/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/codecforsrc/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/codecforsrc/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/codecforsrc/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/codecfortr/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/codecfortr/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/codecfortr/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/codecfortr1/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/codecfortr1/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/codecfortr1/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/codecfortr2/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/codecfortr2/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/codecfortr2/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/codecfortr3/expectedoutput.txt create mode 100644 tests/auto/linguist/lupdate/testdata/good/codecfortr3/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/codecfortr3/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/codecfortr3/project.ts.before create mode 100644 tests/auto/linguist/lupdate/testdata/good/codecfortr3/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/codecfortr4/expectedoutput.txt create mode 100644 tests/auto/linguist/lupdate/testdata/good/codecfortr4/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/codecfortr4/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/codecfortr4/project.ts.before create mode 100644 tests/auto/linguist/lupdate/testdata/good/codecfortr4/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/from_subdir/lupdatecmd create mode 100644 tests/auto/linguist/lupdate/testdata/good/from_subdir/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/from_subdir/src/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/from_subdir/src/main.h create mode 100644 tests/auto/linguist/lupdate/testdata/good/from_subdir/translations/translations.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/heuristics/expectedoutput.txt create mode 100644 tests/auto/linguist/lupdate/testdata/good/heuristics/lupdatecmd create mode 100644 tests/auto/linguist/lupdate/testdata/good/heuristics/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/heuristics/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/heuristics/project.ts.before create mode 100644 tests/auto/linguist/lupdate/testdata/good/heuristics/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/lacksqobject/expectedoutput.txt create mode 100644 tests/auto/linguist/lupdate/testdata/good/lacksqobject/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/lacksqobject/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/lacksqobject/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/merge_ordering/foo.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/merge_ordering/lupdatecmd create mode 100644 tests/auto/linguist/lupdate/testdata/good/merge_ordering/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/merge_ordering/project.ts.before create mode 100644 tests/auto/linguist/lupdate/testdata/good/merge_ordering/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/merge_versions/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/merge_versions/project.ts.before create mode 100644 tests/auto/linguist/lupdate/testdata/good/merge_versions/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/merge_versions/project.ui create mode 100644 tests/auto/linguist/lupdate/testdata/good/merge_whitespace/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/merge_whitespace/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/merge_whitespace/project.ts.before create mode 100644 tests/auto/linguist/lupdate/testdata/good/merge_whitespace/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/mergecpp/finddialog.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/mergecpp/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/mergecpp/project.ts.before create mode 100644 tests/auto/linguist/lupdate/testdata/good/mergecpp/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/mergecpp_noobsolete/finddialog.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/mergecpp_noobsolete/lupdatecmd create mode 100644 tests/auto/linguist/lupdate/testdata/good/mergecpp_noobsolete/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/mergecpp_noobsolete/project.ts.before create mode 100644 tests/auto/linguist/lupdate/testdata/good/mergecpp_noobsolete/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/mergecpp_obsolete/finddialog.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/mergecpp_obsolete/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/mergecpp_obsolete/project.ts.before create mode 100644 tests/auto/linguist/lupdate/testdata/good/mergecpp_obsolete/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/mergeui/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/mergeui/project.ts.before create mode 100644 tests/auto/linguist/lupdate/testdata/good/mergeui/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/mergeui/project.ui create mode 100644 tests/auto/linguist/lupdate/testdata/good/mergeui_obsolete/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/mergeui_obsolete/project.ts.before create mode 100644 tests/auto/linguist/lupdate/testdata/good/mergeui_obsolete/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/mergeui_obsolete/project.ui create mode 100644 tests/auto/linguist/lupdate/testdata/good/multiple_locations/finddialog.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/multiple_locations/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/multiple_locations/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/multiple_locations/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/namespaces/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/namespaces/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/namespaces/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/parse_special_chars/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/parse_special_chars/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/parse_special_chars/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsecontexts/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsecontexts/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsecontexts/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsecpp/finddialog.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsecpp/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsecpp/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsecpp/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsecpp2/expectedoutput.txt create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsecpp2/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsecpp2/main.h create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsecpp2/main2.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsecpp2/main3.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsecpp2/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsecpp2/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsejava/main.java create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsejava/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsejava/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsejs/main.js create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsejs/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsejs/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsejs2/expectedoutput.txt create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsejs2/main.js create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsejs2/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsejs2/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsejscontexts/main.js create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsejscontexts/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/parsejscontexts/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/parseqml/main.qml create mode 100644 tests/auto/linguist/lupdate/testdata/good/parseqml/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/parseqml/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/parseui/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/parseui/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/parseui/project.ui create mode 100644 tests/auto/linguist/lupdate/testdata/good/prefix/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/prefix/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/prefix/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/preprocess/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/preprocess/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/preprocess/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing/main_mac.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing/main_unix.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing/main_win.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing/vpaths/dependpath/main_dependpath.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing/wildcard/main1.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing/wildcard/mainfile.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing/wildcard1.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing/wildcard99.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing2/a create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing2/a.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing2/b create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing2/b.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing2/e create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing2/f/g.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing2/files-cc.txt create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing2/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing2/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing2/spaces/z create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing2/variable_with_spaces create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing2/with create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing2/x/d create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsing2/x/variable create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingpaths/file1.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingpaths/filter.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingpaths/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingpaths/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingpaths/sub/sub.pri create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingpaths/sub/subfile1.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingpaths/sub/subfilter.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingpri/common/common.pri create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingpri/common/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingpri/common/main.pri create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingpri/mac/mac.pri create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingpri/mac/main_mac.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingpri/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingpri/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingpri/relativity/relativity.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingpri/relativity/relativity.pri create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingpri/relativity/sub/sub.pri create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingpri/relativity/sub2/sub2.pri create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingpri/unix/main_unix.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingpri/unix/unix.pri create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingpri/win/main_win.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingpri/win/win.pri create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingsubdirs/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingsubdirs/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingsubdirs/sub1/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingsubdirs/sub1/sub1.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingsubs/common/common.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingsubs/common/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingsubs/lupdatecmd create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingsubs/mac/mac.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingsubs/mac/main_mac.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingsubs/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingsubs/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingsubs/unix/main_unix.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingsubs/unix/unix.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingsubs/win/main_win.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/proparsingsubs/win/win.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/recurse_full/expectedoutput.txt create mode 100644 tests/auto/linguist/lupdate/testdata/good/recurse_full/lupdatecmd create mode 100644 tests/auto/linguist/lupdate/testdata/good/recurse_full/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/recurse_full/project_sub.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/recurse_full_ts/expectedoutput.txt create mode 100644 tests/auto/linguist/lupdate/testdata/good/recurse_full_ts/lupdatecmd create mode 100644 tests/auto/linguist/lupdate/testdata/good/recurse_full_ts/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/recurse_full_ts/project_sub.ts.before create mode 100644 tests/auto/linguist/lupdate/testdata/good/recurse_full_ts/project_sub.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/recurse_full_ts_join/expectedoutput.txt create mode 100644 tests/auto/linguist/lupdate/testdata/good/recurse_full_ts_join/lupdatecmd create mode 100644 tests/auto/linguist/lupdate/testdata/good/recurse_full_ts_join/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/recurse_part/expectedoutput.txt create mode 100644 tests/auto/linguist/lupdate/testdata/good/recurse_part/lupdatecmd create mode 100644 tests/auto/linguist/lupdate/testdata/good/recurse_part/project.ts.before create mode 100644 tests/auto/linguist/lupdate/testdata/good/recurse_part/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/recurse_part/project_sub.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/recurse_part_ts/expectedoutput.txt create mode 100644 tests/auto/linguist/lupdate/testdata/good/recurse_part_ts/lupdatecmd create mode 100644 tests/auto/linguist/lupdate/testdata/good/recurse_part_ts/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/recurse_part_ts/project_sub.ts.before create mode 100644 tests/auto/linguist/lupdate/testdata/good/recurse_part_ts/project_sub.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/reloutput/lupdatecmd create mode 100644 tests/auto/linguist/lupdate/testdata/good/reloutput/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/reloutput/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/reloutput/translations/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/respfile/lupdatecmd create mode 100644 tests/auto/linguist/lupdate/testdata/good/respfile/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/respfile/source1.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/respfile/source2.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/good/respfile/sources.lst create mode 100644 tests/auto/linguist/lupdate/testdata/good/respfile/tsfiles.lst create mode 100644 tests/auto/linguist/lupdate/testdata/good/textsimilarity/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/good/textsimilarity/project.ts.before create mode 100644 tests/auto/linguist/lupdate/testdata/good/textsimilarity/project.ts.result create mode 100644 tests/auto/linguist/lupdate/testdata/good/textsimilarity/project.ui create mode 100644 tests/auto/linguist/lupdate/testdata/recursivescan/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/recursivescan/project.ui create mode 100644 tests/auto/linguist/lupdate/testdata/recursivescan/sub/filetypes/main.c++ create mode 100644 tests/auto/linguist/lupdate/testdata/recursivescan/sub/filetypes/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/recursivescan/sub/filetypes/main.cxx create mode 100644 tests/auto/linguist/lupdate/testdata/recursivescan/sub/finddialog.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/subdirs_full/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/subdirs_full/subdir1/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/subdirs_full/subdir1/subdir1.pro create mode 100644 tests/auto/linguist/lupdate/testdata/subdirs_full/subdir2/subdir2.pro create mode 100644 tests/auto/linguist/lupdate/testdata/subdirs_full/subdir2/subsub1/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/subdirs_full/subdir2/subsub1/subsub1.pro create mode 100644 tests/auto/linguist/lupdate/testdata/subdirs_full/subdir2/subsub2/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/subdirs_full/subdir2/subsub2/subsub2.pro create mode 100644 tests/auto/linguist/lupdate/testdata/subdirs_part/project.pro create mode 100644 tests/auto/linguist/lupdate/testdata/subdirs_part/subdir1/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/subdirs_part/subdir1/subdir1.pro create mode 100644 tests/auto/linguist/lupdate/testdata/subdirs_part/subdir2/subdir2.pro create mode 100644 tests/auto/linguist/lupdate/testdata/subdirs_part/subdir2/subsub1/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/subdirs_part/subdir2/subsub1/subsub1.pro create mode 100644 tests/auto/linguist/lupdate/testdata/subdirs_part/subdir2/subsub2/main.cpp create mode 100644 tests/auto/linguist/lupdate/testdata/subdirs_part/subdir2/subsub2/subsub2.pro create mode 100644 tests/auto/linguist/lupdate/tst_lupdate.cpp create mode 100644 tests/auto/qhelpcontentmodel/.gitignore create mode 100644 tests/auto/qhelpcontentmodel/data/collection.qhc create mode 100644 tests/auto/qhelpcontentmodel/data/qmake-3.3.8.qch create mode 100644 tests/auto/qhelpcontentmodel/data/qmake-4.3.0.qch create mode 100644 tests/auto/qhelpcontentmodel/data/test.qch create mode 100644 tests/auto/qhelpcontentmodel/qhelpcontentmodel.pro create mode 100644 tests/auto/qhelpcontentmodel/tst_qhelpcontentmodel.cpp create mode 100644 tests/auto/qhelpenginecore/.gitignore create mode 100644 tests/auto/qhelpenginecore/data/collection.qhc create mode 100644 tests/auto/qhelpenginecore/data/collection1.qhc create mode 100644 tests/auto/qhelpenginecore/data/linguist-3.3.8.qch create mode 100644 tests/auto/qhelpenginecore/data/qmake-3.3.8.qch create mode 100644 tests/auto/qhelpenginecore/data/qmake-4.3.0.qch create mode 100644 tests/auto/qhelpenginecore/data/test.html create mode 100644 tests/auto/qhelpenginecore/data/test.qch create mode 100644 tests/auto/qhelpenginecore/qhelpenginecore.pro create mode 100644 tests/auto/qhelpenginecore/tst_qhelpenginecore.cpp create mode 100644 tests/auto/qhelpgenerator/.gitignore create mode 100644 tests/auto/qhelpgenerator/data/cars.html create mode 100644 tests/auto/qhelpgenerator/data/classic.css create mode 100644 tests/auto/qhelpgenerator/data/fancy.html create mode 100644 tests/auto/qhelpgenerator/data/people.html create mode 100644 tests/auto/qhelpgenerator/data/sub/about.html create mode 100644 tests/auto/qhelpgenerator/data/test.html create mode 100644 tests/auto/qhelpgenerator/data/test.qhp create mode 100644 tests/auto/qhelpgenerator/qhelpgenerator.pro create mode 100644 tests/auto/qhelpgenerator/tst_qhelpgenerator.cpp create mode 100644 tests/auto/qhelpindexmodel/.gitignore create mode 100644 tests/auto/qhelpindexmodel/data/collection.qhc create mode 100644 tests/auto/qhelpindexmodel/data/collection1.qhc create mode 100644 tests/auto/qhelpindexmodel/data/linguist-3.3.8.qch create mode 100644 tests/auto/qhelpindexmodel/data/qmake-3.3.8.qch create mode 100644 tests/auto/qhelpindexmodel/data/qmake-4.3.0.qch create mode 100644 tests/auto/qhelpindexmodel/data/test.html create mode 100644 tests/auto/qhelpindexmodel/data/test.qch create mode 100644 tests/auto/qhelpindexmodel/qhelpindexmodel.pro create mode 100644 tests/auto/qhelpindexmodel/tst_qhelpindexmodel.cpp create mode 100644 tests/auto/qhelpprojectdata/.gitignore create mode 100644 tests/auto/qhelpprojectdata/data/test.qhp create mode 100644 tests/auto/qhelpprojectdata/qhelpprojectdata.pro create mode 100644 tests/auto/qhelpprojectdata/tst_qhelpprojectdata.cpp create mode 100644 tests/global/.gitignore create mode 100644 tests/tests.pro diff --git a/3rdparty/clucene/APACHE.license b/3rdparty/clucene/APACHE.license new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/3rdparty/clucene/APACHE.license @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/3rdparty/clucene/AUTHORS b/3rdparty/clucene/AUTHORS new file mode 100644 index 000000000..4a7904b6d --- /dev/null +++ b/3rdparty/clucene/AUTHORS @@ -0,0 +1,22 @@ +As with most development projects, contributions come from many people and in +many forms. The CLucene project would like to thank it's many contributors. +Omissions are merely accidental, please e-mail ustramooner@users.sourceforge.net +if you have been left out or a contribution is not mentioned. + +CLucene was originally ported to C++ by Ben van Klinken (ustramooner@users.sourceforge.net) +from Doug Cutting's popular java search engine, Lucene (see http://lucene.apache.org). + +Here is a list of contributors. Please send me an email at ustramooner@users.sourceforge.net +if I have left you out. + +Doug Cutting cutting@users.sourceforge.net +John Wheeler j_wheeler@users.sourceforge.net +Robert G. Ristroph rgristroph@users.sourceforge.net +David Rushby woodsplitter@users.sourceforge.net +Jimmy Pritts jpritts@sdf.lonestar.org +Peter Edwards peter@dragonstaff.co.uk +Jorge Sabater Redondo jsabater@elderecho.com +Daniel Glassey danglassey@ntlworld.com +Peter Gladkikh batyi@mail.ru +Pedja amigo@max3d.com +Peter Hodges hodges.peter@gmail.com diff --git a/3rdparty/clucene/COPYING b/3rdparty/clucene/COPYING new file mode 100644 index 000000000..0e32bb4f3 --- /dev/null +++ b/3rdparty/clucene/COPYING @@ -0,0 +1,30 @@ +License + +The CLucene Core Library uses a dual license strategy for the source code. +These licenses are the GNU Lesser General Public License (LGPL) and the Apache +License (Version 2.0). Users can choose the license they wish to distribute +their software under. This means that you do not need to abide by *both* +licenses, but rather than you can choose the license which most suits your +needs. + +To rephrase this and to make it perfectly clear: +CLucene is distributed under the GNU Lesser General Public License (LGPL) + *or* +the Apache License, Version 2.0 + +However, we are an open source project, and we encourage users to use the LGPL +license and participate fully in the free software community. Dual licensing +of the CLucene source code provides open and free access to the technology both +for the GPL community and for other developers or companies that cannot use the +GPL. + +You can freely modify, extend, and improve the CLucene source code. The only +question is whether or not you must provide the source code and contribute +modifications to the community. The GNU and Apache licenses allow different +ranges of flexibility in this regard, but in the end, regardless of the license +used, we highly recommend that you submit any bugs, incompatibilities or +added features. + +Note that this same license does *not* apply to the CLucene Contributions +package. You should read the COPYING file in that directory or package for +more information. \ No newline at end of file diff --git a/3rdparty/clucene/ChangeLog b/3rdparty/clucene/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/3rdparty/clucene/LGPL.license b/3rdparty/clucene/LGPL.license new file mode 100644 index 000000000..422c76072 --- /dev/null +++ b/3rdparty/clucene/LGPL.license @@ -0,0 +1,475 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + +------------------------------------------------------------------------------- + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + +------------------------------------------------------------------------------- + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + +------------------------------------------------------------------------------- + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + +------------------------------------------------------------------------------- + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + +------------------------------------------------------------------------------- + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + +------------------------------------------------------------------------------- + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + +------------------------------------------------------------------------------- + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + +------------------------------------------------------------------------------- + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + diff --git a/3rdparty/clucene/README b/3rdparty/clucene/README new file mode 100644 index 000000000..ee4f49369 --- /dev/null +++ b/3rdparty/clucene/README @@ -0,0 +1,92 @@ +CLucene README +============== + +------------------------------------------------------ +CLucene is a C++ port of Lucene. +It is a high-performance, full-featured text search +engine written in C++. CLucene is faster than lucene +as it is written in C++. +------------------------------------------------------ + +CLucene has contributions from many, see AUTHORS + +CLucene is distributed under the GNU Lesser General Public License (LGPL) + *or* +the Apache License, Version 2.0 +See the LGPL.license and APACHE.license for the respective license information. +Read COPYING for more about the license. + +Installation +------------ +* For Linux, MacOSX, cygwin and MinGW build information, read INSTALL. +* Boost.Jam files are provided in the root directory and subdirectories. +* Microsoft Visual Studio (6&7) are provided in the win32 folder. + +Mailing List +------------ +Questions and discussion should be directed to the CLucene mailing list + at clucene-developers@lists.sourceforge.net +Find subscription instructions at + http://lists.sourceforge.net/lists/listinfo/clucene-developers +Suggestions and bug reports can be made on our bug tracking database + (http://sourceforge.net/tracker/?group_id=80013&atid=558446) + +The latest version +------------------ +Details of the latest version can be found on the CLucene sourceforge project +web site: http://www.sourceforge.net/projects/clucene + +Documentation +------------- +Documentation is provided at http://clucene.sourceforge.net/doc/doxygen/html/ +You can also build your own documentation by running doxygen from the root directory +of clucene. +CLucene is a very close port of Java Lucene, so you can also try looking at the +Java Docs on http://lucene.apache.org/java/ + + +Performance +----------- +Very little benchmarking has been done on clucene. Andi Vajda posted some +limited statistics on the clucene list a while ago with the following results. + +There are 250 HTML files under $JAVA_HOME/docs/api/java/util for about +6108kb of HTML text. +org.apache.lucene.demo.IndexFiles with java and gcj: +on mac os x 10.3.1 (panther) powerbook g4 1ghz 1gb: + . running with java 1.4.1_01-99 : 20379 ms + . running with gcj 3.3.2 -O2 : 17842 ms + . running clucene 0.8.9's demo : 9930 ms + +I recently did some more tests and came up with these rough tests: +663mb (797 files) of Guttenberg texts +on a Pentium 4 running Windows XP with 1 GB of RAM. Indexing max 100,000 fields +• Jlucene: 646453ms. peak mem usage ~72mb, avg ~14mb ram +• Clucene: 232141. peak mem usage ~60, avg ~4mb ram + +Searching indexing using 10,000 single word queries +• Jlucene: ~60078ms and used ~13mb ram +• Clucene: ~48359ms and used ~4.2mb ram + +Platform notes +-------------- + +'Too many open files' +Some platforms don't provide enough file handles to run CLucene properly. +To solve this, increase the open file limit: + +On Solaris: +ulimit -n 1024 +set rlim_fd_cur=1024 + +Acknowledgments +---------------- + +The Apache Lucene project is the basis for this software, so the biggest +acknoledgment goes to that project. + +We wish to acknowledge the following copyrighted works that +make up portions of the CLucene software: + +CLucene relies heavily on the use of autoconf and libtool to provide +a build environment. diff --git a/3rdparty/clucene/src/CLucene.h b/3rdparty/clucene/src/CLucene.h new file mode 100644 index 000000000..1eac800fd --- /dev/null +++ b/3rdparty/clucene/src/CLucene.h @@ -0,0 +1,38 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +//Includes some standard headers for searching and indexing. +#ifndef _lucene_CLucene_ +#define _lucene_CLucene_ + +#include "CLucene/StdHeader.h" +#include "CLucene/debug/condition.h" +#include "CLucene/debug/mem.h" +#include "CLucene/index/IndexReader.h" +#include "CLucene/index/IndexWriter.h" +#include "CLucene/index/MultiReader.h" +#include "CLucene/index/Term.h" +#include "CLucene/search/IndexSearcher.h" +#include "CLucene/search/MultiSearcher.h" +#include "CLucene/search/DateFilter.h" +#include "CLucene/search/WildcardQuery.h" +#include "CLucene/search/FuzzyQuery.h" +#include "CLucene/search/PhraseQuery.h" +#include "CLucene/search/PrefixQuery.h" +#include "CLucene/search/RangeQuery.h" +#include "CLucene/search/BooleanQuery.h" +#include "CLucene/document/Document.h" +#include "CLucene/document/Field.h" +#include "CLucene/document/DateField.h" +#include "CLucene/store/Directory.h" +#include "CLucene/store/FSDirectory.h" +#include "CLucene/queryParser/QueryParser.h" +#include "CLucene/queryParser/MultiFieldQueryParser.h" +#include "CLucene/analysis/standard/StandardAnalyzer.h" +#include "CLucene/analysis/Analyzers.h" +#include "CLucene/util/Reader.h" + +#endif diff --git a/3rdparty/clucene/src/CLucene/CLBackwards.h b/3rdparty/clucene/src/CLucene/CLBackwards.h new file mode 100644 index 000000000..ffaf42824 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/CLBackwards.h @@ -0,0 +1,87 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _clucene_backwards_h +#define _clucene_backwards_h + +//In light of the recent major changes to clucene, +//this file should help to maintain some backwards compatibility +//include it after including StdHeader.h +// +//Note: I haven't tested this much, so please send me your changes + +//dirent is one of the most major changes that won't easily port. +//you can use the TCHAR copying macros, STRCPY_TtoA and STRCPY_AtoT +//to copy between different character types. + +//If you use stringPrintF, you will need to add the target string +//size parameter, because it is using _sntprintf... Change this if you +//want, but _sntprintf is much safer + +#define char_t TCHAR +#define uchar_t TCHAR +#define l_byte_t byte_t + +//#define stringSpn _tcsspn //not used in clucene anymore +#define stringCSpn _tcscspn +#define stringLength _tcslen +//#define stringToInteger _ttoi //not used in clucene anymore, use integer w/ base +#define stringFind _tcsstr +#define stringFindChar _tcschr +#define stringCompare _tcscmp +#define stringNCopy _tcsncpy +#define stringCopy _tcscpy +#define stringCat _tcscat +//#define stringToken _tcstok //not used in clucene anymore +#define stringPrintF _sntprintf //you will have errors, because now we used printf w/ bufferlen count +#define printFormatted _tprintf + +//conversion functions +#define integerToString _i64tot +#define stringToIntegerBase _tcstoi64 +#define stringToFloat _tcstod + +//file find structures +#define Cmd_Stat fileStat +#define Struct_Stat fileStat +#define stringICompare _tcsicmp +#define stringNCompare _tcsncmp +#define stringDifference _tcscmp + +//character conversion functions +#define isSpace _istspace +#define isDigit _istwdigit +#define isAlNum _istwalnum +#define toLower _totlower +#define stringUpper _tcsupr +//#define stringLower _tcslwr //not used in clucene anymore + +#define _THROWX(y) _THROWT(y) +#define _THROWC(y) _THROWA(y) + +//file naming stuff - remember we have changed all names to file naming lower case +#define fileRename _rename +#define fileFullName(abs,rel) _realpath(rel,abs) +#define makeDirectory _tmkdir +#define unlinkFile _unlink + +//no longer supported definitions +#ifdef _UNICODE + #define TO_CHAR_T STRDUP_AtoT + #define _cout wcout + #define _cin wcin + #define _cerr wcerr +#else + #define TO_CHAR_T STRDUP_WtoT + #define _cout cout + #define _cin cin + #define _cerr cerr +#endif + +//some headers that used to be automatically included: +#include "CLucene/util/dirent.h" //if we have dirent, then the native one will be used + +#endif diff --git a/3rdparty/clucene/src/CLucene/CLConfig.h b/3rdparty/clucene/src/CLucene/CLConfig.h new file mode 100644 index 000000000..c63c083ff --- /dev/null +++ b/3rdparty/clucene/src/CLucene/CLConfig.h @@ -0,0 +1,304 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_Config_ +#define _lucene_Config_ + + +//////////////////////////////////////////////////////////////////// +// this settings should be set up in the compiler, +// but are put here for reference as to what could be defined +//////////////////////////////////////////////////////////////////// +// +//define this if you want debugging code to be enabled +//#define _DEBUG +// +//define this if you want condition debugging to be enabled +#if defined(_DEBUG) && !defined(_CL__CND_DEBUG) + #define _CL__CND_DEBUG +#endif +// +//define this to print out lots of information about merges, etc +//requires __CL__CND_DEBUG to be defined +//#define _CL_DEBUG_INFO stdout +// +//to disable namespaces define this +//#define DISABLE_NAMESPACE +// +//This is mostly for windows. If you have put the google sparse +//map code in your include path somewhere, then define this +//to use it. +//However, for msvc, there are no significant gains since there +//is already a compatible hashmap available. +//#define _CL_HAVE_GOOGLE_DENSE_HASH_MAP +// +//////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////// +// These options can be set depending on the particular needs of +// Your application +//////////////////////////////////////////////////////////////////// +// +//define this to force the build into ascii mode +//#define _ASCII +// +//define this to force the build into ucs2 mode +//#define _UCS2 +// +//if a wide character is being converted to a ascii character and it +//cannot fit, this character is used instead. Required. +#define LUCENE_OOR_CHAR(c) ((char)(((unsigned short)c)&0xFF)) +// +//define if you would like to force clucene to use the internal +//character functions. +//Tests may display unpredictable behaviour if this is not defined. +#define LUCENE_USE_INTERNAL_CHAR_FUNCTIONS +// +//define this to enable mmap support in the fsdirectory IndexInput +//todo: only available for windows so far...need to add MMapInput.cpp to project +//EXPERIMENTAL +//#define LUCENE_FS_MMAP +// +//LOCK_DIR implementation: +//define this to set an exact directory for the lock dir (not recommended) +//all other methods of getting the temporary directory will be ignored +//#define LUCENE_LOCK_DIR "/tmp" +// +//define this to try and load the lock dir from this specified environment variable +#define LUCENE_LOCK_DIR_ENV_1 "TEMP" +//define this if you want to have look up this environment variable if the first one fails +#define LUCENE_LOCK_DIR_ENV_2 "TMP" +//define this if you want to have a fallback directory, if not defined then +//the lockdirectory will be the index directory +#define LUCENE_LOCK_DIR_ENV_FALLBACK "/tmp" +// +//////////////////////////////////////////////////////////////////// + + + +//////////////////////////////////////////////////////////////////// +// The following are search query options +// THe NO_* options can make CLucene faster and/or smaller +// special queries sometime require longer search times or may +// not be required +//////////////////////////////////////////////////////////////////// +// +//Define this to remove fuzzy query and sloppy scoring +//#define NO_FUZZY_QUERY +// +//Define to remove wildcard t*m or te?m to match term +//#define NO_WILDCARD_QUERY +// +//Define to remove prefix term query - ter* to match term or terms +//#define NO_PREFIX_QUERY +// +//Define to remove range (exlusive and inclusive) +//#define NO_RANGE_QUERY +// +//This must always be defined. They can be adjusted if required. But +//general Wildcard string would be '*' and Wildcard Char would be '?' +//Both are Required. +#define LUCENE_WILDCARDTERMENUM_WILDCARD_STRING '*' +#define LUCENE_WILDCARDTERMENUM_WILDCARD_CHAR '?' +// +//////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////// +// memory handling configurations +//////////////////////////////////////////////////////////////////// +// +//If this is defined, lucene's configurations are changed +//to use less memory, but may run slower. +//todo: i dont think this actualy changes speed much, just memory +#define LUCENE_OPTIMIZE_FOR_MEMORY +// +//define this if you want the pointer tracking to be enabled +//this is a useful tool for memory leak tracking +//The LuceneBase can slow down the code a *lot* +#if defined(_DEBUG) + #if !defined(LUCENE_DISABLE_MEMTRACKING) && !defined(LUCENE_ENABLE_MEMLEAKTRACKING) + #define LUCENE_ENABLE_MEMLEAKTRACKING + #endif +#endif +// +//enable use of rich file/line tracking. use CL_FILELINE to pass +//to functions like stringDuplicate (or use CL_STRDUP* functions instead) and +//CLStringIntern::x. +#if defined(LUCENE_ENABLE_MEMLEAKTRACKING) + #define LUCENE_ENABLE_FILELINEINFO +#endif +// +//enable creation of clucene.log file. Logs every +//call to new operator. Must have LUCENE_ENABLE_MEMLEAKTRACKING enabled. +//writes log in this format. +//action,file name,file line,allocation size +//logging can be disabled by setting _lucene_disable_debuglogging to true +#if defined(LUCENE_ENABLE_MEMLEAKTRACKING) && defined(_DEBUG) +//#define LUCENE_ENABLE_CONSTRUCTOR_LOG +#endif +// +// +//enable this if you want to enable reference counting. This is +//not necessary or useful in most cases except when implementing wrappers +//which have reference counting. If the wrapper wraps a StringReader, +//for example, it should expect that the wrapped StringReader should not +//be deleted. However, when the stringreader is added into a Field, +//the Field usually takes over the stringReader and deletes it on completion. +//If reference counting is enabled, the wrapper can add a reference to any class +//and when _CLDECDELETE is called, the reference is decremented and only deleted +//if the refcount is zero. +#define LUCENE_ENABLE_REFCOUNT + + +//////////////////////////////////////////////////////////////////// +// These options allow you to remove certain implementations +// out of clucene so that they can be implemented in the client +// application +//////////////////////////////////////////////////////////////////// +// +//define this to your own setting if you would like to implement your own +//threading locking code. it should have the same sort of functions as +//mutex_default. If not defined, clucene will try and use posix,win32 critical +//sections, or a timer based mutex hack. +//#define _LUCENE_THREADMUTEX CL_NS(util)::mutex_default +// +//define this if you want to implement the _Cnd_OutDebug routine yourself +//you can then easily customise in your own application how to handle debug messages +//#define _CND_DEBUG_DONTIMPLEMENT_OUTDEBUG +// +//define this if you want to implement your own namespace macros +//#define _LUCENE_DONTIMPLEMENT_NS_MACROS +// +//define this if you do not want clucene to include any standard libraries. +//this could be useful if you want to use alternate libraries +//#define LUCENE_DISABLE_INCLUDES +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// These options will be changed depending on your compiler/platform +// but can also be changed here if required +//////////////////////////////////////////////////////////////////// +// +//define this if multi-threading support is not required +//if not defined, multi-thread locking will +//occur (and its related processing overhead) +//note: it is recommended to disable multithreading if you do not need it +//there is a lot of overhead that can be avoided. +//#define _CL_DISABLE_MULTITHREADING +// +//if you want to define your own default file encoding. specify it +//here - normally defined in the platform specific headers +//#define PLATFORM_DEFAULT_READER_ENCODING CL_NS(util)::FileReader::ENCODING_ASCII +// +//disable hash implementations (if available) +//#define LUCENE_DISABLE_HASHING +//////////////////////////////////////////////////////////////////// + + + +//////////////////////////////////////////////////////////////////// +// These options should not be changed. But you can experiment with +// them to optimize performance +//////////////////////////////////////////////////////////////////// +// +//some defaults, wouldn't usually need to be changed +//Buffer size for input/output streams. Required. +#define LUCENE_STREAM_BUFFER_SIZE 1024 +// +// DSR:2004.08.19: +// Formerly, StringBuffer used 1024 as the default size of its internal buffer. +// However, StringBuffer is used primarily for token- and term-oriented +// processing, e.g. in StandardTokenizer. I've calculated that the average +// token (as produced by StandardTokenizer) in all .txt files distributed in +// the Project Gutenberg CD Image (August 2003 release) has only 6 characters. +// Although most languages are likely to have a longer average word length than +// English due to the popularity of "non-atomized" conjugation and declension +// mechanisms, 1024 is still vastly excessive. +// I made two changes intended to deliver better overall performance: +// a) Switched to a default StringBuffer character capacity of 32. Though 32 +// is longer than the average token, the high cost of realloc makes a +// slightly liberal default size optimal. I chose the default size of 32 +// after fairly extensive experimentation on the Gutenberg e-texts. The +// results are summarized in the following table: +// ------------------------------------------------------------------------ +// LUCENE_DEFAULT_TOKEN_BUFFER_SIZE value | % faster than default size 1024 +// ------------------------------------------------------------------------ +// 8 : 4% +// 16 : 7% +// 32 : 6% +// 64 : 3% +// A default size of 32 is actually slightly slower than 16, but I was +// experimenting on English text; I expect that 32 will maintain decent +// performance in languages such as German, and in technical documents +// with long tokens. +// +// b) To offset the switch to a smaller default buffer size, I implemented a +// more aggressive growth strategy. A StringBuffer now [at least] doubles +// the size of its internal buffer every time it needs to grow, rather +// than [at least] increasing by LUCENE_DEFAULT_TOKEN_BUFFER_SIZE no +// matter how many times it has already grown. +//Required. +#define LUCENE_DEFAULT_TOKEN_BUFFER_SIZE 32 +//todo: should implement a similar strategy in analysis/token +// +//Expert: The fraction of {@link TermDocs} entries stored in skip tables, +//used to accellerate {@link TermDocs#skipTo(int)}. Larger values result in +//smaller indices, greater acceleration, but fewer accelerable cases, while +//smaller values result in bigger indices, less acceleration and more +//accelerable cases. More detailed experiments would be useful here. */ +#define LUCENE_DEFAULT_TERMDOCS_SKIP_INTERVAL 16 +// +//Size of TermScore cache. Required. +#define LUCENE_SCORE_CACHE_SIZE 32 +// +//analysis options +//maximum length that the CharTokenizer uses. Required. +//By adjusting this value, you can greatly improve the performance of searching +//and especially indexing. Default is 255, but smaller numbers will decrease +//the amount of memory used as well as increasing the speed. +#define LUCENE_MAX_WORD_LEN 255 +//Maximum length of a token word. +//Should be the same or more than LUCENE_MAX_WORD_LEN +//if not defined, then no token limit, but may be slower +//if defined will be faster (up to 15% in some cases), but will use more memory +#ifndef LUCENE_OPTIMIZE_FOR_MEMORY + #define LUCENE_TOKEN_WORD_LENGTH LUCENE_MAX_WORD_LEN +#endif +// +//maximum field length. some optimisation can be done if a maximum field +//length is given... The smaller the better +#define LUCENE_MAX_FIELD_LEN 100 +// +//The initial value set to BooleanQuery::maxClauseCount. Default is 1024 +#define LUCENE_BOOLEANQUERY_MAXCLAUSECOUNT 1024 +// +//bvk: 12.3.2005 +//============================================================================== +//Previously the way the tokenizer has worked has been changed to optionally +//use a a fixed word length. I have implemented this in the Term class as well. +//It seems that by predefining the text length instead of using new TCHAR[x] +//in the constructor greatly improves the performance by 20-30% for certain +//operations. +//Maximum length of a term text. +//Should be the same or more than LUCENE_MAX_WORD_LEN +//if not defined, then no term text limit, but may be slower +//if defined will be faster (up to 30% in some cases), but will use more memory +#ifndef LUCENE_OPTIMIZE_FOR_MEMORY + #define LUCENE_TERM_TEXT_LENGTH LUCENE_MAX_WORD_LEN +#endif +// +//Size of the CharTokenizer buffersize. Required. +#define LUCENE_IO_BUFFER_SIZE 1024 +// +//the minimum amount the segment term enum should grow by. Must be at least 1 +#define LUCENE_SEGMENTTERMENUM_GROWSIZE 8 +// +//////////////////////////////////////////////////////////////////// + +#endif + diff --git a/3rdparty/clucene/src/CLucene/CLMonolithic.cpp b/3rdparty/clucene/src/CLucene/CLMonolithic.cpp new file mode 100644 index 000000000..e3c279876 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/CLMonolithic.cpp @@ -0,0 +1,115 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +* +* Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +------------------------------------------------------------------------------*/ +/* +* this is a monolithic file that can be used to compile clucene using one source file. +* it simplifies some build processes by avoiding static & dynamic compalation pitfalls. +* +* note: when creating a project add either this file, or all the other .cpp files, not both! +*/ +#include "CLucene/StdHeader.cpp" +#include "CLucene/analysis/Analyzers.cpp" +#include "CLucene/analysis/AnalysisHeader.cpp" +#include "CLucene/analysis/standard/StandardAnalyzer.cpp" +#include "CLucene/analysis/standard/StandardFilter.cpp" +#include "CLucene/analysis/standard/StandardTokenizer.cpp" +#include "CLucene/config/gunichartables.cpp" +#include "CLucene/config/repl_tcscasecmp.cpp" +#include "CLucene/config/repl_tcslwr.cpp" +#include "CLucene/config/repl_tcstod.cpp" +#include "CLucene/config/repl_lltot.cpp" +#include "CLucene/config/repl_tcstoll.cpp" +#include "CLucene/config/repl_tprintf.cpp" +#include "CLucene/config/threads.cpp" +#include "CLucene/config/utf8.cpp" +#include "CLucene/debug/condition.cpp" +#include "CLucene/debug/error.cpp" +#include "CLucene/debug/memtracking.cpp" +#include "CLucene/document/DateField.cpp" +#include "CLucene/document/Document.cpp" +#include "CLucene/document/Field.cpp" +#include "CLucene/index/CompoundFile.cpp" +#include "CLucene/index/DocumentWriter.cpp" +#include "CLucene/index/FieldInfos.cpp" +#include "CLucene/index/FieldsReader.cpp" +#include "CLucene/index/FieldsWriter.cpp" +#include "CLucene/index/IndexWriter.cpp" +#include "CLucene/index/IndexReader.cpp" +#include "CLucene/index/MultiReader.cpp" +#include "CLucene/index/SegmentInfos.cpp" +#include "CLucene/index/SegmentMergeInfo.cpp" +#include "CLucene/index/SegmentMergeQueue.cpp" +#include "CLucene/index/SegmentMerger.cpp" +#include "CLucene/index/SegmentReader.cpp" +#include "CLucene/index/SegmentTermDocs.cpp" +#include "CLucene/index/SegmentTermEnum.cpp" +#include "CLucene/index/SegmentTermPositions.cpp" +#include "CLucene/index/SegmentTermVector.cpp" +#include "CLucene/index/Term.cpp" +#include "CLucene/index/TermInfo.cpp" +#include "CLucene/index/TermInfosReader.cpp" +#include "CLucene/index/TermInfosWriter.cpp" +#include "CLucene/index/TermVectorReader.cpp" +#include "CLucene/index/TermVectorWriter.cpp" +#include "CLucene/queryParser/Lexer.cpp" +#include "CLucene/queryParser/MultiFieldQueryParser.cpp" +#include "CLucene/queryParser/QueryParser.cpp" +#include "CLucene/queryParser/QueryParserBase.cpp" +#include "CLucene/queryParser/QueryToken.cpp" +#include "CLucene/queryParser/TokenList.cpp" +#include "CLucene/search/BooleanQuery.cpp" +#include "CLucene/search/BooleanScorer.cpp" +#include "CLucene/search/CachingWrapperFilter.cpp" +#include "CLucene/search/ChainedFilter.cpp" +#include "CLucene/search/DateFilter.cpp" +#include "CLucene/search/ConjunctionScorer.cpp" +#include "CLucene/search/ExactPhraseScorer.cpp" +#include "CLucene/search/Explanation.cpp" +#include "CLucene/search/FieldCache.cpp" +#include "CLucene/search/FieldCacheImpl.cpp" +#include "CLucene/search/FieldDocSortedHitQueue.cpp" +#include "CLucene/search/FieldSortedHitQueue.cpp" +#include "CLucene/search/FilteredTermEnum.cpp" +#include "CLucene/search/FuzzyQuery.cpp" +#include "CLucene/search/Hits.cpp" +#include "CLucene/search/HitQueue.cpp" +#include "CLucene/search/IndexSearcher.cpp" +#include "CLucene/search/MultiSearcher.cpp" +#include "CLucene/search/MultiTermQuery.cpp" +#include "CLucene/search/PhrasePositions.cpp" +#include "CLucene/search/PhraseQuery.cpp" +#include "CLucene/search/PhraseScorer.cpp" +#include "CLucene/search/PrefixQuery.cpp" +#include "CLucene/search/QueryFilter.cpp" +#include "CLucene/search/RangeQuery.cpp" +#include "CLucene/search/RangeFilter.cpp" +#include "CLucene/search/SearchHeader.cpp" +#include "CLucene/search/Similarity.cpp" +#include "CLucene/search/SloppyPhraseScorer.cpp" +#include "CLucene/search/Sort.cpp" +#include "CLucene/search/TermQuery.cpp" +#include "CLucene/search/TermScorer.cpp" +#include "CLucene/search/WildcardQuery.cpp" +#include "CLucene/search/WildcardTermEnum.cpp" +#include "CLucene/store/FSDirectory.cpp" +#include "CLucene/store/IndexInput.cpp" +#include "CLucene/store/Lock.cpp" +#include "CLucene/store/MMapInput.cpp" +#include "CLucene/store/IndexOutput.cpp" +#include "CLucene/store/RAMDirectory.cpp" +#include "CLucene/store/TransactionalRAMDirectory.cpp" +#include "CLucene/util/BitSet.cpp" +#include "CLucene/util/Equators.cpp" +#include "CLucene/util/FastCharStream.cpp" +#include "CLucene/util/fileinputstream.cpp" +#include "CLucene/util/Misc.cpp" +#include "CLucene/util/Reader.cpp" +#include "CLucene/util/StringBuffer.cpp" +#include "CLucene/util/StringIntern.cpp" +#include "CLucene/util/dirent.cpp" +#include "CLucene/util/ThreadLocal.cpp" diff --git a/3rdparty/clucene/src/CLucene/LuceneThreads.h b/3rdparty/clucene/src/CLucene/LuceneThreads.h new file mode 100644 index 000000000..cad07869f --- /dev/null +++ b/3rdparty/clucene/src/CLucene/LuceneThreads.h @@ -0,0 +1,72 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _LuceneThreads_h +#define _LuceneThreads_h +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#if defined(_CL_DISABLE_MULTITHREADING) + #define SCOPED_LOCK_MUTEX(theMutex) + #define DEFINE_MUTEX(x) + #define STATIC_DEFINE_MUTEX(x) + #define _LUCENE_SLEEP(x) + #define _LUCENE_CURRTHREADID 1 + #define _LUCENE_THREADID_TYPE char + + CL_NS_DEF(util) + class CLuceneThreadIdCompare + { + public: + enum + { // parameters for hash table + bucket_size = 4, // 0 < bucket_size + min_buckets = 8 + }; // min_buckets = 2 ^^ N, 0 < N + + bool operator()( char t1, char t2 ) const{ + return t1 < t2; + } + }; + CL_NS_END +#else + + #if defined(_LUCENE_DONTIMPLEMENT_THREADMUTEX) + //do nothing + #elif defined(_CL_HAVE_PTHREAD) + #include "CLucene/config/threadPthread.h" + #elif defined(_CL_HAVE_WIN32_THREADS) || defined(_CLCOMPILER_MSVC) || defined(__MINGW32__) //note that mingw32 could have pthreads, so put this after. + #if !defined(_CL_HAVE_WIN32_THREADS) + #define _CL_HAVE_WIN32_THREADS + #endif + #include "CLucene/config/threadCSection.h" + #else + #error A valid thread library was not found + #endif //mutex types + + CL_NS_DEF(util) + /** @internal */ + class mutexGuard + { + private: + _LUCENE_THREADMUTEX* mrMutex; + mutexGuard(const mutexGuard& clone); + public: + mutexGuard( _LUCENE_THREADMUTEX& rMutex ); + ~mutexGuard(); + }; + CL_NS_END + + #define SCOPED_LOCK_MUTEX(theMutex) CL_NS(util)::mutexGuard theMutexGuard(theMutex); + #define DEFINE_MUTEX(theMutex) _LUCENE_THREADMUTEX theMutex; + #define STATIC_DEFINE_MUTEX(theMutex) static _LUCENE_THREADMUTEX theMutex; + +#endif //_CL_DISABLE_MULTITHREADING + + + +#endif diff --git a/3rdparty/clucene/src/CLucene/StdHeader.cpp b/3rdparty/clucene/src/CLucene/StdHeader.cpp new file mode 100644 index 000000000..d64c51f77 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/StdHeader.cpp @@ -0,0 +1,134 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +* +* Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "CLucene/util/Misc.h" + +#include "CLucene/search/Sort.h" +#include "CLucene/search/Similarity.h" +#include "CLucene/search/FieldCache.h" +#include "CLucene/search/FieldSortedHitQueue.h" + +#if defined(_CLCOMPILER_MSVC) && defined(_DEBUG) +# define CRTDBG_MAP_ALLOC +# include +#ifndef UNDER_CE +# include +#endif +#endif + +CL_NS_USE(util) + +TCHAR* _LUCENE_BLANK_STRING = _T(""); +char* _LUCENE_BLANK_ASTRING = ""; + +#ifndef Q_CC_MIPS +#if defined(_LUCENE_THREADMUTEX_USINGDEFAULT) +# if defined(_LUCENE_PRAGMA_WARNINGS) +# pragma message ("==================Using clunky thread mutex!!!==================") +# else +# if !defined(Q_OS_SOLARIS) +# warning "==================Using clunky thread mutex!!!==================" +# endif +# endif +#endif + +#if defined(_ASCII) +# if defined(_LUCENE_PRAGMA_WARNINGS) +# pragma message ("==================Using ascii mode!!!==================") +# else +# if !defined(Q_OS_SOLARIS) +# warning "==================Using ascii mode!!!==================" +# endif +# endif +#endif + +//This causes confusion, because CLucene doesn't really need hashed maps/sets. My experience with the +//hash maps on linux are that there are no significant improvements in using them (infact it adversely +//affected performance... therefore we'll just silently ignore +/*#if defined(LUCENE_DISABLE_HASHING) +# if defined(_LUCENE_PRAGMA_WARNINGS) +# pragma message ("==================Hashing not available or is disabled! CLucene may run slower than optimal ==================") +# else +# if !defined(Q_OS_SOLARIS) +# warning "==================Hashing not available or is disabled! CLucene may run slower than optimal ==================" +# endif +# endif +#endif*/ +#endif + +//clears all static memory. do not attempt to do anything else +//in clucene after calling this function +void _lucene_shutdown(){ + CL_NS(search)::FieldSortedHitQueue::Comparators.clear(); + _CLDELETE(CL_NS(search)::Sort::RELEVANCE); + _CLDELETE(CL_NS(search)::Sort::INDEXORDER); + _CLDELETE(CL_NS(search)::ScoreDocComparator::INDEXORDER); + _CLDELETE(CL_NS(search)::ScoreDocComparator::RELEVANCE); + _CLDELETE(CL_NS(search)::SortField::FIELD_SCORE); + _CLDELETE(CL_NS(search)::SortField::FIELD_DOC); + _CLDELETE(CL_NS(search)::FieldCache::DEFAULT); + + _CLLDELETE(CL_NS(search)::Similarity::getDefault()); + + CL_NS(util)::CLStringIntern::shutdown(); +} + +void CLDebugBreak(){ + //can be used for debug breaking... +#if defined(_CLCOMPILER_MSVC) && defined(_DEBUG) + _CrtDbgBreak(); +#else + int i=0; //a line to put breakpoint on +#endif +} + +//these are functions that lucene uses which +//are not replacement functions +char* lucenestrdup(const char* v CL_FILELINEPARAM){ + size_t len = strlen(v); + char* ret = new char[len+1]; + strncpy(ret,v,len+1); +#if defined(LUCENE_ENABLE_MEMLEAKTRACKING) +# if defined(LUCENE_ENABLE_FILELINEINFO) + CL_NS(debug)::LuceneBase::__cl_voidpadd((void*)ret,file,line,len); +# else + CL_NS(debug)::LuceneBase::__cl_voidpadd((void*)ret,__FILE__,__LINE__,len); +# endif +#endif + return ret; +} + +#ifdef _UCS2 +wchar_t* lucenewcsdup(const wchar_t* v CL_FILELINEPARAM){ + size_t len = _tcslen(v); + wchar_t* ret = new wchar_t[len+1]; + _tcsncpy(ret,v,len+1); +#if defined(LUCENE_ENABLE_MEMLEAKTRACKING) +# if defined(LUCENE_ENABLE_FILELINEINFO) + CL_NS(debug)::LuceneBase::__cl_voidpadd((void*)ret,file,line,len); +# else + CL_NS(debug)::LuceneBase::__cl_voidpadd((void*)ret,__FILE__,__LINE__,len); +# endif +#endif + return ret; +} +#endif //ucs2 + + +//ok, these are the exceptions, but these never +//exist on non-msvc platform, so lets put it here +#ifndef _CL_HAVE_FILELENGTH +int64_t lucene_filelength(int filehandle) +{ + struct fileStat info; + if (fileHandleStat(filehandle, &info) == -1) + _CLTHROWA( CL_ERR_IO,"fileStat error" ); + return info.st_size; +} +#endif diff --git a/3rdparty/clucene/src/CLucene/StdHeader.h b/3rdparty/clucene/src/CLucene/StdHeader.h new file mode 100644 index 000000000..fbb3fd949 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/StdHeader.h @@ -0,0 +1,501 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +* +* Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +------------------------------------------------------------------------------*/ +#ifndef lucene_stdheader_h +#define lucene_stdheader_h + +#if defined(OVERRIDE_DEFAULT_CLCONFIG) + #include "AltCLConfig.h" +#else + #include "CLucene/CLConfig.h" +#endif + +//first inclusion of compiler.h (it will be called again later) +#include "CLucene/config/compiler.h" + +extern void _lucene_shutdown(); +extern int _lucene_counter_break; //can set a watch on this +#if defined(LUCENE_ENABLE_MEMLEAKTRACKING) + extern bool _lucene_disable_debuglogging; //if LUCENE_ENABLE_CONSTRUCTOR_LOG is on, dont do log if this is true +#endif + +//////////////////////////////////////////////////////// +// default includes +//////////////////////////////////////////////////////// +#ifndef LUCENE_DISABLE_INCLUDES + +#include + +#if defined(_CL_STDC_HEADERS) + #include + #include +#else + #if defined(_CL_HAVE_STDLIB_H) + #include + #endif +#endif + +#if defined(_CL_HAVE_STRING_H) + #if !defined(_CL_STDC_HEADERS) && defined(_CL_HAVE_MEMORY_H) + #include + #endif + #include +#elif defined(_CL_HAVE_STRINGS_H) + //note: as a side note, strtok is not thread-safe.. so be careful where you use it! + #error "strtok replacement for BSD has not been implemented" + #include + #if !defined(_CL_HAVE_STRCHR) + #define strchr index + #define strrchr rindex + #endif +#endif + +#if defined(_CL_HAVE_UNISTD_H) + #include +#elif defined(_CL_HAVE_IO_H) && defined(_CL_HAVE_DIRECT_H) +#ifndef UNDER_CE + #include + #include +#endif +#else + #error "Neither unistd.h or (io.h & direct.h) were available" +#endif + +#ifndef _CL_DISABLE_NATIVE_EXCEPTIONS + #ifdef _CL_HAVE_STDEXCEPT + #include + #else + #error "CLucene can't compile with exception handling on because header is not available" + #endif +#endif + +#if defined(_CL_STAT_MACROS_BROKEN) + #error "Haven't implemented STAT_MACROS_BROKEN fix yet" +#elif defined(_CL_HAVE_SYS_STAT_H) +#ifdef UNDER_CE + #include +#else + #include +#endif +#else + #error "Haven't implemented platforms with no sys/stat.h" +#endif + +#if defined(_CL_HAVE_STDARG_H) + #include +#else + #error "CLucene can compile, but some extras may not work" +#endif + +#if defined(_CL_HAVE_MATH_H) + #include +#else + #error "CLucene can't compile without " +#endif + +#if defined(_CL_HAVE_MAP) + #include +#else + #error "CLucene can't compile without the map header" +#endif + +#if defined(_CL_HAVE_LIST) + #include +#else + #error "CLucene can't compile without the list header" +#endif + +#if defined(_CL_HAVE_SET) + #include +#else + #error "CLucene can't compile without the set header" +#endif + +#if defined(_CL_HAVE_VECTOR) + #include +#else + #error "CLucene can't compile without the vector header" +#endif + +#if !defined(LUCENE_DISABLE_HASHING) && defined(_CL_HAVE_HASH_MAP) && defined(_CL_HAVE_HASH_SET) + //hashing is all or nothing! + #include + #include +#elif !defined(LUCENE_DISABLE_HASHING) && defined(_CL_HAVE_EXT_HASH_MAP) && defined(_CL_HAVE_EXT_HASH_SET) + #include + #include +#elif !defined(LUCENE_DISABLE_HASHING) + #define LUCENE_DISABLE_HASHING +#endif +#if !defined(LUCENE_DISABLE_HASHING) && !defined(CL_NS_HASHING) + #define CL_NS_HASHING(func) std::func +#endif + +#if defined(_CL_HAVE_ALGORITHM) +# include +#else +# error "Can't compile clucene without " +#endif + +#if defined(_CL_HAVE_FUNCTIONAL) +# include +#else +# error "Can't compile clucene without " +#endif + +#if !defined(_CL_HAVE_PRINTF) + #error "CLucene can't compile without printf, replacements have not been implemented" +#endif + +#if !defined(_CL_HAVE_SNPRINTF) && !defined(_CL_HAVE__SNPRINTF) + #error "CLucene can't compile without snprintf, replacements have not been implemented" +#elif !defined(_CL_HAVE__SNPRINTF)&& defined(_CL_HAVE_SVNPRINTF) + #define _snprintf snprintf +#endif + +#if defined(_UCS2) + #if defined(_CL_HAVE_WCHAR_H) + #include + #else + //actually the repl_wchar.h replacements header will + //always be included. It replaces some functions + //that are missing in some wchar.h headers. + #endif +#endif + +#if defined(_UCS2) && defined(_CL_HAVE_WCTYPE_H) + #include +#elif defined(_ASCII) && defined(_CL_HAVE_CTYPE_H) + #include + #undef LUCENE_USE_INTERNAL_CHAR_FUNCTIONS +#elif defined(_UCS2) + //must be in _UCS2 to use internal char functions + #undef LUCENE_USE_INTERNAL_CHAR_FUNCTIONS + #define LUCENE_USE_INTERNAL_CHAR_FUNCTIONS +#else + #error "Cannot compile in _ASCII without ctype.h" +#endif + +//always include replacement, some missing tchar defines +#include "CLucene/config/repl_tchar.h" + +#if defined(_CL_HAVE_ERRNO_H) +#ifndef UNDER_CE + #include +#endif +#else + #error "Haven't implemented platforms with no errno.h" +#endif + +#if defined(_CL_HAVE_FCNTL_H) +#ifndef UNDER_CE + #include +#endif +#else + #error "Haven't implemented platforms with no fcntl.h" +#endif + +#if defined(_CL_HAVE_WINDOWS_H) + #include +#endif + +#endif //LUCENE_DISABLE_INCLUDES +// +//////////////////////////////////////////////////////// + +//second inclusion of compiler.h +//this gives CompilerXXX.h a chance to include other headers +#include "CLucene/config/compiler.h" +// +//////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////// +// Character functions. +// Here we decide whose character functions to use +//////////////////////////////////////////////////////// +#if defined(LUCENE_USE_INTERNAL_CHAR_FUNCTIONS) + #define stringCaseFold cl_tcscasefold + #define stringCaseFoldCmp cl_tcscasefoldcmp + + #undef _istspace + #undef _istdigit + #undef _istalnum + #undef _istalpha + #undef _totlower + #undef _totupper + #define _istalnum cl_isalnum + #define _istalpha cl_isletter + #define _istspace cl_isspace + #define _istdigit cl_isdigit + #define _totlower cl_tolower + #define _totupper cl_toupper + + //here are some functions to help deal with utf8/ucs2 conversions + //lets let the user decide what mb functions to use... we provide pure utf8 ones no matter what. + /*#undef _mbtowc + #undef _mbstowcs + #undef _wctomb + #undef _wcstombs + #define _mbtowc lucene_mbstowc + #define _mbsstowcs lucene_mbstowcs + #define _wctomb lucene_wcto_mb + #define _wcstombs lucene_wcstombs*/ +#else + //we are using native functions + //here are some functions to help deal with utf8/ucs2 conversions + /*#define _mbtowc mbtowc + #define _wctomb wctomb + #define _mbstowcs mbstowcs + #define _wcstombs wcstombs*/ + + //we are using native character functions + #if defined(_ASCII) + #undef _istspace + #undef _istdigit + #undef _istalnum + #undef _istalpha + #undef _totlower + #undef _totupper + #define _istspace(x) isspace((unsigned char)x) + #define _istdigit(x) isdigit((unsigned char)x) + #define _istalnum(x) isalnum((unsigned char)x) + #define _istalpha(x) isalpha((unsigned char)x) + #define _totlower(x) tolower((unsigned char)x) + #define _totupper(x) toupper((unsigned char)x) + #endif +#endif + +//the methods contained in gunichartables.h +typedef unsigned long clunichar; +bool cl_isletter(clunichar c); +bool cl_isalnum(clunichar c); +bool cl_isdigit(clunichar c); +bool cl_isspace (clunichar c); +TCHAR cl_tolower (TCHAR c); +TCHAR cl_toupper (TCHAR c); + +int cl_tcscasefoldcmp(const TCHAR * dst, const TCHAR * src); +TCHAR* cl_tcscasefold( TCHAR * str, int len=-1 ); + +//we provide utf8 conversion functions +size_t lucene_utf8towc (wchar_t *ret, const char *s, size_t n); +size_t lucene_utf8towcs(wchar_t *, const char *, size_t maxslen); +size_t lucene_wctoutf8 (char * ret, const wchar_t str); +size_t lucene_wcstoutf8 (char *, const wchar_t *, size_t maxslen); +size_t lucene_utf8charlen(const char *p); + +///a blank string... +extern TCHAR* _LUCENE_BLANK_STRING; +#define LUCENE_BLANK_STRING _LUCENE_BLANK_STRING +extern char* _LUCENE_BLANK_ASTRING; +#define LUCENE_BLANK_ASTRING _LUCENE_BLANK_ASTRING + +/* Converts a string into a form that is independent of case. The + * result will not correspond to any particular case, but can be + * compared for equality or ordered with the results of calling + * stringCaseFold() on other strings. + * + * If we did not define this elsewhere, then just convert to lower case + */ +#ifndef stringCaseFold + #define stringCaseFold _tcslwr +#endif +/* Compares 2 strings using case folding (if available) + * If we did not define this elsewhere, then just compare + * using normal method + */ +#ifndef stringCaseFoldCmp + #define stringCaseFoldCmp _tcsicmp +#endif + +//now that all the character routines are completed, include the +//wchar.h replacements. +#include "CLucene/config/repl_wchar.h" //always include replacements + +//a replacement for _tcsdup. This uses new TCHAR[] instead of malloc, so that we can use delete[] to free +#if defined(LUCENE_ENABLE_FILELINEINFO) + #define CL_FILELINE ,__FILE__,__LINE__ + #define CL_FILELINEREF ,file,line /// StringArray; +typedef CL_NS(util)::CLVector StringArrayWithDeletor; +typedef CL_NS(util)::CLVector StringArrayConst; +typedef CL_NS(util)::CLVector StringArrayConstWithDeletor; + +typedef CL_NS(util)::CLVector AStringArray; +typedef CL_NS(util)::CLVector AStringArrayWithDeletor; +typedef CL_NS(util)::CLVector AStringArrayConst; +typedef CL_NS(util)::CLVector AStringArrayConstWithDeletor; +CL_NS_END + +// +//////////////////////////////////////////////////////// + +#endif // STDHEADER_H diff --git a/3rdparty/clucene/src/CLucene/analysis/AnalysisHeader.cpp b/3rdparty/clucene/src/CLucene/analysis/AnalysisHeader.cpp new file mode 100644 index 000000000..03f61a038 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/analysis/AnalysisHeader.cpp @@ -0,0 +1,200 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "AnalysisHeader.h" +#include "CLucene/util/StringBuffer.h" + +CL_NS_USE(util) +CL_NS_DEF(analysis) + +const TCHAR* Token::defaultType=_T("word"); + +Token::Token(): + _startOffset (0), + _endOffset (0), + _type ( defaultType ), + positionIncrement (1) +{ + _termTextLen = 0; +#ifndef LUCENE_TOKEN_WORD_LENGTH + _termText = NULL; + bufferTextLen = 0; +#else + _termText[0] = 0; //make sure null terminated + bufferTextLen = LUCENE_TOKEN_WORD_LENGTH+1; +#endif +} + +Token::~Token(){ +#ifndef LUCENE_TOKEN_WORD_LENGTH + free(_termText); +#endif +} + +Token::Token(const TCHAR* text, const int32_t start, const int32_t end, const TCHAR* typ): + _startOffset (start), + _endOffset (end), + _type ( typ ), + positionIncrement (1) +{ + _termTextLen = 0; +#ifndef LUCENE_TOKEN_WORD_LENGTH + _termText = NULL; + bufferTextLen = 0; +#else + _termText[0] = 0; //make sure null terminated + bufferTextLen = LUCENE_TOKEN_WORD_LENGTH+1; +#endif + setText(text); +} + +void Token::set(const TCHAR* text, const int32_t start, const int32_t end, const TCHAR* typ){ + _startOffset = start; + _endOffset = end; + _type = typ; + positionIncrement = 1; + setText(text); +} + +void Token::setText(const TCHAR* text){ + _termTextLen = _tcslen(text); + +#ifndef LUCENE_TOKEN_WORD_LENGTH + growBuffer(_termTextLen+1); + _tcsncpy(_termText,text,_termTextLen+1); +#else + if ( _termTextLen > LUCENE_TOKEN_WORD_LENGTH ){ + //in the case where this occurs, we will leave the endOffset as it is + //since the actual word still occupies that space. + _termTextLen=LUCENE_TOKEN_WORD_LENGTH; + } + _tcsncpy(_termText,text,_termTextLen+1); +#endif + _termText[_termTextLen] = 0; //make sure null terminated +} + +void Token::growBuffer(size_t size){ + if(bufferTextLen>=size) + return; +#ifndef LUCENE_TOKEN_WORD_LENGTH + if ( _termText == NULL ) + _termText = (TCHAR*)malloc( size * sizeof(TCHAR) ); + else + _termText = (TCHAR*)realloc( _termText, size * sizeof(TCHAR) ); + bufferTextLen = size; +#else + _CLTHROWA(CL_ERR_TokenMgr,"Couldn't grow Token buffer"); +#endif +} + +void Token::setPositionIncrement(int32_t posIncr) { + if (posIncr < 0) { + _CLTHROWA(CL_ERR_IllegalArgument,"positionIncrement must be >= 0"); + } + positionIncrement = posIncr; +} + +int32_t Token::getPositionIncrement() const { return positionIncrement; } + +// Returns the Token's term text. +const TCHAR* Token::termText() const{ + return (const TCHAR*) _termText; +} +size_t Token::termTextLength() { + if ( _termTextLen == -1 ) //it was invalidated by growBuffer + _termTextLen = _tcslen(_termText); + return _termTextLen; +} +void Token::resetTermTextLen(){ + _termTextLen=-1; +} +bool Token::OrderCompare::operator()( Token* t1, Token* t2 ) const{ + if(t1->startOffset()>t2->startOffset()) + return false; + if(t1->startOffset()startOffset()) + return true; + return true; +} +TCHAR* Token::toString() const{ + StringBuffer sb; + sb.append(_T("(")); + sb.append( _termText ); + sb.append(_T(",")); + sb.appendInt( _startOffset ); + sb.append(_T(",")); + sb.appendInt( _endOffset ); + + if (!_tcscmp( _type, _T("word")) == 0 ){ + sb.append(_T(",type=")); + sb.append(_type); + } + if (positionIncrement != 1){ + sb.append(_T(",posIncr=")); + sb.appendInt(positionIncrement); + } + sb.append(_T(")")); + + return sb.toString(); +} + + +Token* TokenStream::next(){ + Token* t = _CLNEW Token; //deprecated + if ( !next(t) ) + _CLDELETE(t); + return t; +} + + +TokenFilter::TokenFilter(TokenStream* in, bool deleteTS): + input(in), + deleteTokenStream(deleteTS) +{ +} +TokenFilter::~TokenFilter(){ + close(); +} + +// Close the input TokenStream. +void TokenFilter::close() { + if ( input != NULL ){ + input->close(); + if ( deleteTokenStream ) + _CLDELETE( input ); + } + input = NULL; +} + + + +Tokenizer::Tokenizer() { + input = NULL; +} + +Tokenizer::Tokenizer(CL_NS(util)::Reader* _input): + input(_input) +{ +} + +void Tokenizer::close(){ + if (input != NULL) { + // ? delete input; + input = NULL; + } +} + +Tokenizer::~Tokenizer(){ + close(); +} + + +int32_t Analyzer::getPositionIncrementGap(const TCHAR* fieldName) +{ + return 0; +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/analysis/AnalysisHeader.h b/3rdparty/clucene/src/CLucene/analysis/AnalysisHeader.h new file mode 100644 index 000000000..0cfd9c684 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/analysis/AnalysisHeader.h @@ -0,0 +1,234 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_analysis_AnalysisHeader_ +#define _lucene_analysis_AnalysisHeader_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/util/Reader.h" + +CL_NS_DEF(analysis) + + +/** A Token is an occurence of a term from the text of a field. It consists of +* a term's text, the start and end offset of the term in the text of the field, +* and a type string. +* +* The start and end offsets permit applications to re-associate a token with +* its source text, e.g., to display highlighted query terms in a document +* browser, or to show matching text fragments in a KWIC (KeyWord In Context) +* display, etc. +* +* The type is an interned string, assigned by a lexical analyzer +* (a.k.a. tokenizer), naming the lexical or syntactic class that the token +* belongs to. For example an end of sentence marker token might be implemented +* with type "eos". The default token type is "word". +*/ +class Token:LUCENE_BASE{ +private: + int32_t _startOffset; // start in source text + int32_t _endOffset; // end in source text + const TCHAR* _type; // lexical type + int32_t positionIncrement; + size_t bufferTextLen; + +public: + #ifndef LUCENE_TOKEN_WORD_LENGTH + TCHAR* _termText; // the text of the term + #else + TCHAR _termText[LUCENE_TOKEN_WORD_LENGTH+1]; // the text of the term + #endif + int32_t _termTextLen; + static const TCHAR* defaultType; + + Token(); + ~Token(); + // Constructs a Token with the given text, start and end offsets, & type. + Token(const TCHAR* text, const int32_t start, const int32_t end, const TCHAR* typ=defaultType); + void set(const TCHAR* text, const int32_t start, const int32_t end, const TCHAR* typ=defaultType); + + size_t bufferLength(){ return bufferTextLen; } + void growBuffer(size_t size); + + /* Set the position increment. This determines the position of this + * token relative to the previous Token in a TokenStream, used in + * phrase searching. + * + * The default value is 1. + * + * Some common uses for this are: + * + * - Set it to zero to put multiple terms in the same position. This is + * useful if, e.g., a word has multiple stems. Searches for phrases + * including either stem will match. In this case, all but the first stem's + * increment should be set to zero: the increment of the first instance + * should be one. Repeating a token with an increment of zero can also be + * used to boost the scores of matches on that token. + * + * - Set it to values greater than one to inhibit exact phrase matches. + * If, for example, one does not want phrases to match across removed stop + * words, then one could build a stop word filter that removes stop words and + * also sets the increment to the number of stop words removed before each + * non-stop word. Then exact phrase queries will only match when the terms + * occur with no intervening stop words. + */ + void setPositionIncrement(int32_t posIncr); + int32_t getPositionIncrement() const; + const TCHAR* termText() const; + size_t termTextLength(); + void resetTermTextLen(); + void setText(const TCHAR* txt); + + /** + * Returns this Token's starting offset, the position of the first character + * corresponding to this token in the source text. + * + * Note that the difference between endOffset() and startOffset() may not be + * equal to termText.length(), as the term text may have been altered by a + * stemmer or some other filter. + */ + int32_t startOffset() const { return _startOffset; } + void setStartOffset(int32_t val){ _startOffset =val; } + + /** + * Returns this Token's ending offset, one greater than the position of the + * last character corresponding to this token in the source text. + */ + int32_t endOffset() const { return _endOffset; } + void setEndOffset(int32_t val){ _endOffset =val; } + + // Returns this Token's lexical type. Defaults to "word". + const TCHAR* type() const { return _type; } /// + { + public: + bool operator()( Token* t1, Token* t2 ) const; + }; +}; + +/** +* A TokenStream enumerates the sequence of tokens, either from +* fields of a document or from query text. +*

+* This is an abstract class. Concrete subclasses are: +*

    +*
  • {@link Tokenizer}, a TokenStream +* whose input is a Reader; and +*
  • {@link TokenFilter}, a TokenStream +* whose input is another TokenStream. +*
+*/ +class TokenStream:LUCENE_BASE { +public: + /** Sets token to the next token in the stream, returns false at the EOS. */ + virtual bool next(Token* token) = 0; + + /** Releases resources associated with this stream. */ + virtual void close() = 0; + + virtual ~TokenStream(){ + } + + /* This is for backwards compatibility only. You should pass the token you want to fill + * to next(), this will save a lot of object construction and destructions. + * @deprecated. use next(token). Kept only to avoid breaking existing code. + */ + _CL_DEPRECATED(next(Token)) Token* next(); +}; + + +/** An Analyzer builds TokenStreams, which analyze text. It thus represents a + * policy for extracting index terms from text. + *

+ * Typical implementations first build a Tokenizer, which breaks the stream of + * characters from the Reader into raw Tokens. One or more TokenFilters may + * then be applied to the output of the Tokenizer. + *

+ * WARNING: You must override one of the methods defined by this class in your + * subclass or the Analyzer will enter an infinite loop. + */ +class Analyzer:LUCENE_BASE{ +public: + /** Creates a TokenStream which tokenizes all the text in the provided + Reader. Default implementation forwards to tokenStream(Reader) for + compatibility with older version. Override to allow Analyzer to choose + strategy based on document and/or field. Must be able to handle null + field name for backward compatibility. */ + virtual TokenStream* tokenStream(const TCHAR* fieldName, CL_NS(util)::Reader* reader)=0; + + virtual ~Analyzer(){ + } + + /** + * Invoked before indexing a Field instance if + * terms have already been added to that field. This allows custom + * analyzers to place an automatic position increment gap between + * Field instances using the same field name. The default value + * position increment gap is 0. With a 0 position increment gap and + * the typical default token position increment of 1, all terms in a field, + * including across Field instances, are in successive positions, allowing + * exact PhraseQuery matches, for instance, across Field instance boundaries. + * + * @param fieldName Field name being indexed. + * @return position increment gap, added to the next token emitted from {@link #tokenStream(TCHAR*, Reader*)} + */ + virtual int32_t getPositionIncrementGap(const TCHAR* fieldName); +}; + + +/** A Tokenizer is a TokenStream whose input is a Reader. +

+This is an abstract class. +*/ +class Tokenizer:public TokenStream { +protected: + /** The text source for this Tokenizer. */ + CL_NS(util)::Reader* input; + +public: + /** Construct a tokenizer with null input. */ + Tokenizer(); + /** Construct a token stream processing the given input. */ + Tokenizer(CL_NS(util)::Reader* _input); + + // ** By default, closes the input Reader. */ + virtual void close(); + virtual ~Tokenizer(); +}; + +/** A TokenFilter is a TokenStream whose input is another token stream. +

+This is an abstract class. +*/ +class TokenFilter:public TokenStream { +protected: + /** The source of tokens for this filter. */ + TokenStream* input; + /** If true then input will be deleted in the destructor */ + bool deleteTokenStream; + + /** Construct a token stream filtering the given input. + * + * @param in The TokenStream to filter from + * @param deleteTS If true, input will be deleted in the destructor + */ + TokenFilter(TokenStream* in, bool deleteTS=false); + virtual ~TokenFilter(); +public: + /** Close the input TokenStream. */ + void close(); +}; + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/analysis/Analyzers.cpp b/3rdparty/clucene/src/CLucene/analysis/Analyzers.cpp new file mode 100644 index 000000000..142bbfb63 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/analysis/Analyzers.cpp @@ -0,0 +1,389 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +* +* Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "Analyzers.h" +#include "CLucene/util/StringBuffer.h" + +CL_NS_USE(util) +CL_NS_DEF(analysis) + +CharTokenizer::CharTokenizer(Reader* in) : + Tokenizer(in), + offset(0), + bufferIndex(0), + dataLen(0), + ioBuffer(NULL) +{ + buffer[0]=0; +} + +TCHAR CharTokenizer::normalize(const TCHAR c) const +{ + return c; +} +bool CharTokenizer::next(Token* token){ + int32_t length = 0; + int32_t start = offset; + while (true) { + TCHAR c; + offset++; + if (bufferIndex >= dataLen) { + dataLen = input->read(ioBuffer, LUCENE_IO_BUFFER_SIZE); + if (dataLen == -1) + dataLen = 0; + bufferIndex = 0; + } + if (dataLen <= 0 ) { + if (length > 0) + break; + else + return false; + }else + c = ioBuffer[bufferIndex++]; + if (isTokenChar(c)) { // if it's a token TCHAR + + if (length == 0) // start of token + start = offset-1; + + buffer[length++] = normalize(c); // buffer it, normalized + + if (length == LUCENE_MAX_WORD_LEN) // buffer overflow! + break; + + } else if (length > 0) // at non-Letter w/ chars + break; // return 'em + + } + buffer[length]=0; + token->set( buffer, start, start+length); + return true; +} + +bool LetterTokenizer::isTokenChar(const TCHAR c) const { + return _istalpha(c)!=0; +} + + +TCHAR LowerCaseTokenizer::normalize(const TCHAR chr) const { + return _totlower(chr); +} + +bool WhitespaceTokenizer::isTokenChar(const TCHAR c) const{ + return _istspace(c)==0; //(return true if NOT a space) +} + +TokenStream* WhitespaceAnalyzer::tokenStream(const TCHAR* fieldName, Reader* reader) { + return _CLNEW WhitespaceTokenizer(reader); +} + +TokenStream* SimpleAnalyzer::tokenStream(const TCHAR* fieldName, Reader* reader) { + return _CLNEW LowerCaseTokenizer(reader); +} + +bool LowerCaseFilter::next(Token* t){ + if (!input->next(t)) + return false; + stringCaseFold( t->_termText ); + return true; +} + +StopFilter::StopFilter(TokenStream* in, bool deleteTokenStream, const TCHAR** stopWords): + TokenFilter(in, deleteTokenStream), + table(_CLNEW CLSetList(false)) +{ + fillStopTable( table,stopWords ); +} + +void StopFilter::fillStopTable(CLSetList* stopTable, + const TCHAR** stopWords) { + for (int32_t i = 0; stopWords[i]!=NULL; i++) + stopTable->insert(stopWords[i]); +} + +bool StopFilter::next(Token* token) { + // return the first non-stop word found + while (input->next(token)){ + if (table->find(token->_termText)==table->end()){ + return true; + } + } + + // reached EOS -- return nothing + return false; +} + +StopAnalyzer::StopAnalyzer():stopTable(false) +{ + StopFilter::fillStopTable(&stopTable,ENGLISH_STOP_WORDS); +} +StopAnalyzer::~StopAnalyzer() +{ +} +StopAnalyzer::StopAnalyzer( const TCHAR** stopWords) { + StopFilter::fillStopTable(&stopTable,stopWords); +} +TokenStream* StopAnalyzer::tokenStream(const TCHAR* fieldName, Reader* reader) { + return _CLNEW StopFilter(_CLNEW LowerCaseTokenizer(reader),true, &stopTable); +} + +const TCHAR* StopAnalyzer::ENGLISH_STOP_WORDS[] = +{ + _T("a"), _T("an"), _T("and"), _T("are"), _T("as"), _T("at"), _T("be"), _T("but"), _T("by"), + _T("for"), _T("if"), _T("in"), _T("into"), _T("is"), _T("it"), + _T("no"), _T("not"), _T("of"), _T("on"), _T("or"), _T("s"), _T("such"), + _T("t"), _T("that"), _T("the"), _T("their"), _T("then"), _T("there"), _T("these"), + _T("they"), _T("this"), _T("to"), _T("was"), _T("will"), _T("with"), NULL +}; + +PerFieldAnalyzerWrapper::PerFieldAnalyzerWrapper(Analyzer* defaultAnalyzer): + analyzerMap(true,true) +{ + this->defaultAnalyzer = defaultAnalyzer; +} +PerFieldAnalyzerWrapper::~PerFieldAnalyzerWrapper(){ + analyzerMap.clear(); + _CLDELETE(defaultAnalyzer); +} + +void PerFieldAnalyzerWrapper::addAnalyzer(const TCHAR* fieldName, Analyzer* analyzer) { + analyzerMap.put(STRDUP_TtoT(fieldName), analyzer); +} + +TokenStream* PerFieldAnalyzerWrapper::tokenStream(const TCHAR* fieldName, Reader* reader) { + Analyzer* analyzer = (fieldName==NULL?defaultAnalyzer:analyzerMap.get(fieldName)); + if (analyzer == NULL) { + analyzer = defaultAnalyzer; + } + + return analyzer->tokenStream(fieldName, reader); +} + + + +bool ISOLatin1AccentFilter::next(Token* token){ + if ( input->next(token) ){ + int32_t l = token->termTextLength(); + const TCHAR* chars = token->termText(); + bool doProcess = false; + for (int32_t i = 0; i < l; ++i) { +#ifdef _UCS2 + if ( chars[i] >= 0xC0 && chars[i] <= 0x178 ) { +#else + if ( (chars[i] >= 0xC0 && chars[i] <= 0xFF) || chars[i] < 0 ) { +#endif + doProcess = true; + break; + } + } + if ( !doProcess ) { + return true; + } + + StringBuffer output(l*2); + for (int32_t j = 0; j < l; j++) { + #ifdef _UCS2 + TCHAR c = chars[j]; + #else + unsigned char c = chars[j]; + #endif + switch (c) { + case 0xC0 : + case 0xC1 : + case 0xC2 : + case 0xC3 : + case 0xC4 : + case 0xC5 : + output.appendChar('A'); + break; + case 0xC6 : + output.append(_T("AE")); + break; + case 0xC7 : + output.appendChar('C'); + break; + case 0xC8 : + case 0xC9 : + case 0xCA : + case 0xCB : + output.appendChar('E'); + break; + case 0xCC : + case 0xCD : + case 0xCE : + case 0xCF : + output.appendChar('I'); + break; + case 0xD0 : + output.appendChar('D'); + break; + case 0xD1 : + output.appendChar('N'); + break; + case 0xD2 : + case 0xD3 : + case 0xD4 : + case 0xD5 : + case 0xD6 : + case 0xD8 : + output.appendChar('O'); + break; + case 0xDE : + output.append(_T("TH")); + break; + case 0xD9 : + case 0xDA : + case 0xDB : + case 0xDC : + output.appendChar('U'); + break; + case 0xDD : + output.appendChar('Y'); + break; + case 0xE0 : + case 0xE1 : + case 0xE2 : + case 0xE3 : + case 0xE4 : + case 0xE5 : + output.appendChar('a'); + break; + case 0xE6 : + output.append(_T("ae")); + break; + case 0xE7 : + output.appendChar('c'); + break; + case 0xE8 : + case 0xE9 : + case 0xEA : + case 0xEB : + output.appendChar('e'); + break; + case 0xEC : + case 0xED : + case 0xEE : + case 0xEF : + output.appendChar('i'); + break; + case 0xF0 : + output.appendChar('d'); + break; + case 0xF1 : + output.appendChar('n'); + break; + case 0xF2 : + case 0xF3 : + case 0xF4 : + case 0xF5 : + case 0xF6 : + case 0xF8 : + output.appendChar('o'); + break; + case 0xDF : + output.append(_T("ss")); + break; + case 0xFE : + output.append(_T("th")); + break; + case 0xF9 : + case 0xFA : + case 0xFB : + case 0xFC : + output.appendChar('u'); + break; + case 0xFD : + case 0xFF : + output.appendChar('y'); + break; + + #ifdef _UCS2 + case 0x152 : + output.append(_T("OE")); + break; + case 0x153 : + output.append(_T("oe")); + break; + case 0x178 : + output.appendChar('Y'); + break; + #endif + default : + output.appendChar(c); + break; + } + } + token->setText(output.getBuffer()); + return true; + } + return false; +} + + +TokenStream* KeywordAnalyzer::tokenStream(const TCHAR* fieldName, CL_NS(util)::Reader* reader){ + return _CLNEW KeywordTokenizer(reader); +} + +KeywordTokenizer::KeywordTokenizer(CL_NS(util)::Reader* input, int bufferSize): + Tokenizer(input) +{ + this->done = false; + if ( bufferSize < 0 ) + this->bufferSize = DEFAULT_BUFFER_SIZE; +} +KeywordTokenizer::~KeywordTokenizer(){ +} + +bool KeywordTokenizer::next(Token* token){ + if (!done) { + done = true; + int32_t rd; + const TCHAR* buffer=0; + while (true) { + rd = input->read(buffer, bufferSize); + if (rd == -1) + break; + token->growBuffer(token->_termTextLen +rd+1); + + int32_t cp = rd; + if ( token->_termTextLen + cp > token->bufferLength() ) + cp = token->bufferLength() - token->_termTextLen; + _tcsncpy(token->_termText+token->_termTextLen,buffer,cp); + token->_termTextLen+=rd; + } + token->_termText[token->_termTextLen]=0; + token->set(token->_termText,0,token->_termTextLen); + return true; + } + return false; +} + + +LengthFilter::LengthFilter(TokenStream* in, int _min, int _max): + TokenFilter(in) +{ + this->_min = _min; + this->_max = _max; +} + +bool LengthFilter::next(Token* token) +{ + // return the first non-stop word found + while ( input->next(token) ) + { + size_t len = token->termTextLength(); + if (len >= _min && len <= _max) + return true; + // note: else we ignore it but should we index each part of it? + } + // reached EOS -- return null + return false; +} + + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/analysis/Analyzers.h b/3rdparty/clucene/src/CLucene/analysis/Analyzers.h new file mode 100644 index 000000000..a12bd653f --- /dev/null +++ b/3rdparty/clucene/src/CLucene/analysis/Analyzers.h @@ -0,0 +1,309 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_analysis_Analyzers_ +#define _lucene_analysis_Analyzers_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/util/Reader.h" +#include "AnalysisHeader.h" +#include "CLucene/util/Misc.h" + +CL_NS_DEF(analysis) + +/** An abstract base class for simple, character-oriented tokenizers.*/ +class CharTokenizer:public Tokenizer { +private: + int32_t offset, bufferIndex, dataLen; + TCHAR buffer[LUCENE_MAX_WORD_LEN+1]; + const TCHAR* ioBuffer; +protected: + + /** Returns true iff a character should be included in a token. This + * tokenizer generates as tokens adjacent sequences of characters which + * satisfy this predicate. Characters for which this is false are used to + * define token boundaries and are not included in tokens. */ + virtual bool isTokenChar(const TCHAR c) const = 0; + + /** Called on each token character to normalize it before it is added to the + * token. The default implementation does nothing. Subclasses may use this + * to, e.g., lowercase tokens. */ + virtual TCHAR normalize(const TCHAR c) const; + +public: + CharTokenizer(CL_NS(util)::Reader* in); + virtual ~CharTokenizer(){ + } + bool next(Token* token); +}; + + +/** A LetterTokenizer is a tokenizer that divides text at non-letters. That's +to say, it defines tokens as maximal strings of adjacent letters, as defined +by java.lang.Character.isLetter() predicate. + +Note: this does a decent job for most European languages, but does a terrible +job for some Asian languages, where words are not separated by spaces. */ +class LetterTokenizer:public CharTokenizer { +public: + // Construct a new LetterTokenizer. + LetterTokenizer(CL_NS(util)::Reader* in): + CharTokenizer(in) {} + + ~LetterTokenizer(){} +protected: + /** Collects only characters which satisfy _istalpha.*/ + bool isTokenChar(const TCHAR c) const; +}; + + + +/** +* LowerCaseTokenizer performs the function of LetterTokenizer +* and LowerCaseFilter together. It divides text at non-letters and converts +* them to lower case. While it is functionally equivalent to the combination +* of LetterTokenizer and LowerCaseFilter, there is a performance advantage +* to doing the two tasks at once, hence this (redundant) implementation. +*

+* Note: this does a decent job for most European languages, but does a terrible +* job for some Asian languages, where words are not separated by spaces. +*/ +class LowerCaseTokenizer:public LetterTokenizer { +public: + /** Construct a new LowerCaseTokenizer. */ + LowerCaseTokenizer(CL_NS(util)::Reader* in): + LetterTokenizer(in) {} + + ~LowerCaseTokenizer(){} +protected: + /** Collects only characters which satisfy _totlower. */ + TCHAR normalize(const TCHAR chr) const; +}; + + +/** A WhitespaceTokenizer is a tokenizer that divides text at whitespace. + * Adjacent sequences of non-Whitespace characters form tokens. */ +class WhitespaceTokenizer: public CharTokenizer { +public: + /** Construct a new WhitespaceTokenizer. */ + WhitespaceTokenizer(CL_NS(util)::Reader* in):CharTokenizer(in) {} + ~WhitespaceTokenizer(){} +protected: + /** Collects only characters which do not satisfy _istspace. + */ + bool isTokenChar(const TCHAR c) const; +}; + + +/** An Analyzer that uses WhitespaceTokenizer. */ +class WhitespaceAnalyzer: public Analyzer { + public: + TokenStream* tokenStream(const TCHAR* fieldName, CL_NS(util)::Reader* reader); + ~WhitespaceAnalyzer(){} +}; + +/** An Analyzer that filters LetterTokenizer with LowerCaseFilter. */ +class SimpleAnalyzer: public Analyzer { +public: + TokenStream* tokenStream(const TCHAR* fieldName, CL_NS(util)::Reader* reader); + ~SimpleAnalyzer(){} +}; + + + +/** +* Normalizes token text to lower case. +*/ +class LowerCaseFilter: public TokenFilter { +public: + LowerCaseFilter(TokenStream* in, bool deleteTokenStream):TokenFilter(in,deleteTokenStream) {} + ~LowerCaseFilter(){} + bool next(Token* token); +}; + + +/** + * Removes stop words from a token stream. + */ +class StopFilter: public TokenFilter { +private: + //bvk: i found this to work faster with a non-hash table. the number of items + //in the stop table is not like to make it worth having hashing. + CL_NS(util)::CLSetList* table; +public: + // Constructs a filter which removes words from the input + // TokenStream that are named in the array of words. + StopFilter(TokenStream* in, bool deleteTokenStream, const TCHAR** stopWords); + + ~StopFilter(){} + + /** Constructs a filter which removes words from the input + * TokenStream that are named in the CLSetList. + */ + StopFilter(TokenStream* in, bool deleteTokenStream, CL_NS(util)::CLSetList* stopTable): + TokenFilter(in, deleteTokenStream), + table(stopTable) + {} + + + /** + * Builds a Hashtable from an array of stop words, appropriate for passing + * into the StopFilter constructor. This permits this table construction to + * be cached once when an Analyzer is constructed. + * Note: the stopWords list must be a static list because the strings are not copied + */ + static void fillStopTable(CL_NS(util)::CLSetList* stopTable, + const TCHAR** stopWords); + + /** + * Returns the next input Token whose termText() is not a stop word. + */ + bool next(Token* token); +}; + + + + +/** Filters LetterTokenizer with LowerCaseFilter and StopFilter. */ +class StopAnalyzer: public Analyzer { + CL_NS(util)::CLSetList stopTable; + +public: + /** Builds an analyzer which removes words in ENGLISH_STOP_WORDS. */ + StopAnalyzer(); + ~StopAnalyzer(); + + /** Builds an analyzer which removes words in the provided array. */ + StopAnalyzer( const TCHAR** stopWords ); + /** Filters LowerCaseTokenizer with StopFilter. */ + TokenStream* tokenStream(const TCHAR* fieldName, CL_NS(util)::Reader* reader); + + /** An array containing some common English words that are not usually useful + for searching. */ + static const TCHAR* ENGLISH_STOP_WORDS[]; +}; + + + +/** + * This analyzer is used to facilitate scenarios where different + * fields require different analysis techniques. Use {@link #addAnalyzer} + * to add a non-default analyzer on a field name basis. + * + *

Example usage: + * + *

+ *   PerFieldAnalyzerWrapper aWrapper =
+ *      new PerFieldAnalyzerWrapper(new StandardAnalyzer());
+ *   aWrapper.addAnalyzer("firstname", new KeywordAnalyzer());
+ *   aWrapper.addAnalyzer("lastname", new KeywordAnalyzer());
+ * 
+ * + *

In this example, StandardAnalyzer will be used for all fields except "firstname" + * and "lastname", for which KeywordAnalyzer will be used. + * + *

A PerFieldAnalyzerWrapper can be used like any other analyzer, for both indexing + * and query parsing. + */ +class PerFieldAnalyzerWrapper : public Analyzer { +private: + Analyzer* defaultAnalyzer; + CL_NS(util)::CLHashMap > analyzerMap; +public: + /** + * Constructs with default analyzer. + * + * @param defaultAnalyzer Any fields not specifically + * defined to use a different analyzer will use the one provided here. + */ + PerFieldAnalyzerWrapper(Analyzer* defaultAnalyzer); + ~PerFieldAnalyzerWrapper(); + + /** + * Defines an analyzer to use for the specified field. + * + * @param fieldName field name requiring a non-default analyzer + * @param analyzer non-default analyzer to use for field + */ + void addAnalyzer(const TCHAR* fieldName, Analyzer* analyzer); + TokenStream* tokenStream(const TCHAR* fieldName, CL_NS(util)::Reader* reader); +}; + + +/** + * A filter that replaces accented characters in the ISO Latin 1 character set + * (ISO-8859-1) by their unaccented equivalent. The case will not be altered. + *

+ * For instance, 'à' will be replaced by 'a'. + *

+ */ +class ISOLatin1AccentFilter: public TokenFilter { +public: + ISOLatin1AccentFilter(TokenStream* input, bool deleteTs): + TokenFilter(input,deleteTs) + { + } + + /** + * To replace accented characters in a String by unaccented equivalents. + */ + bool next(Token* token); +}; + + +/** + * Emits the entire input as a single token. + */ +class KeywordTokenizer: public Tokenizer { +private: + LUCENE_STATIC_CONSTANT(int, DEFAULT_BUFFER_SIZE = 256); + bool done; + int bufferSize; +public: + KeywordTokenizer(CL_NS(util)::Reader* input, int bufferSize=-1); + virtual ~KeywordTokenizer(); + bool next(Token* token); +}; + +/** + * "Tokenizes" the entire stream as a single token. This is useful + * for data like zip codes, ids, and some product names. + */ +class KeywordAnalyzer: public Analyzer { +public: + TokenStream* tokenStream(const TCHAR* fieldName, CL_NS(util)::Reader* reader); + virtual ~KeywordAnalyzer(){} +}; + + +/** + * Removes words that are too long and too short from the stream. + * + */ +class LengthFilter: public TokenFilter { +private: + int _min; + int _max; +public: + /** + * Build a filter that removes words that are too long or too + * short from the text. + */ + LengthFilter(TokenStream* in, int _min, int _max); + + /** + * Returns the next input Token whose termText() is the right len + */ + bool next(Token* token); +}; + + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/analysis/standard/StandardAnalyzer.cpp b/3rdparty/clucene/src/CLucene/analysis/standard/StandardAnalyzer.cpp new file mode 100644 index 000000000..e0994c41a --- /dev/null +++ b/3rdparty/clucene/src/CLucene/analysis/standard/StandardAnalyzer.cpp @@ -0,0 +1,46 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "StandardAnalyzer.h" + +#include "CLucene/util/VoidMap.h" +#include "CLucene/util/Reader.h" +#include "CLucene/analysis/AnalysisHeader.h" +#include "CLucene/analysis/Analyzers.h" +#include "StandardFilter.h" +#include "StandardTokenizer.h" + +CL_NS_USE(util) +CL_NS_USE(analysis) + +CL_NS_DEF2(analysis,standard) + + StandardAnalyzer::StandardAnalyzer(): + stopSet(false) + { + StopFilter::fillStopTable( &stopSet,CL_NS(analysis)::StopAnalyzer::ENGLISH_STOP_WORDS); + } + + StandardAnalyzer::StandardAnalyzer( const TCHAR** stopWords): + stopSet(false) + { + StopFilter::fillStopTable( &stopSet,stopWords ); + } + + StandardAnalyzer::~StandardAnalyzer(){ + } + + + TokenStream* StandardAnalyzer::tokenStream(const TCHAR* fieldName, Reader* reader) + { + TokenStream* ret = _CLNEW StandardTokenizer(reader); + ret = _CLNEW StandardFilter(ret,true); + ret = _CLNEW LowerCaseFilter(ret,true); + ret = _CLNEW StopFilter(ret,true, &stopSet); + return ret; + } +CL_NS_END2 diff --git a/3rdparty/clucene/src/CLucene/analysis/standard/StandardAnalyzer.h b/3rdparty/clucene/src/CLucene/analysis/standard/StandardAnalyzer.h new file mode 100644 index 000000000..9cce041df --- /dev/null +++ b/3rdparty/clucene/src/CLucene/analysis/standard/StandardAnalyzer.h @@ -0,0 +1,47 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_analysis_standard_StandardAnalyzer +#define _lucene_analysis_standard_StandardAnalyzer + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/util/VoidMap.h" +#include "CLucene/util/Reader.h" +#include "CLucene/analysis/AnalysisHeader.h" +#include "CLucene/analysis/Analyzers.h" +#include "StandardFilter.h" +#include "StandardTokenizer.h" + + +CL_NS_DEF2(analysis,standard) + + /** Represents a standard analyzer. */ + class StandardAnalyzer : public Analyzer + { + private: + CL_NS(util)::CLSetList stopSet; + public: + /** Builds an analyzer.*/ + StandardAnalyzer(); + + /** Builds an analyzer with the given stop words. */ + StandardAnalyzer( const TCHAR** stopWords); + + ~StandardAnalyzer(); + + + /** + * Constructs a StandardTokenizer filtered by a + * StandardFilter, a LowerCaseFilter and a StopFilter. + */ + TokenStream* tokenStream(const TCHAR* fieldName, CL_NS(util)::Reader* reader) + ; + }; +CL_NS_END2 +#endif diff --git a/3rdparty/clucene/src/CLucene/analysis/standard/StandardFilter.cpp b/3rdparty/clucene/src/CLucene/analysis/standard/StandardFilter.cpp new file mode 100644 index 000000000..9869d2592 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/analysis/standard/StandardFilter.cpp @@ -0,0 +1,58 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "StandardFilter.h" + +#include "../AnalysisHeader.h" +#include "../Analyzers.h" +#include "StandardTokenizerConstants.h" +#include "CLucene/util/StringBuffer.h" + +CL_NS_USE(analysis) +CL_NS_USE(util) +CL_NS_DEF2(analysis,standard) + + StandardFilter::StandardFilter(TokenStream* in, bool deleteTokenStream): + TokenFilter(in, deleteTokenStream) + { + } + + StandardFilter::~StandardFilter(){ + } + + bool StandardFilter::next(Token* t) { + if (!input->next(t)) + return false; + + TCHAR* text = t->_termText; + const int32_t textLength = t->termTextLength(); + const TCHAR* type = t->type(); + + if ( type == tokenImage[APOSTROPHE] && //we can compare the type directy since the type should always come from the tokenImage + ( textLength >= 2 && _tcsicmp(text+textLength-2, _T("'s"))==0 ) ) + { + // remove 's + text[textLength-2]=0; + t->resetTermTextLen(); + + return true; + + } else if ( type == tokenImage[ACRONYM] ) { // remove dots + int32_t j = 0; + for ( int32_t i=0;iin. + StandardFilter(TokenStream* in, bool deleteTokenStream); + + ~StandardFilter(); + + + /** Returns the next token in the stream, or NULL at EOS. + *

Removes 's from the end of words. + *

Removes dots from acronyms. + */ + bool next(Token* token); + }; +CL_NS_END2 +#endif diff --git a/3rdparty/clucene/src/CLucene/analysis/standard/StandardTokenizer.cpp b/3rdparty/clucene/src/CLucene/analysis/standard/StandardTokenizer.cpp new file mode 100644 index 000000000..60f9a449c --- /dev/null +++ b/3rdparty/clucene/src/CLucene/analysis/standard/StandardTokenizer.cpp @@ -0,0 +1,446 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "StandardTokenizer.h" + +CL_NS_USE(analysis) +CL_NS_USE(util) +CL_NS_DEF2(analysis,standard) + + const static TCHAR* tokenImageArray[] = { + _T(""), + _T(""), + _T(""), + _T(""), + _T(""), + _T(""), + _T(""), + _T(""), + _T(""), + _T("") + }; + const TCHAR** tokenImage = tokenImageArray; + + /* A bunch of shortcut macros, many of which make assumptions about variable + ** names. These macros enhance readability, not just convenience! */ + #define EOS (ch==-1 || rd->Eos()) + #define SPACE (_istspace((TCHAR)ch) != 0) + #define ALPHA (_istalpha((TCHAR)ch) != 0) + #define ALNUM (_istalnum(ch) != 0) + #define DIGIT (_istdigit(ch) != 0) + #define UNDERSCORE (ch == '_') + + #define _CJK ( (ch>=0x3040 && ch<=0x318f) || \ + (ch>=0x3300 && ch<=0x337f) || \ + (ch>=0x3400 && ch<=0x3d2d) || \ + (ch>=0x4e00 && ch<=0x9fff) || \ + (ch>=0xf900 && ch<=0xfaff) || \ + (ch>=0xac00 && ch<=0xd7af) ) //korean + + + #define DASH (ch == '-') + #define NEGATIVE_SIGN_ DASH + //#define POSITIVE_SIGN_ (ch == '+') + //#define SIGN (NEGATIVE_SIGN_ || POSITIVE_SIGN_) + + #define DOT (ch == '.') + #define DECIMAL DOT + + + //freebsd seems to have a problem with defines over multiple lines, so this has to be one long line + #define _CONSUME_AS_LONG_AS(conditionFails) while (true) { ch = readChar(); if (ch==-1 || (!(conditionFails) || str.len >= LUCENE_MAX_WORD_LEN)) { break; } str.appendChar(ch);} + + #define CONSUME_ALPHAS _CONSUME_AS_LONG_AS(ALPHA) + + #define CONSUME_DIGITS _CONSUME_AS_LONG_AS(DIGIT) + + /* otherMatches is a condition (possibly compound) under which a character + ** that's not an ALNUM or UNDERSCORE can be considered not to break the + ** span. Callers should pass false if only ALNUM/UNDERSCORE are acceptable. */ + #define CONSUME_WORD _CONSUME_AS_LONG_AS(ALNUM || UNDERSCORE) + + /* + ** Consume CJK characters + */ + #define CONSUME_CJK _CONSUME_AS_LONG_AS(_CJK) + + + /* It is considered that "nothing of value" has been read if: + ** a) The "read head" hasn't moved since specialCharPos was established. + ** or + ** b) The "read head" has moved by one character, but that character was + ** either whitespace or not among the characters found in the body of + ** a token (deliberately doesn't include the likes of '@'/'&'). */ + #define CONSUMED_NOTHING_OF_VALUE (rdPos == specialCharPos || (rdPos == specialCharPos+1 && ( SPACE || !(ALNUM || DOT || DASH || UNDERSCORE) ))) + + #define RIGHTMOST(sb) (sb.getBuffer()[sb.len-1]) + #define RIGHTMOST_IS(sb, c) (RIGHTMOST(sb) == c) + /* To discard the last character in a StringBuffer, we decrement the buffer's + ** length indicator and move the terminator back by one character. */ + #define SHAVE_RIGHTMOST(sb) (sb.getBuffer()[--sb.len] = '\0') + + //#define REMOVE_TRAILING_CHARS(sb, charMatchesCondition) { TCHAR* sbBuf = sb.getBuffer(); for (int32_t i = sb.len-1; i >= 0; i--) { TCHAR c = sbBuf[i]; if (charMatchesCondition) { sbBuf[--sb.len] = '\0'; } else {break;}}} + + /* Does StringBuffer sb contain any of the characters in string ofThese? */ + #define CONTAINS_ANY(sb, ofThese) (_tcscspn(sb.getBuffer(), _T(ofThese)) != static_cast(sb.len)) + + + StandardTokenizer::StandardTokenizer(Reader* reader): + rd(_CLNEW FastCharStream(reader)), + /* rdPos is zero-based. It starts at -1, and will advance to the first + ** position when readChar() is first called. */ + rdPos(-1), + tokenStart(-1) + { + } + + StandardTokenizer::~StandardTokenizer() { + _CLDELETE(rd); + } + + int StandardTokenizer::readChar() { + /* Increment by 1 because we're speaking in terms of characters, not + ** necessarily bytes: */ + rdPos++; + return rd->GetNext(); + } + + void StandardTokenizer::unReadChar() { + rd->UnGet(); + rdPos--; + } + + inline bool StandardTokenizer::setToken(Token* t, StringBuffer* sb, TokenTypes tokenCode) { + t->setStartOffset(tokenStart); + t->setEndOffset(tokenStart+sb->length()); + t->setType(tokenImage[tokenCode]); + sb->getBuffer(); //null terminates the buffer + t->resetTermTextLen(); + return true; + } + + bool StandardTokenizer::next(Token* t) { + int ch=0; + while (!EOS) { + ch = readChar(); + + if ( ch == 0 || ch == -1 ){ + continue; + } else if (SPACE) { + continue; + } else if (ALPHA || UNDERSCORE) { + tokenStart = rdPos; + return ReadAlphaNum(ch,t); + } else if (DIGIT || NEGATIVE_SIGN_ || DECIMAL) { + tokenStart = rdPos; + /* ReadNumber returns NULL if it fails to extract a valid number; in + ** that case, we just continue. */ + if (ReadNumber(NULL, ch,t)) + return true; + } else if ( _CJK ){ + if ( ReadCJK(ch,t) ) + return true; + } + } + return false; + } + + bool StandardTokenizer::ReadNumber(const TCHAR* previousNumber, const TCHAR prev,Token* t) { + /* previousNumber is only non-NULL if this function already read a complete + ** number in a previous recursion, yet has been asked to read additional + ** numeric segments. For example, in the HOST "192.168.1.3", "192.168" is + ** a complete number, but this function will recurse to read the "1.3", + ** generating a single HOST token "192.168.1.3". */ + t->growBuffer(LUCENE_MAX_WORD_LEN+1);//make sure token can hold the next word + StringBuffer str(t->_termText,t->bufferLength(),true); //use stringbuffer to read data onto the termText + TokenTypes tokenType; + bool decExhausted; + if (previousNumber != NULL) { + str.prepend(previousNumber); + tokenType = CL_NS2(analysis,standard)::HOST; + decExhausted = false; + } else { + tokenType = CL_NS2(analysis,standard)::NUM; + decExhausted = (prev == '.'); + } + if ( str.len >= LUCENE_MAX_WORD_LEN ){ + //if a number is too long, i would say there is no point + //storing it, because its going to be the wrong number anyway? + //what do people think? + return false; + } + str.appendChar(prev); + + const bool signExhausted = (prev == '-'); + int ch = prev; + + CONSUME_DIGITS; + + if (str.len < 2 /* CONSUME_DIGITS didn't find any digits. */ + && ( + (signExhausted && !DECIMAL) + || (decExhausted /* && !DIGIT is implied, since CONSUME_DIGITS stopped on a non-digit. */) + ) + ) + { + /* We have either: + ** a) a negative sign that's not followed by either digit(s) or a decimal + ** b) a decimal that's not followed by digit(s) + ** so this is not a valid number. */ + if (!EOS) { + /* Unread the character that stopped CONSUME_DIGITS: */ + unReadChar(); + } + return false; + } + + /* We just read a group of digits. Is it followed by a decimal symbol, + ** implying that there might be another group of digits available? */ + if (!EOS) { + if (DECIMAL) { + if ( str.len >= LUCENE_MAX_WORD_LEN ) + return false; //read above for rationale + str.appendChar(ch); + } else { + unReadChar(); + goto SUCCESSFULLY_EXTRACTED_NUMBER; + } + + CONSUME_DIGITS; + if (!DIGIT && !DECIMAL) { + unReadChar(); + } else if (!EOS && DECIMAL && _istdigit(rd->Peek())) { + /* We just read the fractional digit group, but it's also followed by + ** a decimal symbol and at least one more digit, so this must be a + ** HOST rather than a real number. */ + return ReadNumber(str.getBuffer(), '.',t); + } + } + + SUCCESSFULLY_EXTRACTED_NUMBER: + TCHAR rightmost = RIGHTMOST(str); + /* Don't including a trailing decimal point. */ + if (rightmost == '.') { + SHAVE_RIGHTMOST(str); + unReadChar(); + rightmost = RIGHTMOST(str); + } + /* If all we have left is a negative sign, it's not a valid number. */ + if (rightmost == '-') { + CND_PRECONDITION (str.len == 1, "Number is invalid"); + return false; + } + + return setToken(t,&str,tokenType); + } + + bool StandardTokenizer::ReadAlphaNum(const TCHAR prev, Token* t) { + t->growBuffer(LUCENE_MAX_WORD_LEN+1);//make sure token can hold the next word + StringBuffer str(t->_termText,t->bufferLength(),true); //use stringbuffer to read data onto the termText + if ( str.len < LUCENE_MAX_WORD_LEN ){ + str.appendChar(prev); + int ch = prev; + + CONSUME_WORD; + if (!EOS && str.len < LUCENE_MAX_WORD_LEN-1 ) { //still have space for 1 more character? + switch(ch) { /* What follows the first alphanum segment? */ + case '.': + str.appendChar('.'); + return ReadDotted(&str, CL_NS2(analysis,standard)::UNKNOWN,t); + case '\'': + str.appendChar('\''); + return ReadApostrophe(&str,t); + case '@': + str.appendChar('@'); + return ReadAt(&str,t); + case '&': + str.appendChar('&'); + return ReadCompany(&str,t); + /* default: fall through to end of this function. */ + } + } + } + return setToken(t,&str,CL_NS2(analysis,standard)::ALPHANUM); + } + + bool StandardTokenizer::ReadCJK(const TCHAR prev, Token* t) { + t->growBuffer(LUCENE_MAX_WORD_LEN+1);//make sure token can hold the next word + StringBuffer str(t->_termText,t->bufferLength(),true); //use stringbuffer to read data onto the termText + if ( str.len < LUCENE_MAX_WORD_LEN ){ + str.appendChar(prev); + int ch = prev; + + CONSUME_CJK; + } + return setToken(t,&str,CL_NS2(analysis,standard)::CJK); + } + + + bool StandardTokenizer::ReadDotted(StringBuffer* _str, TokenTypes forcedType, Token* t) { + const int32_t specialCharPos = rdPos; + StringBuffer& str=*_str; + + /* A segment of a "dotted" is not allowed to begin with another dot or a dash. + ** Even though hosts, e-mail addresses, etc., could have a dotted-segment + ** that begins with a dot or a dash, it's far more common in source text + ** for a pattern like "abc.--def" to be intended as two tokens. */ + int ch = rd->Peek(); + if (!(DOT || DASH)) { + bool prevWasDot; + bool prevWasDash; + if (str.len == 0) { + prevWasDot = false; + prevWasDash = false; + } else { + prevWasDot = RIGHTMOST(str) == '.'; + prevWasDash = RIGHTMOST(str) == '-'; + } + while (!EOS && str.len < LUCENE_MAX_WORD_LEN-1 ) { + ch = readChar(); + const bool dot = ch == '.'; + const bool dash = ch == '-'; + + if (!(ALNUM || UNDERSCORE || dot || dash)) { + break; + } + /* Multiple dots or dashes in succession end the token. + ** Consider the following inputs: + ** "Visit windowsupdate.microsoft.com--update today!" + ** "In the U.S.A.--yes, even there!" */ + if ((dot || dash) && (prevWasDot || prevWasDash)) { + /* We're not going to append the character we just read, in any case. + ** As to the character before it (which is currently RIGHTMOST(str)): + ** Unless RIGHTMOST(str) is a dot, in which we need to save it so the + ** acronym-versus-host detection can work, we want to get rid of it. */ + if (!prevWasDot) { + SHAVE_RIGHTMOST(str); + } + break; + } + + str.appendChar(ch); + + prevWasDot = dot; + prevWasDash = dash; + } + } + + /* There's a potential StringBuffer.append call in the code above, which + ** could cause str to reallocate its internal buffer. We must wait to + ** obtain the optimization-oriented strBuf pointer until after the initial + ** potentially realloc-triggering operations on str. + ** Because there can be other such ops much later in this function, strBuf + ** is guarded within a block to prevent its use during or after the calls + ** that would potentially invalidate it. */ + { /* Begin block-guard of strBuf */ + TCHAR* strBuf = str.getBuffer(); + + bool rightmostIsDot = RIGHTMOST_IS(str, '.'); + if (CONSUMED_NOTHING_OF_VALUE) { + /* No more alphanums available for this token; shave trailing dot, if any. */ + if (rightmostIsDot) { + SHAVE_RIGHTMOST(str); + } + /* If there are no dots remaining, this is a generic ALPHANUM. */ + if (_tcschr(strBuf, '.') == NULL) { + forcedType = CL_NS2(analysis,standard)::ALPHANUM; + } + + /* Check the token to see if it's an acronym. An acronym must have a + ** letter in every even slot and a dot in every odd slot, including the + ** last slot (for example, "U.S.A."). */ + } else if (rightmostIsDot) { + bool isAcronym = true; + const int32_t upperCheckLimit = str.len - 1; /* -1 b/c we already checked the last slot. */ + + for (int32_t i = 0; i < upperCheckLimit; i++) { + const bool even = (i % 2 == 0); + ch = strBuf[i]; + if ( (even && !ALPHA) || (!even && !DOT) ) { + isAcronym = false; + break; + } + } + if (isAcronym) { + forcedType = CL_NS2(analysis,standard)::ACRONYM; + } else { + /* If it's not an acronym, we don't want the trailing dot. */ + SHAVE_RIGHTMOST(str); + /* If there are no dots remaining, this is a generic ALPHANUM. */ + if (_tcschr(strBuf, '.') == NULL) { + forcedType = CL_NS2(analysis,standard)::ALPHANUM; + } + } + } + } /* End block-guard of strBuf */ + + if (!EOS) { + if (ch == '@' && str.len < LUCENE_MAX_WORD_LEN-1) { + str.appendChar('@'); + return ReadAt(&str,t); + } else { + unReadChar(); + } + } + + return setToken(t,&str,CL_NS2(analysis,standard)::UNKNOWN + ? forcedType : CL_NS2(analysis,standard)::HOST); + } + + bool StandardTokenizer::ReadApostrophe(StringBuffer* _str, Token* t) { + StringBuffer& str=*_str; + + TokenTypes tokenType = CL_NS2(analysis,standard)::APOSTROPHE; + const int32_t specialCharPos = rdPos; + int ch=0; + + CONSUME_ALPHAS; + if (RIGHTMOST_IS(str, '\'') || CONSUMED_NOTHING_OF_VALUE) { + /* After the apostrophe, no more alphanums were available within this + ** token; shave trailing apostrophe and revert to generic ALPHANUM. */ + SHAVE_RIGHTMOST(str); + tokenType = CL_NS2(analysis,standard)::ALPHANUM; + } + if (!EOS) { + unReadChar(); + } + + return setToken(t,&str,tokenType); + } + + bool StandardTokenizer::ReadAt(StringBuffer* str, Token* t) { + ReadDotted(str, CL_NS2(analysis,standard)::EMAIL,t); + /* JLucene grammar indicates dots/digits not allowed in company name: */ + if (!CONTAINS_ANY((*str), ".0123456789")) { + setToken(t,str,CL_NS2(analysis,standard)::COMPANY); + } + return true; + } + + bool StandardTokenizer::ReadCompany(StringBuffer* _str, Token* t) { + StringBuffer& str = *_str; + const int32_t specialCharPos = rdPos; + int ch=0; + + CONSUME_WORD; + if (CONSUMED_NOTHING_OF_VALUE) { + /* After the ampersand, no more alphanums were available within this + ** token; shave trailing ampersand and revert to ALPHANUM. */ + CND_PRECONDITION(RIGHTMOST_IS(str, '&'),"ReadCompany failed"); + SHAVE_RIGHTMOST(str); + + + return setToken(t,&str,CL_NS2(analysis,standard)::ALPHANUM); + } + if (!EOS) { + unReadChar(); + } + + return setToken(t,&str,CL_NS2(analysis,standard)::COMPANY); + } + +CL_NS_END2 diff --git a/3rdparty/clucene/src/CLucene/analysis/standard/StandardTokenizer.h b/3rdparty/clucene/src/CLucene/analysis/standard/StandardTokenizer.h new file mode 100644 index 000000000..d4195be81 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/analysis/standard/StandardTokenizer.h @@ -0,0 +1,88 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_analysis_standard_StandardTokenizer +#define _lucene_analysis_standard_StandardTokenizer + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "../AnalysisHeader.h" +#include "../Analyzers.h" +#include "StandardTokenizerConstants.h" +#include "CLucene/util/StringBuffer.h" +#include "CLucene/util/FastCharStream.h" +#include "CLucene/util/Reader.h" + + +CL_NS_DEF2(analysis,standard) + +/** A grammar-based tokenizer constructed with JavaCC. + * + *

This should be a good tokenizer for most European-language documents: + * + *

    + *
  • Splits words at punctuation characters, removing punctuation. However, a + * dot that's not followed by whitespace is considered part of a token. + *
  • Splits words at hyphens, unless there's a number in the token, in which case + * the whole token is interpreted as a product number and is not split. + *
  • Recognizes email addresses and internet hostnames as one token. + *
+ * + *

Many applications have specific tokenizer needs. If this tokenizer does + * not suit your application, please consider copying this source code + * directory to your project and maintaining your own grammar-based tokenizer. + */ + class StandardTokenizer: public Tokenizer { + private: + int32_t rdPos; + int32_t tokenStart; + + // Advance by one character, incrementing rdPos and returning the character. + int readChar(); + // Retreat by one character, decrementing rdPos. + void unReadChar(); + + // createToken centralizes token creation for auditing purposes. + //Token* createToken(CL_NS(util)::StringBuffer* sb, TokenTypes tokenCode); + inline bool setToken(Token* t, CL_NS(util)::StringBuffer* sb, TokenTypes tokenCode); + + bool ReadDotted(CL_NS(util)::StringBuffer* str, TokenTypes forcedType,Token* t); + + public: + CL_NS(util)::FastCharStream* rd; + + // Constructs a tokenizer for this Reader. + StandardTokenizer(CL_NS(util)::Reader* reader); + + ~StandardTokenizer(); + + /** Returns the next token in the stream, or false at end-of-stream. + * The returned token's type is set to an element of + * StandardTokenizerConstants::tokenImage. */ + bool next(Token* token); + + // Reads for number like "1"/"1234.567", or IP address like "192.168.1.2". + bool ReadNumber(const TCHAR* previousNumber, const TCHAR prev, Token* t); + + bool ReadAlphaNum(const TCHAR prev, Token* t); + + // Reads for apostrophe-containing word. + bool ReadApostrophe(CL_NS(util)::StringBuffer* str, Token* t); + + // Reads for something@... it may be a COMPANY name or a EMAIL address + bool ReadAt(CL_NS(util)::StringBuffer* str, Token* t); + + // Reads for COMPANY name like AT&T. + bool ReadCompany(CL_NS(util)::StringBuffer* str, Token* t); + + // Reads CJK characters + bool ReadCJK(const TCHAR prev, Token* t); + }; + +CL_NS_END2 +#endif diff --git a/3rdparty/clucene/src/CLucene/analysis/standard/StandardTokenizerConstants.h b/3rdparty/clucene/src/CLucene/analysis/standard/StandardTokenizerConstants.h new file mode 100644 index 000000000..3c95af45a --- /dev/null +++ b/3rdparty/clucene/src/CLucene/analysis/standard/StandardTokenizerConstants.h @@ -0,0 +1,30 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_analysis_standard_StandardTokenizerConstants +#define _lucene_analysis_standard_StandardTokenizerConstants + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +CL_NS_DEF2(analysis,standard) + enum TokenTypes { + _EOF, + UNKNOWN, + ALPHANUM, + APOSTROPHE, + ACRONYM, + COMPANY, + EMAIL, + HOST, + NUM, + CJK + }; + extern const TCHAR** tokenImage; + + CL_NS_END2 +#endif diff --git a/3rdparty/clucene/src/CLucene/config/CompilerAcc.h b/3rdparty/clucene/src/CLucene/config/CompilerAcc.h new file mode 100644 index 000000000..6ecd142be --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/CompilerAcc.h @@ -0,0 +1,166 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +* +* Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +------------------------------------------------------------------------------*/ +#if !defined(_lucene_COMPILER_ACC) +#define _lucene_COMPILER_ACC + +// It is internal CLucene header - DO NOT include it directly +#if !defined(_SUPPRESS_MAKE_BASED_CONFIG) +#if defined(_BUILD_FOR_QT_) +#include "fulltextsearch/qclucene-config_p.h" +#else +#include "CLucene/clucene-config.h" //make clucene-config.h file +#endif +#endif + +#if defined(_ASCII) +#undef _UCS2 +#elif defined(_UCS2) +// +#else +#define CL_CHARSET_GUESS +#endif + +//dont allow FS_MMAP if mmap is not available +#if defined(LUCENE_FS_MMAP) && !defined(_CL_HAVE_MMAP) +#error "LUCENE_FS_MMAP is defined and MMap doesn't appear to be available" +#endif + +#ifdef _CL_HAVE_NO_FUNCTION_TRY_BLOCKS +#undef _LUCENE_DISABLE_EXCEPTIONS +#define _LUCENE_DISABLE_EXCEPTIONS + +#error "this is bad if you made it here... your compiler seems not to have try/catch blocks." +#error "maybe you could implement an alternative solution for us? :)" +#endif + +#ifndef _CL_HAVE_NAMESPACES +#define DISABLE_NAMESPACE +#endif + +#define LUCENE_DISABLE_HASHING //we could enable this, but so far test show that the hashing is slower :( + +//define the file functions +#define fileSeek lseek +#define fileSize _filelength +#define fileStat stat +#define fileHandleStat fstat +#ifdef _CL_HAVE_TELL +#define fileTell tell +#else +//ftell (and probably soon ftell64) are POSIX standard functions, but tell and +//tell64 are not, so we define fileTell in terms of fileSeek. +#define fileTell(fhandle) fileSeek(fhandle, 0, SEEK_CUR) +#endif + +//this is needed early on so that CL_MAX_PATH can be correctly determined +//in the StdHeader.h. This was earlier causing problems with macosx. +//:: crash was due to realpath() that expects an output arguments that +//has at least the size of PATH_MAX (even if the result has a lower size) +#include + +#ifndef _CL_HAVE_WCHAR_T + typedef unsigned short wchar_t; +#endif + +#if defined(__CYGWIN__) +//cygwin seems to incorrectly define that it has wprintf??? +#undef _CL_HAVE_WPRINTF +#elif defined(__MINGW32__) +# ifndef _CL_HAVE_WINDOWS_H +# define _CL_HAVE_WINDOWS_H +# endif +#endif + + +/////////////////////////////////////////////////////////////////////////////// +//end _lucene_COMPILER_ACC +#elif !defined(_lucene_COMPILER_ACC2) +#define _lucene_COMPILER_ACC2 +//second inclusion + + //types + #if defined(_CL_HAVE_SYS_TYPES_H) + #include + #endif + #if defined(_CL_HAVE_INTTYPES_H) + #include + #elif defined(_CL_HAVE_STDINT_H) + #include + #else + #if _CL_SIZEOF_UNSIGNED_LONG_LONG==8 + typedef unsigned long long uint64_t; + typedef long long int64_t; + #elif _CL_SIZEOF_UNSIGNED_LONG==8 + typedef unsigned long uint64_t; + typedef long int64_t; + #else + #error I do not know what to use for a uint64_t. + #endif + + /* Give us an unsigned 32-bit data type. */ + #if _CL_SIZEOF_UNSIGNED_LONG==4 + typedef unsigned long uint32_t; + typedef long int32_t; + #elif _CL_SIZEOF_UNSIGNED_INT==4 + typedef unsigned int uint32_t; + typedef int int32_t; + #else + #error I do not know what to use for a uint32_t. + #endif + + /* An unsigned 8-bit data type */ + #if _CL_SIZEOF_UNSIGNED_CHAR==1 + typedef unsigned char uint8_t; + #else + #error I do not know what to use for a uint8_t. + #endif + #endif + + //second chance to fix default settings + //this must be defined later, otherwise it messes up + //the standard libraries + #if !defined(__MINGW32__) + #define _close ::close + #define _read ::read + #endif + + //now that int64_t is defined, we can define this... + #ifndef _CL_HAVE_FILELENGTH + #undef fileSize + #define fileSize lucene_filelength + int64_t lucene_filelength(int handle); + #endif + +#elif !defined(_lucene_COMPILER_ACC3) +#define _lucene_COMPILER_ACC3 + //third inclusion + + #if !defined(__MINGW32__) + //define replacements + #define O_RANDOM 0 + #undef O_BINARY + #define O_BINARY 0 + #define _S_IREAD 0444 + #define _S_IWRITE 0333 // write and execute permissions + + //some functions that are needed - not charset dependent and not tchar type functions + #define _open open + #define _write write + #define _snprintf snprintf + + //clucene uses ascii for filename interactions + #define _realpath(rel,abs) realpath(rel,abs) + #define _mkdir(x) mkdir(x,0777) + #define _unlink unlink + #else + #define _realpath(rel,abs) _fullpath(abs,rel,CL_MAX_PATH) + #endif + //also required by mingw + #define _rename rename +#endif diff --git a/3rdparty/clucene/src/CLucene/config/CompilerBcb.h b/3rdparty/clucene/src/CLucene/config/CompilerBcb.h new file mode 100644 index 000000000..f1b423b50 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/CompilerBcb.h @@ -0,0 +1,68 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#if !defined(_lucene_COMPILER_BCB) +#define _lucene_COMPILER_BCB + +// It is internal CLucene header - DO NOT include it directly + +#include "CLucene/config/define_std.h" +#undef _CL_HAVE_STRTOLL +#undef _CL_HAVE_WCSTOLL + +#define _LUCENE_PRAGMA_ONCE +#define _LUCENE_PRAGMA_WARNINGS //tell lucene to display warnings using pragmas instead of #warning +#define LUCENE_DISABLE_HASHING +#define LUCENE_STATIC_CONSTANT(type, assignment) enum { assignment } + +#undef LUCENE_ENABLE_MEMLEAKTRACKING //it has been reported that this causes problems + +#define fileSize filelength +#define fileSeek lseek +#define fileTell tell +#define fileStat stat +#define fileHandleStat fstat + +#define O_RANDOM 0 + +//java long type +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; + +//java int type +typedef int int32_t; +typedef unsigned int uint32_t; + +//java byte type +typedef unsigned char uint8_t; + +//floating point type +//we are going to use qreal now +//typedef double float_t; + +//required type +typedef int intptr_t; + +#define _CL_ILONG(x) x ## L +#define _ILONGLONG(x) x ## i64 + + +#elif !defined(_lucene_COMPILER_BCB2) +#define _lucene_COMPILER_BCB2 + //second inclusion + + #define _open open + #define _timeb timeb + #define _ftime ::ftime + #define _rename rename + + #define _realpath(rel,abs) _fullpath(abs,rel,CL_MAX_PATH) + +#elif !defined(_lucene_COMPILER_BCB3) +#define _lucene_COMPILER_BCB3 + //third inclusion + +#endif diff --git a/3rdparty/clucene/src/CLucene/config/CompilerGcc.h b/3rdparty/clucene/src/CLucene/config/CompilerGcc.h new file mode 100644 index 000000000..a9120988b --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/CompilerGcc.h @@ -0,0 +1,175 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +* +* Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +------------------------------------------------------------------------------*/ +#if !defined(_lucene_COMPILER_GCC) +#define _lucene_COMPILER_GCC + +// It is internal CLucene header - DO NOT include it directly +#if !defined(_SUPPRESS_MAKE_BASED_CONFIG) + #if defined(_BUILD_FOR_QT_) + #include "fulltextsearch/qclucene-config_p.h" + #else + #include "CLucene/clucene-config.h" //make clucene-config.h file + #endif +#endif + +#if defined(_ASCII) + #undef _UCS2 +#elif defined(_UCS2) +// +#else + #define CL_CHARSET_GUESS +#endif + +//dont allow FS_MMAP if mmap is not available +#if defined(LUCENE_FS_MMAP) && !defined(_CL_HAVE_MMAP) + #error "LUCENE_FS_MMAP is defined and MMap doesn't appear to be available" +#endif + +#ifdef _CL_HAVE_NO_FUNCTION_TRY_BLOCKS + #undef _LUCENE_DISABLE_EXCEPTIONS + #define _LUCENE_DISABLE_EXCEPTIONS + + #error "this is bad if you made it here... your compiler seems not to have try/catch blocks." + #error "maybe you could implement an alternative solution for us? :)" +#endif + +#ifndef _CL_HAVE_NAMESPACES + #define DISABLE_NAMESPACE +#endif + +#define CL_NS_HASHING(func) __gnu_cxx::func +#define LUCENE_DISABLE_HASHING //we could enable this, but so far test show that the hashing is slower :( + +//define the file functions +#define fileSeek lseek +#define fileSize _filelength +#define fileStat stat +#define fileHandleStat fstat +#ifdef _CL_HAVE_TELL + #define fileTell tell +#else + //ftell (and probably soon ftell64) are POSIX standard functions, but tell and + //tell64 are not, so we define fileTell in terms of fileSeek. + #define fileTell(fhandle) fileSeek(fhandle, 0, SEEK_CUR) +#endif + +//this is needed early on so that CL_MAX_PATH can be correctly determined +//in the StdHeader.h. This was earlier causing problems with macosx. +//:: crash was due to realpath() that expects an output arguments that +//has at least the size of PATH_MAX (even if the result has a lower size) +#include + +#ifndef _CL_HAVE_WCHAR_T + typedef unsigned short wchar_t; +#endif + +#if defined(__CYGWIN__) + //cygwin seems to incorrectly define that it has wprintf??? + #undef _CL_HAVE_WPRINTF +#elif defined(__MINGW32__) + #ifndef _CL_HAVE_WINDOWS_H + #define _CL_HAVE_WINDOWS_H + #endif +#endif + + +/////////////////////////////////////////////////////////////////////////////// +//end _lucene_COMPILER_GCC1 +#elif !defined(_lucene_COMPILER_GCC2) +#define _lucene_COMPILER_GCC2 + //second inclusion + + //types + #if defined(_CL_HAVE_SYS_TYPES_H) + #include + #endif + #if defined(_CL_HAVE_INTTYPES_H) + #include + #elif defined(_CL_HAVE_STDINT_H) + #include + #else + #if _CL_SIZEOF_UNSIGNED_LONG_LONG==8 + typedef unsigned long long uint64_t; + typedef long long int64_t; + #elif _CL_SIZEOF_UNSIGNED_LONG==8 + typedef unsigned long uint64_t; + typedef long int64_t; + #else + #error I do not know what to use for a uint64_t. + #endif + + /* Give us an unsigned 32-bit data type. */ + #if _CL_SIZEOF_UNSIGNED_LONG==4 + typedef unsigned long uint32_t; + typedef long int32_t; + #elif _CL_SIZEOF_UNSIGNED_INT==4 + typedef unsigned int uint32_t; + typedef int int32_t; + #else + #error I do not know what to use for a uint32_t. + #endif + + /* An unsigned 8-bit data type */ + #if _CL_SIZEOF_UNSIGNED_CHAR==1 + typedef unsigned char uint8_t; + #else + #error I do not know what to use for a uint8_t. + #endif + #endif + + //second chance to fix default settings + //this must be defined later, otherwise it messes up + //the standard libraries + #if !defined(__MINGW32__) + #define _close ::close + #define _read ::read + #endif + + //now that int64_t is defined, we can define this... + #ifndef _CL_HAVE_FILELENGTH + #undef fileSize + #define fileSize lucene_filelength + int64_t lucene_filelength(int handle); + #endif + +#elif !defined(_lucene_COMPILER_GCC3) +#define _lucene_COMPILER_GCC3 + //third inclusion + + #if !defined(__MINGW32__) + //define replacements + #define O_RANDOM 0 + #undef O_BINARY + #define O_BINARY 0 + #define _S_IREAD 0444 + #define _S_IWRITE 0333 // write and execute permissions + + //some functions that are needed - not charset dependent and not tchar type functions + #define _open open + #define _write write + #define _snprintf snprintf + + //clucene uses ascii for filename interactions + #define _realpath(rel,abs) realpath(rel,abs) + #define _mkdir(x) mkdir(x,0777) + #define _unlink unlink + #else + #define _realpath(rel,abs) _fullpath(abs,rel,CL_MAX_PATH) + #endif + //also required by mingw + #define _rename rename +#endif + +#if defined(__GNUC__) && (defined(__sgi) || (defined(Q_OS_SOLARIS) && Q_SOLARIS_VERSION < 10)) + #undef _CL_HAVE_FLOAT_T +#endif + +#if defined(__GNUC__) && defined(Q_OS_SOLARIS) && Q_SOLARIS_VERSION < 10 + #undef _CL_HAVE_WCSTOLL +#endif diff --git a/3rdparty/clucene/src/CLucene/config/CompilerMsvc.h b/3rdparty/clucene/src/CLucene/config/CompilerMsvc.h new file mode 100644 index 000000000..0021ea368 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/CompilerMsvc.h @@ -0,0 +1,136 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +* +* Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +------------------------------------------------------------------------------*/ +#if !defined(_lucene_COMPILER_MSVC) +#define _lucene_COMPILER_MSVC + +// It is internal CLucene header - DO NOT include it directly + +#include "CLucene/config/define_std.h" + +#if (_MSC_VER >= 1300) +//>= 7.0 + #if defined(_BUILD_FOR_QT_) + # pragma warning(disable: 4100) // disable unreferenced formal parameter + # pragma warning(disable: 4189) // disable local variable is initialized but not referenced + #endif + # pragma warning(disable: 4512) // This would be very annoying + # pragma warning(disable: 4290) // Ignore exception specification warning + # pragma warning(disable: 4250) // Ignore 'class1' : inherits 'class2::member' via dominance (e.g. in MultiReader) + // Check for STLport presence + #include + #if (_MSC_VER < 1310) || defined(_STLPORT_VERSION) + #define CL_NS_HASHING(func) std::func //the namespace is different on VC 7.0 + #else + #define CL_NS_HASHING(func) stdext::func + #endif + #define LUCENE_STATIC_CONSTANT_SYNTAX 1 + + #if _MSC_FULL_VER >= 140050320 + #define _CL_DEPRECATE_TEXT(_Text) __declspec(deprecated(_Text)) + #else + #define _CL_DEPRECATE_TEXT(_Text) __declspec(deprecated) + #endif + +#elif (_MSC_VER >= 1200) +//6.0 +#ifdef LUCENE_ENABLE_MEMLEAKTRACKING + #define _CLDELETE_CARRAY(x) if (x!=NULL){CL_NS(debug)::LuceneBase::__cl_voidpremove((void*)x,__FILE__,__LINE__);delete[] __CONST_CAST(TCHAR*,x); x=NULL;} + #define _CLDELETE_CaARRAY(x) if (x!=NULL){CL_NS(debug)::LuceneBase::__cl_voidpremove((void*)x,__FILE__,__LINE__);delete[] __CONST_CAST(char*,x); x=NULL;} + #define _CLDELETE_LCARRAY(x) if (x!=NULL){CL_NS(debug)::LuceneBase::__cl_voidpremove((void*)x,__FILE__,__LINE__);delete[] __CONST_CAST(TCHAR*,x);} + #define _CLDELETE_LCaARRAY(x) if (x!=NULL){CL_NS(debug)::LuceneBase::__cl_voidpremove((void*)x,__FILE__,__LINE__);delete[] __CONST_CAST(char*,x);} +#else + #define _CLDELETE_CARRAY(x) if (x!=NULL){delete[] __CONST_CAST(TCHAR*,x); x=NULL;} + #define _CLDELETE_CaARRAY(x) if (x!=NULL){delete[] __CONST_CAST(char*,x); x=NULL;} + #define _CLDELETE_LCARRAY(x) if (x!=NULL){delete[] __CONST_CAST(TCHAR*,x);} + #define _CLDELETE_LCaARRAY(x) if (x!=NULL){delete[] __CONST_CAST(char*,x);} + +#endif + #define LUCENE_STATIC_CONSTANT_SYNTAX 2 + + # pragma warning(disable: 4786) // This would be very annoying + namespace std{ + # undef min // just in case + # undef max // just in case + + #define min(a,b) (a>b?b:a) + #define max(a,b) (a>b?a:b) + } + + //only 7.0+ has these function + #undef _CL_HAVE_LLTOA + #undef _CL_HAVE_LLTOAW + #undef _CL_HAVE_INTPTR_T + #undef _CL_HAVE_WCSTOLL + #undef _CL_HAVE_STRTOLL + #undef _CL_HAVE_HASH_MAP + #undef _CL_HAVE_HASH_SET + +#else +# error "This version of MSVC has not been tested. Please uncomment this line to try anyway. Please send a report to the Clucene's administration if successful" +#endif + +#if _MSC_VER >= 1020 + #define _LUCENE_PRAGMA_ONCE +#endif +#define _LUCENE_PRAGMA_WARNINGS //tell lucene to display warnings using pragmas instead of #warning + +//if we are compiling using single-threaded libraries, we can disable multi-threading stuff +#if !defined(_MT) && !defined(_CL_DISABLE_MULTITHREADING) + #define _CL_DISABLE_MULTITHREADING +#endif + +//msvc supports large files +#ifdef _LARGE_FILES +# define fileSize _filelengthi64 +# define fileSeek _lseeki64 +# define fileTell _telli64 +# define fileStat _stati64 +# define fileHandleStat _fstati64 +#else +# define fileSize _filelength +# define fileSeek _lseek +# define fileTell _tell +# define fileStat _stat +# define fileHandleStat _fstat +#endif + +//_rename is not defined??? +#define _rename rename + +#define CL_MAX_PATH 260 //give the windef.h value for this... +#define _realpath(rel,abs) _fullpath(abs,rel,CL_MAX_PATH) + +//java long type +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; + +//java int type +typedef int int32_t; +typedef unsigned int uint32_t; + +//java byte type +typedef unsigned char uint8_t; + +//floating point type +//we are going to use qreal now +//typedef double float_t; + +#define _CL_ILONG(x) x ## L +#define _ILONGLONG(x) x ## i64 + + +#elif !defined(_lucene_COMPILER_MSVC2) +#define _lucene_COMPILER_MSVC2 + //second inclusion + + +#elif !defined(_lucene_COMPILER_MSVC3) +#define _lucene_COMPILER_MSVC3 + //third inclusion +#endif diff --git a/3rdparty/clucene/src/CLucene/config/PlatformMac.h b/3rdparty/clucene/src/CLucene/config/PlatformMac.h new file mode 100644 index 000000000..9f6d6f421 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/PlatformMac.h @@ -0,0 +1,19 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +// It is internal CLucene header - DO NOT include it directly + +# define PATH_DELIMITER _T("/") +# define PATH_DELIMITERA "/" +# define PATH_DELIMITERC '/' + +# if (__GNUC__ < 3) && !defined( __APPLE_CC__) +// GCC strange "ignore std" mode works better if you pretend everything +// is in the std namespace, for the most part. +# define LUCENE_NO_STDC_NAMESPACE +# endif + +#undef _T //apple has something else strange here... diff --git a/3rdparty/clucene/src/CLucene/config/PlatformUnix.h b/3rdparty/clucene/src/CLucene/config/PlatformUnix.h new file mode 100644 index 000000000..202a894bd --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/PlatformUnix.h @@ -0,0 +1,12 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +// It is internal CLucene header - DO NOT include it directly + +# define PATH_DELIMITER _T("/") +# define PATH_DELIMITERA "/" +# define PATH_DELIMITERC '/' + diff --git a/3rdparty/clucene/src/CLucene/config/PlatformWin32.h b/3rdparty/clucene/src/CLucene/config/PlatformWin32.h new file mode 100644 index 000000000..8b8a1132e --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/PlatformWin32.h @@ -0,0 +1,11 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +// It is internal CLucene header - DO NOT include it directly + +# define PATH_DELIMITER _T("\\") +# define PATH_DELIMITERA "\\" +# define PATH_DELIMITERC '\\' diff --git a/3rdparty/clucene/src/CLucene/config/compiler.h b/3rdparty/clucene/src/CLucene/config/compiler.h new file mode 100644 index 000000000..68f93b6e4 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/compiler.h @@ -0,0 +1,259 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#if !defined(lucene_compiler_h) +#define lucene_compiler_h + +#if defined(_MBCS) || defined(_ASCII) +#undef _ASCII +#undef _UCS2 +#define _ASCII +#elif defined(_UNICODE) +#define _UCS2 +#elif !defined(_UCS2) +#define _UCS2 +#endif + +//msvc needs unicode define so that it uses unicode library +#ifdef _UCS2 +#undef _UNICODE +#define _UNICODE +#undef _ASCII +#else +#undef _UNICODE +#undef _UCS2 +#endif + + +//////////////////////////////////////////////////////////////////// +// Figure out what compiler we are using +//////////////////////////////////////////////////////////////////// + +#if defined(_MSC_VER) && !defined(__MWERKS__) && !defined (__COMO__) +#define _CLCOMPILER_MSVC _MSC_VER +#endif + +#if defined(__GNUC__) || defined(__SUNPRO_CC) || defined(__xlC__) || defined(__sgi) && defined(__EDG__) +#include "CLucene/config/CompilerGcc.h" + +#elif defined(_CLCOMPILER_MSVC) +/* Microsoft Visual C++ */ +#include "CLucene/config/CompilerMsvc.h" + +#elif defined (__BORLANDC__) +#include "CLucene/config/CompilerBcb.h" + +#elif defined (__HP_aCC) +#include "CLucene/config/CompilerAcc.h" + +#else + //Unable to identify the compiler, issue error diagnostic. + //Edit to set STLport up for your compiler. + //Uncomment this next line +#error "Unable to identify the compiler, issue error diagnostic. Edit to set Lucene up for your compiler." +#include "CLucene/config/LuceneMycomp.h" +#endif /* end of compiler choice */ +//////////////////////////////////////////////////////////////////// + + + +//////////////////////////////////////////////////////////////////// +// Now include platform specific definitions +//////////////////////////////////////////////////////////////////// + +/* Operating system recognition (basic) */ +#if defined (__unix) || defined (__linux__) || defined (__QNX__) || defined (_AIX) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__Lynx__) || defined(hpux) || defined(__hpux) +#undef _UNIX +#define _UNIX 1 +#include "CLucene/config/PlatformUnix.h" + +#elif defined(macintosh) || defined (_MAC) || defined(__APPLE__) +#undef _MAC +#define _MAC 1 +#include "CLucene/config/PlatformMac.h" + +#elif defined (_WIN32) || defined (__WIN32) || defined (WIN32) || defined (__WIN32__) +#undef _WIN32 +#define _WIN32 +#include "CLucene/config/PlatformWin32.h" + +#elif defined (__WIN16) || defined (WIN16) || defined (_WIN16) +#undef _WIN16 +#define _WIN16 +#error "CLucene has not been tested on this platform. Please send a report to the lucene administrators if you are able to successfully compile" +#else +#error "CLucene could not identify the platform." +#endif /* platforms */ + + + +//////////////////////////////////////////////////////////////////// +// Now we take all that we have learnt, and define some things +//////////////////////////////////////////////////////////////////// + +//lets just say that we can always do unicode! :) +#ifdef CL_CHARSET_GUESS +#define _UCS2 +#endif + +#if defined(_ASCII) +#undef _UCS2 +#elif defined(_UCS2) +#undef _ASCII +#endif + +#ifndef _LUCENE_NO_NEW_STYLE_CASTS +#define __CONST_CAST(typ,var) const_cast(var) +#define __REINTERPRET_CAST(typ,var) reinterpret_cast(var) +#else +#define __CONST_CAST(typ,var) ((typ)(var)) +#define __REINTERPRET_CAST,var) ((typ)(var)) +#endif + +#ifndef _CL_DEPRECATE_TEXT +#define _CL_DEPRECATE_TEXT(_Text) +#endif +#define _CL_DEPRECATED(_NewItem) _CL_DEPRECATE_TEXT("This function or variable has been superceded by newer library or operating system functionality. Consider using" #_NewItem "instead. See online help for details.") + + +//cnd-debug exit command +#ifndef debugFatalExit +#define debugFatalExit(ret) exit(ret) +#endif + +#ifndef _CL_ILONG +#define _CL_ILONG(x) x ## L +#endif +#ifndef _ILONGLONG +#define _ILONGLONG(x) x ## LL +#endif + +//define whats the values of item intergers *should* be. we can check this in a test +#define LUCENE_INT64_MAX_SHOULDBE _ILONGLONG(0x7FFFFFFFFFFFFFFF) +#define LUCENE_INT32_MAX_SHOULDBE 0x7FFFFFFFL +#define LUCENE_UINT8_MAX_SHOULDBE 0xff + +//maximum path length. only used for buffers that use fullpath. +//anything else should use a dynamic length. +#if defined(CL_MAX_PATH) +//do nothing... +#elif defined(PATH_MAX) +#define CL_MAX_PATH PATH_MAX +#elif defined(MAX_PATH) +#define CL_MAX_PATH MAX_PATH +#elif defined(_MAX_PATH) +#define CL_MAX_PATH _MAX_PATH +#else + #error "CL_MAX_PATH could not be determined" +#endif + +//this is the max filename... for now its just the same, +//but this could change, so we use a different name +#define CL_MAX_NAME CL_MAX_PATH +//this used to be CL_MAX_NAME * 32, but as Alex Hudson points out, this could come to be 128kb. +//the above logic for CL_MAX_NAME should be correct enough to handle all file names +#define CL_MAX_DIR CL_MAX_PATH + +#ifdef _LARGE_FILES +#define LUCENE_MAX_FILELENGTH LUCENE_INT64_MAX_SHOULDBE +#else +#define LUCENE_MAX_FILELENGTH LUCENE_INT32_MAX_SHOULDBE +#endif + +//use the LUCENE_STATIC_CONSTANT_SYNTAX to determine LUCENE_STATIC_CONSTANT +#ifndef LUCENE_STATIC_CONSTANT + //autoconf is not properly detecting the correct method for this, and since there's no real big + //harm in always using an enum, we'll probably just make this the default. + /*#if LUCENE_STATIC_CONSTANT_SYNTAX == 1 + #define LUCENE_STATIC_CONSTANT(type, assignment) static const type assignment + #elif LUCENE_STATIC_CONSTANT_SYNTAX == 2*/ + #define LUCENE_STATIC_CONSTANT(type, assignment) enum { assignment } + /*#else + #error "LUCENE_STATIC_CONSTANT not defined, and/or LUCENE_STATIC_CONSTANT_SYNTAX is not defined to a valid value" + #endif*/ +#endif + +//end of lucene_compiler_h +#elif !defined(lucene_compiler_h2) +#define lucene_compiler_h2 +//here we include the compiler header again, this gives the header a +//second chance at including stuff, after the main inclusions are complete + +#if defined (__GNUC__) || defined(__SUNPRO_CC) || defined(__xlC__) || defined(__sgi) && defined(__EDG__) +#include "CLucene/config/CompilerGcc.h" + +#elif defined(_CLCOMPILER_MSVC) +/* Microsoft Visual C++ */ +#include "CLucene/config/CompilerMsvc.h" + +#elif defined __BORLANDC__ +#include "CLucene/config/CompilerBcb.h" + +#elif defined (__HP_aCC) +#include "CLucene/config/CompilerAcc.h" + +#else +//Unable to identify the compiler, issue error diagnostic. +//Edit to set STLport up for your compiler. +//Uncomment this next line +#error "Unable to identify the compiler, issue error diagnostic. Edit to set Lucene up for your compiler." +#include "CLucene/config/LuceneMycomp.h" +#endif /* end of compiler choice */ + +#ifndef _CL_HAVE_FLOAT_T +//#ifdef _CL_HAVE_LONG_DOUBLE +// long double's are not working (reported by Mark Ashworth on Solaris 64) +// typedef long double float_t; /* `float' expressions are evaluated as `long double'. */ +//#else +// we are going to use qreal now +// typedef double float_t; +//#endif +#endif + +/*todo: but need to define SIZEOF_VOID_P #if (SIZEOF_VOID_P > 4 && SIZEOF_VOID_P <= 8) +#ifndef _CL_HAVE_INTPTR_T + typedef int64_t intptr_t; +#endif +#elif (SIZEOF_VOID_P > 2 && SIZEOF_VOID_P <= 4) +# ifndef _CL_HAVE_INTPTR_T + typedef int32_t intptr_t; +# endif +#else +#error "void * is either >8 bytes or <= 2. In either case, I am confused." +#endif*/ + +#ifndef _CL_HAVE_INTPTR_T + typedef int intptr_t; +#endif + +//end of lucene_compiler_h2 +#elif !defined(lucene_compiler_h3) +#define lucene_compiler_h3 +//here we include the compiler header again, this gives the header a +//third chance at including stuff, after the main inclusions are complete + +#if defined (__GNUC__ ) || defined(__SUNPRO_CC) || defined(__xlC__) || defined(__sgi) && defined(__EDG__) +#include "CLucene/config/CompilerGcc.h" + +#elif defined(_CLCOMPILER_MSVC) +/* Microsoft Visual C++ */ +#include "CLucene/config/CompilerMsvc.h" + +#elif defined __BORLANDC__ +#include "CLucene/config/CompilerBcb.h" + +#elif defined (__HP_aCC) +#include "CLucene/config/CompilerAcc.h" + +#else +//Unable to identify the compiler, issue error diagnostic. +//Edit to set STLport up for your compiler. +//Uncomment this next line +#error "Unable to identify the compiler, issue error diagnostic. Edit to set Lucene up for your compiler." +#include "CLucene/config/LuceneMycomp.h" +#endif /* end of compiler choice */ + +#endif diff --git a/3rdparty/clucene/src/CLucene/config/define_std.h b/3rdparty/clucene/src/CLucene/config/define_std.h new file mode 100644 index 000000000..22a079053 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/define_std.h @@ -0,0 +1,113 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef lucene_define_std +#define lucene_define_std +//define a standard list of defines. +//These defines represents a fairly complete compiler. +//Of course it is preferable to use the autoconf generated +//list, but then not all systems can do this :) + +//we support long files - 64 bit file functions +#define _LARGE_FILES + +//support namespaces +#define _CL_HAVE_NAMESPACES + +//support try/catch blocks +#define _CL_HAVE_FUNCTION_TRY_BLOCKS + +//the normal headers +#define _CL_STDC_HEADERS +#define _CL_HAVE_STDARG_H +#define _CL_HAVE_ALGORITHM +#define _CL_HAVE_FUNCTIONAL +#define _CL_HAVE_MATH_H +#define _CL_HAVE_STL +#define _CL_HAVE_HASH_MAP +#define _CL_HAVE_HASH_SET +#define _CL_HAVE_MAP +#define _CL_HAVE_SET +#define _CL_HAVE_LIST +#define _CL_HAVE_VECTOR +#define _CL_HAVE_STDEXCEPT +#define _CL_HAVE_ERRNO_H +#define _CL_HAVE_SYS_STAT_H +#define _CL_HAVE_FCNTL_H + +//character & std tchar support +#define _CL_HAVE_TCHAR_H +#ifdef _UCS2 + #define _CL_HAVE_WCTYPE_H + + #define _CL_HAVE_WCSCPY + #define _CL_HAVE_WCSNCPY + #define _CL_HAVE_WCSCAT + #define _CL_HAVE_WCSCHR + #define _CL_HAVE_WCSSTR + #define _CL_HAVE_WCSLEN + #define _CL_HAVE_WCSCMP + #define _CL_HAVE_WCSNCMP + #define _CL_HAVE_WCSCSPN +#else + #define _CL_HAVE_CTYPE_H +#endif + +//already have the normal structures +#define _CL_HAVE_FLOAT_T +#define _CL_HAVE_INTPTR_T + +//system dependant: +#define _CL_HAVE_STRING_H //could be HAVE_STRINGS_H && HAVE_STRCHR +#define _CL_HAVE_SYS_TIMEB_H +#define _CL_HAVE_TIME_H + +#if defined (_WIN32) || defined (__WIN32) || defined (WIN32) || defined (__WIN32__) + #define _CL_HAVE_IO_H + #define _CL_HAVE_DIRECT_H + #define _CL_HAVE_WINDOWS_H +#else + #define _CL_HAVE_UNISTD_H +#endif +#ifdef UNDER_CE +#undef _CL_HAVE_SYS_TIMEB_H +#endif + +//////////////////////////////////////////////// +//now for individual functions. some compilers +//miss these, so must individually define what +//we have +//////////////////////////////////////////////// + +//string functions +#define _CL_HAVE_STRLWR +#define _CL_HAVE_WCSLWR +#define _CL_HAVE_WCSCASECMP +#define _CL_HAVE_STRCASECMP + +//formatting functions +#define _CL_HAVE_SNWPRINTF +#define _CL_HAVE_VSNWPRINTF +#define _CL_HAVE_WPRINTF +#define _CL_HAVE_SNPRINTF +#define _CL_HAVE_PRINTF + + +//conversion functions +#define _CL_HAVE_STRTOLL +#define _CL_HAVE_WCSTOLL +#define _CL_HAVE_WCSTOD +#define _CL_HAVE_LLTOA +#define _CL_HAVE_LLTOW +#define _CL_HAVE_INTPTR_T + +//these ones are not standard (msvc) +//so you will probably need to undefine +//if you are not using msvc +#define _CL_HAVE_FILELENGTH + + +#endif diff --git a/3rdparty/clucene/src/CLucene/config/gunichartables.cpp b/3rdparty/clucene/src/CLucene/config/gunichartables.cpp new file mode 100644 index 000000000..5463936f6 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/gunichartables.cpp @@ -0,0 +1,386 @@ +/* + * Copyright (C) 1999 Tom Tromey + * Copyright (C) 2000 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * + ************************************************ + * Also licensed with permission from Tom Tromey + * and Owen Taylor under the Apache license. + * Original location: + * http://cvs.gnome.org/viewcvs/glib/glib/guniprop.c?view=log + ************************************************ + * + * Copyright 2003-2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +*/ + +#include "CLucene/StdHeader.h" + +typedef unsigned long gunichar; +typedef unsigned short guint16; +typedef short gint16; +typedef char gchar; +typedef unsigned char guchar; + +/* These are the possible character classifications. + * See http://www.unicode.org/Public/UNIDATA/UnicodeData.txt + or http://www.unicode.org/Public/UNIDATA/UCD.html. + + todo: i think there is a new version of the unicode, which we should use. + data is licensed like this: http://www.unicode.org/copyright.html... not sure but looks apache compatible + */ +typedef enum +{ + G_UNICODE_CONTROL, + G_UNICODE_FORMAT, + G_UNICODE_UNASSIGNED, + G_UNICODE_PRIVATE_USE, + G_UNICODE_SURROGATE, + G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_MODIFIER_LETTER, + G_UNICODE_OTHER_LETTER, + G_UNICODE_TITLECASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_COMBINING_MARK, + G_UNICODE_ENCLOSING_MARK, + G_UNICODE_NON_SPACING_MARK, + G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_LETTER_NUMBER, + G_UNICODE_OTHER_NUMBER, + G_UNICODE_CONNECT_PUNCTUATION, + G_UNICODE_DASH_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_FINAL_PUNCTUATION, + G_UNICODE_INITIAL_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CURRENCY_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MATH_SYMBOL, + G_UNICODE_OTHER_SYMBOL, + G_UNICODE_LINE_SEPARATOR, + G_UNICODE_PARAGRAPH_SEPARATOR, + G_UNICODE_SPACE_SEPARATOR +} GUnicodeType; + + +#include "gunichartables.h" + +#define ATTR_TABLE(Page) (((Page) <= G_UNICODE_LAST_PAGE_PART1) \ + ? attr_table_part1[Page] \ + : attr_table_part2[(Page) - 0xe00]) + +#define ATTTABLE(Page, Char) \ + ((ATTR_TABLE(Page) == G_UNICODE_MAX_TABLE_INDEX) ? 0 : (attr_data[ATTR_TABLE(Page)][Char])) + + +#define TTYPE_PART1(Page, Char) \ + ((type_table_part1[Page] >= G_UNICODE_MAX_TABLE_INDEX) \ + ? (type_table_part1[Page] - G_UNICODE_MAX_TABLE_INDEX) \ + : (type_data[type_table_part1[Page]][Char])) + +#define TTYPE_PART2(Page, Char) \ + ((type_table_part2[Page] >= G_UNICODE_MAX_TABLE_INDEX) \ + ? (type_table_part2[Page] - G_UNICODE_MAX_TABLE_INDEX) \ + : (type_data[type_table_part2[Page]][Char])) + +#define TYPE(Char) \ + (((Char) <= G_UNICODE_LAST_CHAR_PART1) \ + ? TTYPE_PART1 ((Char) >> 8, (Char) & 0xff) \ + : (((Char) >= 0xe0000 && (Char) <= G_UNICODE_LAST_CHAR) \ + ? TTYPE_PART2 (((Char) - 0xe0000) >> 8, (Char) & 0xff) \ + : G_UNICODE_UNASSIGNED)) + +/* Count the number of elements in an array. The array must be defined + * as such; using this with a dynamically allocated array will give + * incorrect results. + */ +#define G_N_ELEMENTS(arr) (sizeof (arr) / sizeof ((arr)[0])) + + + + +#if defined(LUCENE_USE_INTERNAL_CHAR_FUNCTIONS) +#ifdef _LUCENE_PRAGMA_WARNINGS + #pragma message ("===== Using internal character function =====") +#else +#if !(defined(Q_OS_SOLARIS) || defined(Q_CC_MIPS)) +#warning "===== Using internal character function =====" +#endif +#endif + +bool cl_isletter(gunichar c) +{ + int t = TYPE (c); + switch(t) + { + case G_UNICODE_LOWERCASE_LETTER: return true; + case G_UNICODE_TITLECASE_LETTER: return true; + case G_UNICODE_UPPERCASE_LETTER: return true; + case G_UNICODE_MODIFIER_LETTER: return true; + case G_UNICODE_OTHER_LETTER: return true; + default: return false; + } +} + +bool cl_isalnum(gunichar c) +{ + int t = TYPE (c); + switch(t) + { + case G_UNICODE_LOWERCASE_LETTER: return true; + case G_UNICODE_TITLECASE_LETTER: return true; + case G_UNICODE_UPPERCASE_LETTER: return true; + case G_UNICODE_MODIFIER_LETTER: return true; + case G_UNICODE_OTHER_LETTER: return true; + case G_UNICODE_DECIMAL_NUMBER: return true; + case G_UNICODE_LETTER_NUMBER: return true; + case G_UNICODE_OTHER_NUMBER: return true; + default: return false; + } +} + +bool cl_isdigit(gunichar c) +{ + int t = TYPE (c); + switch(t) + { + case G_UNICODE_DECIMAL_NUMBER: return true; + case G_UNICODE_LETTER_NUMBER: return true; + case G_UNICODE_OTHER_NUMBER: return true; + default: return false; + } +} + +/** + * cl_isspace: + * @c: a Unicode character + * + * Determines whether a character is a space, tab, or line separator + * (newline, carriage return, etc.). Given some UTF-8 text, obtain a + * character value with lucene_utf8towc(). + * + * (Note: don't use this to do word breaking; you have to use + * Pango or equivalent to get word breaking right, the algorithm + * is fairly complex.) + * + * Return value: %TRUE if @c is a punctuation character + **/ +bool cl_isspace (gunichar c) +{ + switch (c) + { + /* special-case these since Unicode thinks they are not spaces */ + case '\t': + case '\n': + case '\r': + case '\f': + return true; + + default: + { + int t = TYPE ((gunichar)c); + return (t == G_UNICODE_SPACE_SEPARATOR || t == G_UNICODE_LINE_SEPARATOR + || t == G_UNICODE_PARAGRAPH_SEPARATOR); + } + } +} + + + +/** + * cl_tolower: + * @c: a Unicode character. + * + * Converts a character to lower case. + * + * Return value: the result of converting @c to lower case. + * If @c is not an upperlower or titlecase character, + * or has no lowercase equivalent @c is returned unchanged. + **/ +TCHAR cl_tolower (TCHAR ch) +{ + gunichar c=ch; + int t = TYPE ((gunichar)c); + if (t == G_UNICODE_UPPERCASE_LETTER) + { + gunichar val = ATTTABLE (c >> 8, c & 0xff); + if (val >= 0x1000000) + { + const gchar *p = special_case_table + val - 0x1000000; + int len=0; + wchar_t ret=0; + lucene_utf8towc(&ret,p,6); +#ifdef _UCS2 + return ret; +#else + return LUCENE_OOR_CHAR(ret); +#endif + //return cl_utf8_get_char (p, &len); + }else + return val ? val : c; + }else if (t == G_UNICODE_TITLECASE_LETTER){ + unsigned int i; + for (i = 0; i < G_N_ELEMENTS (title_table); ++i) + { + if (title_table[i][0] == c) + return title_table[i][2]; + } + } + return c; +} + +/** + * cl_toupper: + * @c: a Unicode character + * + * Converts a character to uppercase. + * + * Return value: the result of converting @c to uppercase. + * If @c is not an lowercase or titlecase character, + * or has no upper case equivalent @c is returned unchanged. + **/ +TCHAR cl_toupper (TCHAR ch) +{ + gunichar c=ch; + int t = TYPE (c); + if (t == G_UNICODE_LOWERCASE_LETTER) + { + gunichar val = ATTTABLE (c >> 8, c & 0xff); + if (val >= 0x1000000) + { + const gchar *p = special_case_table + val - 0x1000000; + + wchar_t ret=0; + lucene_utf8towc(&ret,p,6); +#ifdef _UCS2 + return ret; +#else + return LUCENE_OOR_CHAR(ret); +#endif + //return lucene_utf8towc (p); + } + else + return val ? val : c; + } + else if (t == G_UNICODE_TITLECASE_LETTER) + { + unsigned int i; + for (i = 0; i < G_N_ELEMENTS (title_table); ++i) + { + if (title_table[i][0] == c) + return title_table[i][1]; + } + } + return c; +} + + + +/** + * cl_tcasefold: + * @str: a unicode string + * + * Converts a string into a form that is independent of case. The + * result will not correspond to any particular case, but can be + * compared for equality or ordered with the results of calling + * cl_tcasefold() on other strings. + * + * Note that calling cl_tcasefold() followed by g_utf8_collate() is + * only an approximation to the correct linguistic case insensitive + * ordering, though it is a fairly good one. Getting this exactly + * right would require a more sophisticated collation function that + * takes case sensitivity into account. GLib does not currently + * provide such a function. + * + * Return value: a newly allocated string, that is a + * case independent form of @str. + **/ +TCHAR cl_tcasefold(const TCHAR ch){ + int start = 0; + int end = G_N_ELEMENTS (casefold_table); + + if (ch >= casefold_table[start].ch && + ch <= casefold_table[end - 1].ch) + { + while (1) + { + int half = (start + end) / 2; + if (ch == casefold_table[half].ch) + { + wchar_t ret=0; + lucene_utf8towc(&ret,casefold_table[half].data,6); + + #ifdef _UCS2 + return ret; + #else + LUCENE_OOR_CHAR(ret) + #endif + }else if (half == start){ + break; + }else if (ch > casefold_table[half].ch){ + start = half; + }else{ + end = half; + } + } + } + return cl_tolower(ch); + +} + + +//this function was not taken from gnome +TCHAR* cl_tcscasefold( TCHAR * str, int len ) //len default is -1 +{ + TCHAR *p = str; + while ((len < 0 || p < str + len) && *p) + { + *p = cl_tcasefold(*p); + p++; + } + return str; +} +//this function was not taken from gnome +int cl_tcscasefoldcmp(const TCHAR * dst, const TCHAR * src){ + TCHAR f,l; + + do{ + f = cl_tcasefold( (*(dst++)) ); + l = cl_tcasefold( (*(src++)) ); + } while ( (f) && (f == l) ); + + return (int)(f - l); +} + +#endif diff --git a/3rdparty/clucene/src/CLucene/config/gunichartables.h b/3rdparty/clucene/src/CLucene/config/gunichartables.h new file mode 100644 index 000000000..182a87054 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/gunichartables.h @@ -0,0 +1,11264 @@ +/* This file is automatically generated. DO NOT EDIT! + Instead, edit gen-unicode-tables.pl and re-run. */ + +#ifndef CHARTABLES_H +#define CHARTABLES_H + +#define G_UNICODE_DATA_VERSION "4.0" + +#define G_UNICODE_LAST_CHAR 0x10ffff + +#define G_UNICODE_MAX_TABLE_INDEX 10000 + +#define G_UNICODE_LAST_CHAR_PART1 0x2FAFF + +#define G_UNICODE_LAST_PAGE_PART1 762 + +static const char type_data[][256] = { + { /* page 0, index 0 */ + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_SPACE_SEPARATOR, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_CURRENCY_SYMBOL, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_MATH_SYMBOL, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_DASH_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_CONNECT_PUNCTUATION, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_MATH_SYMBOL, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_MATH_SYMBOL, G_UNICODE_CONTROL, + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_SPACE_SEPARATOR, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_CURRENCY_SYMBOL, + G_UNICODE_CURRENCY_SYMBOL, G_UNICODE_CURRENCY_SYMBOL, + G_UNICODE_CURRENCY_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_INITIAL_PUNCTUATION, G_UNICODE_MATH_SYMBOL, G_UNICODE_FORMAT, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_OTHER_NUMBER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_FINAL_PUNCTUATION, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_MATH_SYMBOL, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_MATH_SYMBOL, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER + }, + { /* page 1, index 1 */ + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_TITLECASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_TITLECASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_TITLECASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_TITLECASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER + }, + { /* page 2, index 2 */ + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL + }, + { /* page 3, index 3 */ + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_MATH_SYMBOL, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 4, index 4 */ + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, + G_UNICODE_ENCLOSING_MARK, G_UNICODE_ENCLOSING_MARK, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 5, index 5 */ + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_UNASSIGNED, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_DASH_PUNCTUATION, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED + }, + { /* page 6, index 6 */ + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_MODIFIER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_LETTER, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_FORMAT, G_UNICODE_ENCLOSING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_LETTER + }, + { /* page 7, index 7 */ + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_UNASSIGNED, G_UNICODE_FORMAT, G_UNICODE_OTHER_LETTER, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED + }, + { /* page 9, index 8 */ + G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_OTHER_LETTER, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_LETTER, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_COMBINING_MARK, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_CURRENCY_SYMBOL, G_UNICODE_CURRENCY_SYMBOL, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED + }, + { /* page 10, index 9 */ + G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_LETTER, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_UNASSIGNED, + G_UNICODE_CURRENCY_SYMBOL, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED + }, + { /* page 11, index 10 */ + G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_LETTER, + G_UNICODE_COMBINING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_COMBINING_MARK, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_CURRENCY_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 12, index 11 */ + G_UNICODE_UNASSIGNED, G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, G_UNICODE_UNASSIGNED, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_LETTER, + G_UNICODE_COMBINING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_UNASSIGNED, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED + }, + { /* page 13, index 12 */ + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_COMBINING_MARK, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED + }, + { /* page 14, index 13 */ + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_CURRENCY_SYMBOL, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_MODIFIER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED + }, + { /* page 15, index 14 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED + }, + { /* page 16, index 15 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_COMBINING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED + }, + { /* page 17, index 16 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 18, index 17 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER + }, + { /* page 19, index 18 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 20, index 19 */ + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER + }, + { /* page 22, index 20 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_SPACE_SEPARATOR, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 23, index 21 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_COMBINING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_CURRENCY_SYMBOL, + G_UNICODE_OTHER_LETTER, G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED + }, + { /* page 24, index 22 */ + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_DASH_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_SPACE_SEPARATOR, G_UNICODE_UNASSIGNED, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED + }, + { /* page 25, index 23 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL + }, + { /* page 29, index 24 */ + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 30, index 25 */ + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 31, index 26 */ + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_TITLECASE_LETTER, G_UNICODE_TITLECASE_LETTER, + G_UNICODE_TITLECASE_LETTER, G_UNICODE_TITLECASE_LETTER, + G_UNICODE_TITLECASE_LETTER, G_UNICODE_TITLECASE_LETTER, + G_UNICODE_TITLECASE_LETTER, G_UNICODE_TITLECASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_TITLECASE_LETTER, G_UNICODE_TITLECASE_LETTER, + G_UNICODE_TITLECASE_LETTER, G_UNICODE_TITLECASE_LETTER, + G_UNICODE_TITLECASE_LETTER, G_UNICODE_TITLECASE_LETTER, + G_UNICODE_TITLECASE_LETTER, G_UNICODE_TITLECASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_TITLECASE_LETTER, G_UNICODE_TITLECASE_LETTER, + G_UNICODE_TITLECASE_LETTER, G_UNICODE_TITLECASE_LETTER, + G_UNICODE_TITLECASE_LETTER, G_UNICODE_TITLECASE_LETTER, + G_UNICODE_TITLECASE_LETTER, G_UNICODE_TITLECASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_TITLECASE_LETTER, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_TITLECASE_LETTER, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_TITLECASE_LETTER, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_UNASSIGNED + }, + { /* page 32, index 27 */ + G_UNICODE_SPACE_SEPARATOR, G_UNICODE_SPACE_SEPARATOR, + G_UNICODE_SPACE_SEPARATOR, G_UNICODE_SPACE_SEPARATOR, + G_UNICODE_SPACE_SEPARATOR, G_UNICODE_SPACE_SEPARATOR, + G_UNICODE_SPACE_SEPARATOR, G_UNICODE_SPACE_SEPARATOR, + G_UNICODE_SPACE_SEPARATOR, G_UNICODE_SPACE_SEPARATOR, + G_UNICODE_SPACE_SEPARATOR, G_UNICODE_SPACE_SEPARATOR, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_DASH_PUNCTUATION, G_UNICODE_DASH_PUNCTUATION, + G_UNICODE_DASH_PUNCTUATION, G_UNICODE_DASH_PUNCTUATION, + G_UNICODE_DASH_PUNCTUATION, G_UNICODE_DASH_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_INITIAL_PUNCTUATION, G_UNICODE_FINAL_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_INITIAL_PUNCTUATION, + G_UNICODE_INITIAL_PUNCTUATION, G_UNICODE_FINAL_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_INITIAL_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_LINE_SEPARATOR, G_UNICODE_PARAGRAPH_SEPARATOR, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_SPACE_SEPARATOR, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_INITIAL_PUNCTUATION, G_UNICODE_FINAL_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_CONNECT_PUNCTUATION, G_UNICODE_CONNECT_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_MATH_SYMBOL, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_MATH_SYMBOL, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_CONNECT_PUNCTUATION, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_SPACE_SEPARATOR, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_OTHER_NUMBER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_CURRENCY_SYMBOL, + G_UNICODE_CURRENCY_SYMBOL, G_UNICODE_CURRENCY_SYMBOL, + G_UNICODE_CURRENCY_SYMBOL, G_UNICODE_CURRENCY_SYMBOL, + G_UNICODE_CURRENCY_SYMBOL, G_UNICODE_CURRENCY_SYMBOL, + G_UNICODE_CURRENCY_SYMBOL, G_UNICODE_CURRENCY_SYMBOL, + G_UNICODE_CURRENCY_SYMBOL, G_UNICODE_CURRENCY_SYMBOL, + G_UNICODE_CURRENCY_SYMBOL, G_UNICODE_CURRENCY_SYMBOL, + G_UNICODE_CURRENCY_SYMBOL, G_UNICODE_CURRENCY_SYMBOL, + G_UNICODE_CURRENCY_SYMBOL, G_UNICODE_CURRENCY_SYMBOL, + G_UNICODE_CURRENCY_SYMBOL, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_ENCLOSING_MARK, G_UNICODE_ENCLOSING_MARK, + G_UNICODE_ENCLOSING_MARK, G_UNICODE_ENCLOSING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_ENCLOSING_MARK, + G_UNICODE_ENCLOSING_MARK, G_UNICODE_ENCLOSING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED + }, + { /* page 33, index 28 */ + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL + }, + { /* page 35, index 29 */ + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 36, index 30 */ + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER + }, + { /* page 37, index 31 */ + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL + }, + { /* page 38, index 32 */ + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 39, index 33 */ + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL + }, + { /* page 41, index 34 */ + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL + }, + { /* page 43, index 35 */ + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 46, index 36 */ + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 47, index 37 */ + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 48, index 38 */ + G_UNICODE_SPACE_SEPARATOR, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_DASH_PUNCTUATION, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_DASH_PUNCTUATION, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_DASH_PUNCTUATION, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_CONNECT_PUNCTUATION, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_OTHER_LETTER + }, + { /* page 49, index 39 */ + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER + }, + { /* page 50, index 40 */ + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UNASSIGNED + }, + { /* page 77, index 41 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL + }, + { /* page 159, index 42 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 164, index 43 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 215, index 44 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 250, index 45 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 251, index 46 */ + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_MATH_SYMBOL, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER + }, + { /* page 253, index 47 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_CURRENCY_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 254, index 48 */ + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_DASH_PUNCTUATION, G_UNICODE_DASH_PUNCTUATION, + G_UNICODE_CONNECT_PUNCTUATION, G_UNICODE_CONNECT_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_CONNECT_PUNCTUATION, G_UNICODE_CONNECT_PUNCTUATION, + G_UNICODE_CONNECT_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_DASH_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_MATH_SYMBOL, + G_UNICODE_DASH_PUNCTUATION, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_CURRENCY_SYMBOL, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_FORMAT + }, + { /* page 255, index 49 */ + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_CURRENCY_SYMBOL, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_MATH_SYMBOL, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_DASH_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_CONNECT_PUNCTUATION, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_MATH_SYMBOL, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_MATH_SYMBOL, + G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OPEN_PUNCTUATION, + G_UNICODE_CLOSE_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_CONNECT_PUNCTUATION, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_MODIFIER_LETTER, G_UNICODE_MODIFIER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_CURRENCY_SYMBOL, + G_UNICODE_CURRENCY_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_CURRENCY_SYMBOL, G_UNICODE_CURRENCY_SYMBOL, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 256, index 50 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 257, index 51 */ + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED + }, + { /* page 259, index 52 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 260, index 53 */ + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED + }, + { /* page 264, index 54 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 464, index 55 */ + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 465, index 56 */ + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, + G_UNICODE_COMBINING_MARK, G_UNICODE_COMBINING_MARK, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 467, index 57 */ + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 468, index 58 */ + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER + }, + { /* page 469, index 59 */ + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER + }, + { /* page 470, index 60 */ + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_MATH_SYMBOL, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_MATH_SYMBOL, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_MATH_SYMBOL, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER + }, + { /* page 471, index 61 */ + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_MATH_SYMBOL, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_MATH_SYMBOL, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_MATH_SYMBOL, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_MATH_SYMBOL, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_MATH_SYMBOL, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_MATH_SYMBOL, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_MATH_SYMBOL, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER + }, + { /* page 678, index 62 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 762, index 63 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 3584, index 64 */ + G_UNICODE_UNASSIGNED, G_UNICODE_FORMAT, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED + }, + { /* page 3585, index 65 */ + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 4095, index 66 */ + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + }, + { /* page 4351, index 67 */ + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED + } +}; + +/* U+0000 through U+2FAFF */ +static const gint16 type_table_part1[763] = { + 0 /* page 0 */, + 1 /* page 1 */, + 2 /* page 2 */, + 3 /* page 3 */, + 4 /* page 4 */, + 5 /* page 5 */, + 6 /* page 6 */, + 7 /* page 7 */, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + 8 /* page 9 */, + 9 /* page 10 */, + 10 /* page 11 */, + 11 /* page 12 */, + 12 /* page 13 */, + 13 /* page 14 */, + 14 /* page 15 */, + 15 /* page 16 */, + 16 /* page 17 */, + 17 /* page 18 */, + 18 /* page 19 */, + 19 /* page 20 */, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + 20 /* page 22 */, + 21 /* page 23 */, + 22 /* page 24 */, + 23 /* page 25 */, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + 24 /* page 29 */, + 25 /* page 30 */, + 26 /* page 31 */, + 27 /* page 32 */, + 28 /* page 33 */, + G_UNICODE_MATH_SYMBOL + G_UNICODE_MAX_TABLE_INDEX, + 29 /* page 35 */, + 30 /* page 36 */, + 31 /* page 37 */, + 32 /* page 38 */, + 33 /* page 39 */, + G_UNICODE_OTHER_SYMBOL + G_UNICODE_MAX_TABLE_INDEX, + 34 /* page 41 */, + G_UNICODE_MATH_SYMBOL + G_UNICODE_MAX_TABLE_INDEX, + 35 /* page 43 */, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + 36 /* page 46 */, + 37 /* page 47 */, + 38 /* page 48 */, + 39 /* page 49 */, + 40 /* page 50 */, + G_UNICODE_OTHER_SYMBOL + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + 41 /* page 77 */, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + 42 /* page 159 */, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + 43 /* page 164 */, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + 44 /* page 215 */, + G_UNICODE_SURROGATE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_SURROGATE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_SURROGATE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_SURROGATE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_SURROGATE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_SURROGATE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_SURROGATE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_SURROGATE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + 45 /* page 250 */, + 46 /* page 251 */, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + 47 /* page 253 */, + 48 /* page 254 */, + 49 /* page 255 */, + 50 /* page 256 */, + 51 /* page 257 */, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + 52 /* page 259 */, + 53 /* page 260 */, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + 54 /* page 264 */, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + 55 /* page 464 */, + 56 /* page 465 */, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + 57 /* page 467 */, + 58 /* page 468 */, + 59 /* page 469 */, + 60 /* page 470 */, + 61 /* page 471 */, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + 62 /* page 678 */, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + 63 /* page 762 */ +}; + +/* U+E0000 through U+10FFFF */ +static const gint16 type_table_part2[768] = { + 64 /* page 3584 */, + 65 /* page 3585 */, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + 66 /* page 4095 */, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, + 67 /* page 4351 */ +}; + +static const gunichar attr_data[][256] = { + { /* page 0, index 0 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, + 0x0006, 0x0007, 0x0008, 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, + 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, + 0x007a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0041, 0x0042, + 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, + 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, + 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x039c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, + 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, + 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x0000, + 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x1000000, + 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, + 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, 0x00d0, 0x00d1, + 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x0000, 0x00d8, 0x00d9, 0x00da, + 0x00db, 0x00dc, 0x00dd, 0x00de, 0x0178 + }, + { /* page 1, index 1 */ + 0x0101, 0x0100, 0x0103, 0x0102, 0x0105, 0x0104, 0x0107, 0x0106, 0x0109, + 0x0108, 0x010b, 0x010a, 0x010d, 0x010c, 0x010f, 0x010e, 0x0111, 0x0110, + 0x0113, 0x0112, 0x0115, 0x0114, 0x0117, 0x0116, 0x0119, 0x0118, 0x011b, + 0x011a, 0x011d, 0x011c, 0x011f, 0x011e, 0x0121, 0x0120, 0x0123, 0x0122, + 0x0125, 0x0124, 0x0127, 0x0126, 0x0129, 0x0128, 0x012b, 0x012a, 0x012d, + 0x012c, 0x012f, 0x012e, 0x1000007, 0x0049, 0x0133, 0x0132, 0x0135, + 0x0134, 0x0137, 0x0136, 0x0000, 0x013a, 0x0139, 0x013c, 0x013b, 0x013e, + 0x013d, 0x0140, 0x013f, 0x0142, 0x0141, 0x0144, 0x0143, 0x0146, 0x0145, + 0x0148, 0x0147, 0x1000086, 0x014b, 0x014a, 0x014d, 0x014c, 0x014f, + 0x014e, 0x0151, 0x0150, 0x0153, 0x0152, 0x0155, 0x0154, 0x0157, 0x0156, + 0x0159, 0x0158, 0x015b, 0x015a, 0x015d, 0x015c, 0x015f, 0x015e, 0x0161, + 0x0160, 0x0163, 0x0162, 0x0165, 0x0164, 0x0167, 0x0166, 0x0169, 0x0168, + 0x016b, 0x016a, 0x016d, 0x016c, 0x016f, 0x016e, 0x0171, 0x0170, 0x0173, + 0x0172, 0x0175, 0x0174, 0x0177, 0x0176, 0x00ff, 0x017a, 0x0179, 0x017c, + 0x017b, 0x017e, 0x017d, 0x0053, 0x0000, 0x0253, 0x0183, 0x0182, 0x0185, + 0x0184, 0x0254, 0x0188, 0x0187, 0x0256, 0x0257, 0x018c, 0x018b, 0x0000, + 0x01dd, 0x0259, 0x025b, 0x0192, 0x0191, 0x0260, 0x0263, 0x01f6, 0x0269, + 0x0268, 0x0199, 0x0198, 0x0000, 0x0000, 0x026f, 0x0272, 0x0220, 0x0275, + 0x01a1, 0x01a0, 0x01a3, 0x01a2, 0x01a5, 0x01a4, 0x0280, 0x01a8, 0x01a7, + 0x0283, 0x0000, 0x0000, 0x01ad, 0x01ac, 0x0288, 0x01b0, 0x01af, 0x028a, + 0x028b, 0x01b4, 0x01b3, 0x01b6, 0x01b5, 0x0292, 0x01b9, 0x01b8, 0x0000, + 0x0000, 0x01bd, 0x01bc, 0x0000, 0x01f7, 0x0000, 0x0000, 0x0000, 0x0000, + 0x01c6, 0x0000, 0x01c4, 0x01c9, 0x0000, 0x01c7, 0x01cc, 0x0000, 0x01ca, + 0x01ce, 0x01cd, 0x01d0, 0x01cf, 0x01d2, 0x01d1, 0x01d4, 0x01d3, 0x01d6, + 0x01d5, 0x01d8, 0x01d7, 0x01da, 0x01d9, 0x01dc, 0x01db, 0x018e, 0x01df, + 0x01de, 0x01e1, 0x01e0, 0x01e3, 0x01e2, 0x01e5, 0x01e4, 0x01e7, 0x01e6, + 0x01e9, 0x01e8, 0x01eb, 0x01ea, 0x01ed, 0x01ec, 0x01ef, 0x01ee, + 0x10000ad, 0x01f3, 0x0000, 0x01f1, 0x01f5, 0x01f4, 0x0195, 0x01bf, + 0x01f9, 0x01f8, 0x01fb, 0x01fa, 0x01fd, 0x01fc, 0x01ff, 0x01fe + }, + { /* page 2, index 2 */ + 0x0201, 0x0200, 0x0203, 0x0202, 0x0205, 0x0204, 0x0207, 0x0206, 0x0209, + 0x0208, 0x020b, 0x020a, 0x020d, 0x020c, 0x020f, 0x020e, 0x0211, 0x0210, + 0x0213, 0x0212, 0x0215, 0x0214, 0x0217, 0x0216, 0x0219, 0x0218, 0x021b, + 0x021a, 0x021d, 0x021c, 0x021f, 0x021e, 0x019e, 0x0000, 0x0223, 0x0222, + 0x0225, 0x0224, 0x0227, 0x0226, 0x0229, 0x0228, 0x022b, 0x022a, 0x022d, + 0x022c, 0x022f, 0x022e, 0x0231, 0x0230, 0x0233, 0x0232, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0181, 0x0186, 0x0000, 0x0189, 0x018a, 0x0000, 0x018f, + 0x0000, 0x0190, 0x0000, 0x0000, 0x0000, 0x0000, 0x0193, 0x0000, 0x0000, + 0x0194, 0x0000, 0x0000, 0x0000, 0x0000, 0x0197, 0x0196, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x019c, 0x0000, 0x0000, 0x019d, 0x0000, 0x0000, + 0x019f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x01a6, 0x0000, 0x0000, 0x01a9, 0x0000, 0x0000, 0x0000, + 0x0000, 0x01ae, 0x0000, 0x01b1, 0x01b2, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x01b7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* page 3, index 3 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03ac, + 0x0000, 0x03ad, 0x03ae, 0x03af, 0x0000, 0x03cc, 0x0000, 0x03cd, 0x03ce, + 0x100008f, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, + 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, 0x03c0, + 0x03c1, 0x0000, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9, + 0x03ca, 0x03cb, 0x0386, 0x0388, 0x0389, 0x038a, 0x100009e, 0x0391, + 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039a, + 0x039b, 0x039c, 0x039d, 0x039e, 0x039f, 0x03a0, 0x03a1, 0x03a3, 0x03a3, + 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x038c, + 0x038e, 0x038f, 0x0000, 0x0392, 0x0398, 0x0000, 0x0000, 0x0000, 0x03a6, + 0x03a0, 0x0000, 0x03d9, 0x03d8, 0x03db, 0x03da, 0x03dd, 0x03dc, 0x03df, + 0x03de, 0x03e1, 0x03e0, 0x03e3, 0x03e2, 0x03e5, 0x03e4, 0x03e7, 0x03e6, + 0x03e9, 0x03e8, 0x03eb, 0x03ea, 0x03ed, 0x03ec, 0x03ef, 0x03ee, 0x039a, + 0x03a1, 0x03f9, 0x0000, 0x03b8, 0x0395, 0x0000, 0x03f8, 0x03f7, 0x03f2, + 0x03fb, 0x03fa, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* page 4, index 4 */ + 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, + 0x0459, 0x045a, 0x045b, 0x045c, 0x045d, 0x045e, 0x045f, 0x0430, 0x0431, + 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043a, + 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, 0x0440, 0x0441, 0x0442, 0x0443, + 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, + 0x044d, 0x044e, 0x044f, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, + 0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, + 0x041f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, 0x0400, + 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409, + 0x040a, 0x040b, 0x040c, 0x040d, 0x040e, 0x040f, 0x0461, 0x0460, 0x0463, + 0x0462, 0x0465, 0x0464, 0x0467, 0x0466, 0x0469, 0x0468, 0x046b, 0x046a, + 0x046d, 0x046c, 0x046f, 0x046e, 0x0471, 0x0470, 0x0473, 0x0472, 0x0475, + 0x0474, 0x0477, 0x0476, 0x0479, 0x0478, 0x047b, 0x047a, 0x047d, 0x047c, + 0x047f, 0x047e, 0x0481, 0x0480, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x048b, 0x048a, 0x048d, 0x048c, 0x048f, 0x048e, + 0x0491, 0x0490, 0x0493, 0x0492, 0x0495, 0x0494, 0x0497, 0x0496, 0x0499, + 0x0498, 0x049b, 0x049a, 0x049d, 0x049c, 0x049f, 0x049e, 0x04a1, 0x04a0, + 0x04a3, 0x04a2, 0x04a5, 0x04a4, 0x04a7, 0x04a6, 0x04a9, 0x04a8, 0x04ab, + 0x04aa, 0x04ad, 0x04ac, 0x04af, 0x04ae, 0x04b1, 0x04b0, 0x04b3, 0x04b2, + 0x04b5, 0x04b4, 0x04b7, 0x04b6, 0x04b9, 0x04b8, 0x04bb, 0x04ba, 0x04bd, + 0x04bc, 0x04bf, 0x04be, 0x0000, 0x04c2, 0x04c1, 0x04c4, 0x04c3, 0x04c6, + 0x04c5, 0x04c8, 0x04c7, 0x04ca, 0x04c9, 0x04cc, 0x04cb, 0x04ce, 0x04cd, + 0x0000, 0x04d1, 0x04d0, 0x04d3, 0x04d2, 0x04d5, 0x04d4, 0x04d7, 0x04d6, + 0x04d9, 0x04d8, 0x04db, 0x04da, 0x04dd, 0x04dc, 0x04df, 0x04de, 0x04e1, + 0x04e0, 0x04e3, 0x04e2, 0x04e5, 0x04e4, 0x04e7, 0x04e6, 0x04e9, 0x04e8, + 0x04eb, 0x04ea, 0x04ed, 0x04ec, 0x04ef, 0x04ee, 0x04f1, 0x04f0, 0x04f3, + 0x04f2, 0x04f5, 0x04f4, 0x0000, 0x0000, 0x04f9, 0x04f8, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* page 5, index 5 */ + 0x0501, 0x0500, 0x0503, 0x0502, 0x0505, 0x0504, 0x0507, 0x0506, 0x0509, + 0x0508, 0x050b, 0x050a, 0x050d, 0x050c, 0x050f, 0x050e, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, + 0x0566, 0x0567, 0x0568, 0x0569, 0x056a, 0x056b, 0x056c, 0x056d, 0x056e, + 0x056f, 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, + 0x0578, 0x0579, 0x057a, 0x057b, 0x057c, 0x057d, 0x057e, 0x057f, 0x0580, + 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0531, 0x0532, + 0x0533, 0x0534, 0x0535, 0x0536, 0x0537, 0x0538, 0x0539, 0x053a, 0x053b, + 0x053c, 0x053d, 0x053e, 0x053f, 0x0540, 0x0541, 0x0542, 0x0543, 0x0544, + 0x0545, 0x0546, 0x0547, 0x0548, 0x0549, 0x054a, 0x054b, 0x054c, 0x054d, + 0x054e, 0x054f, 0x0550, 0x0551, 0x0552, 0x0553, 0x0554, 0x0555, 0x0556, + 0x1000044, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* page 6, index 6 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, + 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, + 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* page 9, index 7 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, + 0x0006, 0x0007, 0x0008, 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0003, + 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* page 10, index 8 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, + 0x0006, 0x0007, 0x0008, 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0003, + 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* page 11, index 9 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, + 0x0006, 0x0007, 0x0008, 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0003, + 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* page 12, index 10 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, + 0x0006, 0x0007, 0x0008, 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0003, + 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* page 13, index 11 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, + 0x0006, 0x0007, 0x0008, 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* page 14, index 12 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* page 15, index 13 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0003, + 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* page 16, index 14 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* page 19, index 15 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0003, + 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* page 23, index 16 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* page 24, index 17 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, + 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* page 25, index 18 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, + 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* page 30, index 19 */ + 0x1e01, 0x1e00, 0x1e03, 0x1e02, 0x1e05, 0x1e04, 0x1e07, 0x1e06, 0x1e09, + 0x1e08, 0x1e0b, 0x1e0a, 0x1e0d, 0x1e0c, 0x1e0f, 0x1e0e, 0x1e11, 0x1e10, + 0x1e13, 0x1e12, 0x1e15, 0x1e14, 0x1e17, 0x1e16, 0x1e19, 0x1e18, 0x1e1b, + 0x1e1a, 0x1e1d, 0x1e1c, 0x1e1f, 0x1e1e, 0x1e21, 0x1e20, 0x1e23, 0x1e22, + 0x1e25, 0x1e24, 0x1e27, 0x1e26, 0x1e29, 0x1e28, 0x1e2b, 0x1e2a, 0x1e2d, + 0x1e2c, 0x1e2f, 0x1e2e, 0x1e31, 0x1e30, 0x1e33, 0x1e32, 0x1e35, 0x1e34, + 0x1e37, 0x1e36, 0x1e39, 0x1e38, 0x1e3b, 0x1e3a, 0x1e3d, 0x1e3c, 0x1e3f, + 0x1e3e, 0x1e41, 0x1e40, 0x1e43, 0x1e42, 0x1e45, 0x1e44, 0x1e47, 0x1e46, + 0x1e49, 0x1e48, 0x1e4b, 0x1e4a, 0x1e4d, 0x1e4c, 0x1e4f, 0x1e4e, 0x1e51, + 0x1e50, 0x1e53, 0x1e52, 0x1e55, 0x1e54, 0x1e57, 0x1e56, 0x1e59, 0x1e58, + 0x1e5b, 0x1e5a, 0x1e5d, 0x1e5c, 0x1e5f, 0x1e5e, 0x1e61, 0x1e60, 0x1e63, + 0x1e62, 0x1e65, 0x1e64, 0x1e67, 0x1e66, 0x1e69, 0x1e68, 0x1e6b, 0x1e6a, + 0x1e6d, 0x1e6c, 0x1e6f, 0x1e6e, 0x1e71, 0x1e70, 0x1e73, 0x1e72, 0x1e75, + 0x1e74, 0x1e77, 0x1e76, 0x1e79, 0x1e78, 0x1e7b, 0x1e7a, 0x1e7d, 0x1e7c, + 0x1e7f, 0x1e7e, 0x1e81, 0x1e80, 0x1e83, 0x1e82, 0x1e85, 0x1e84, 0x1e87, + 0x1e86, 0x1e89, 0x1e88, 0x1e8b, 0x1e8a, 0x1e8d, 0x1e8c, 0x1e8f, 0x1e8e, + 0x1e91, 0x1e90, 0x1e93, 0x1e92, 0x1e95, 0x1e94, 0x10000b6, 0x10000bf, + 0x10000c8, 0x10000d1, 0x10000da, 0x1e60, 0x0000, 0x0000, 0x0000, 0x0000, + 0x1ea1, 0x1ea0, 0x1ea3, 0x1ea2, 0x1ea5, 0x1ea4, 0x1ea7, 0x1ea6, 0x1ea9, + 0x1ea8, 0x1eab, 0x1eaa, 0x1ead, 0x1eac, 0x1eaf, 0x1eae, 0x1eb1, 0x1eb0, + 0x1eb3, 0x1eb2, 0x1eb5, 0x1eb4, 0x1eb7, 0x1eb6, 0x1eb9, 0x1eb8, 0x1ebb, + 0x1eba, 0x1ebd, 0x1ebc, 0x1ebf, 0x1ebe, 0x1ec1, 0x1ec0, 0x1ec3, 0x1ec2, + 0x1ec5, 0x1ec4, 0x1ec7, 0x1ec6, 0x1ec9, 0x1ec8, 0x1ecb, 0x1eca, 0x1ecd, + 0x1ecc, 0x1ecf, 0x1ece, 0x1ed1, 0x1ed0, 0x1ed3, 0x1ed2, 0x1ed5, 0x1ed4, + 0x1ed7, 0x1ed6, 0x1ed9, 0x1ed8, 0x1edb, 0x1eda, 0x1edd, 0x1edc, 0x1edf, + 0x1ede, 0x1ee1, 0x1ee0, 0x1ee3, 0x1ee2, 0x1ee5, 0x1ee4, 0x1ee7, 0x1ee6, + 0x1ee9, 0x1ee8, 0x1eeb, 0x1eea, 0x1eed, 0x1eec, 0x1eef, 0x1eee, 0x1ef1, + 0x1ef0, 0x1ef3, 0x1ef2, 0x1ef5, 0x1ef4, 0x1ef7, 0x1ef6, 0x1ef9, 0x1ef8, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* page 31, index 20 */ + 0x1f08, 0x1f09, 0x1f0a, 0x1f0b, 0x1f0c, 0x1f0d, 0x1f0e, 0x1f0f, 0x1f00, + 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07, 0x1f18, 0x1f19, + 0x1f1a, 0x1f1b, 0x1f1c, 0x1f1d, 0x0000, 0x0000, 0x1f10, 0x1f11, 0x1f12, + 0x1f13, 0x1f14, 0x1f15, 0x0000, 0x0000, 0x1f28, 0x1f29, 0x1f2a, 0x1f2b, + 0x1f2c, 0x1f2d, 0x1f2e, 0x1f2f, 0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, + 0x1f25, 0x1f26, 0x1f27, 0x1f38, 0x1f39, 0x1f3a, 0x1f3b, 0x1f3c, 0x1f3d, + 0x1f3e, 0x1f3f, 0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, + 0x1f37, 0x1f48, 0x1f49, 0x1f4a, 0x1f4b, 0x1f4c, 0x1f4d, 0x0000, 0x0000, + 0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0x0000, 0x0000, + 0x10000e3, 0x1f59, 0x10000ee, 0x1f5b, 0x10000fd, 0x1f5d, 0x100010c, + 0x1f5f, 0x0000, 0x1f51, 0x0000, 0x1f53, 0x0000, 0x1f55, 0x0000, 0x1f57, + 0x1f68, 0x1f69, 0x1f6a, 0x1f6b, 0x1f6c, 0x1f6d, 0x1f6e, 0x1f6f, 0x1f60, + 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67, 0x1fba, 0x1fbb, + 0x1fc8, 0x1fc9, 0x1fca, 0x1fcb, 0x1fda, 0x1fdb, 0x1ff8, 0x1ff9, 0x1fea, + 0x1feb, 0x1ffa, 0x1ffb, 0x0000, 0x0000, 0x10001b7, 0x10001c4, 0x10001d1, + 0x10001de, 0x10001eb, 0x10001f8, 0x1000205, 0x1000212, 0x100021f, + 0x1000229, 0x1000233, 0x100023d, 0x1000247, 0x1000251, 0x100025b, + 0x1000265, 0x100026f, 0x100027c, 0x1000289, 0x1000296, 0x10002a3, + 0x10002b0, 0x10002bd, 0x10002ca, 0x10002d7, 0x10002e1, 0x10002eb, + 0x10002f5, 0x10002ff, 0x1000309, 0x1000313, 0x100031d, 0x1000327, + 0x1000334, 0x1000341, 0x100034e, 0x100035b, 0x1000368, 0x1000375, + 0x1000382, 0x100038f, 0x1000399, 0x10003a3, 0x10003ad, 0x10003b7, + 0x10003c1, 0x10003cb, 0x10003d5, 0x1fb8, 0x1fb9, 0x100041e, 0x10003df, + 0x100042b, 0x0000, 0x100011b, 0x1000466, 0x1fb0, 0x1fb1, 0x1f70, 0x1f71, + 0x10003eb, 0x0000, 0x0399, 0x0000, 0x0000, 0x0000, 0x1000436, 0x10003f4, + 0x1000443, 0x0000, 0x1000126, 0x1000475, 0x1f72, 0x1f73, 0x1f74, 0x1f75, + 0x1000400, 0x0000, 0x0000, 0x0000, 0x1fd8, 0x1fd9, 0x1000131, 0x1000140, + 0x0000, 0x0000, 0x100014f, 0x100015a, 0x1fd0, 0x1fd1, 0x1f76, 0x1f77, + 0x0000, 0x0000, 0x0000, 0x0000, 0x1fe8, 0x1fe9, 0x1000169, 0x1000178, + 0x1000187, 0x1fec, 0x1000192, 0x100019d, 0x1fe0, 0x1fe1, 0x1f7a, 0x1f7b, + 0x1fe5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x100044e, 0x1000409, + 0x100045b, 0x0000, 0x10001ac, 0x1000484, 0x1f78, 0x1f79, 0x1f7c, 0x1f7d, + 0x1000415, 0x0000, 0x0000, 0x0000 + }, + { /* page 33, index 21 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x03c9, 0x0000, 0x0000, 0x0000, 0x006b, 0x00e5, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* page 251, index 22 */ + 0x100000f, 0x1000016, 0x100001d, 0x1000024, 0x100002d, 0x1000036, + 0x100003d, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x100004f, 0x100005a, 0x1000065, + 0x1000070, 0x100007b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000 + }, + { /* page 255, index 23 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, + 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xff41, 0xff42, 0xff43, + 0xff44, 0xff45, 0xff46, 0xff47, 0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, + 0xff4d, 0xff4e, 0xff4f, 0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, + 0xff56, 0xff57, 0xff58, 0xff59, 0xff5a, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0xff21, 0xff22, 0xff23, 0xff24, 0xff25, 0xff26, 0xff27, + 0xff28, 0xff29, 0xff2a, 0xff2b, 0xff2c, 0xff2d, 0xff2e, 0xff2f, 0xff30, + 0xff31, 0xff32, 0xff33, 0xff34, 0xff35, 0xff36, 0xff37, 0xff38, 0xff39, + 0xff3a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* page 260, index 24 */ + 0x10428, 0x10429, 0x1042a, 0x1042b, 0x1042c, 0x1042d, 0x1042e, 0x1042f, + 0x10430, 0x10431, 0x10432, 0x10433, 0x10434, 0x10435, 0x10436, 0x10437, + 0x10438, 0x10439, 0x1043a, 0x1043b, 0x1043c, 0x1043d, 0x1043e, 0x1043f, + 0x10440, 0x10441, 0x10442, 0x10443, 0x10444, 0x10445, 0x10446, 0x10447, + 0x10448, 0x10449, 0x1044a, 0x1044b, 0x1044c, 0x1044d, 0x1044e, 0x1044f, + 0x10400, 0x10401, 0x10402, 0x10403, 0x10404, 0x10405, 0x10406, 0x10407, + 0x10408, 0x10409, 0x1040a, 0x1040b, 0x1040c, 0x1040d, 0x1040e, 0x1040f, + 0x10410, 0x10411, 0x10412, 0x10413, 0x10414, 0x10415, 0x10416, 0x10417, + 0x10418, 0x10419, 0x1041a, 0x1041b, 0x1041c, 0x1041d, 0x1041e, 0x1041f, + 0x10420, 0x10421, 0x10422, 0x10423, 0x10424, 0x10425, 0x10426, 0x10427, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* page 471, index 25 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, + 0x0009, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, + 0x0007, 0x0008, 0x0009, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, + 0x0006, 0x0007, 0x0008, 0x0009 + } +}; + +/* U+0000 through U+2FAFF */ +static const gint16 attr_table_part1[763] = { + 0 /* page 0 */, + 1 /* page 1 */, + 2 /* page 2 */, + 3 /* page 3 */, + 4 /* page 4 */, + 5 /* page 5 */, + 6 /* page 6 */, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 7 /* page 9 */, + 8 /* page 10 */, + 9 /* page 11 */, + 10 /* page 12 */, + 11 /* page 13 */, + 12 /* page 14 */, + 13 /* page 15 */, + 14 /* page 16 */, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 15 /* page 19 */, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 16 /* page 23 */, + 17 /* page 24 */, + 18 /* page 25 */, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 19 /* page 30 */, + 20 /* page 31 */, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 21 /* page 33 */, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 22 /* page 251 */, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 23 /* page 255 */, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 24 /* page 260 */, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 25 /* page 471 */, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX +}; + +/* U+E0000 through U+10FFFF */ +static const gint16 attr_table_part2[768] = { + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX, + 0x0000 + G_UNICODE_MAX_TABLE_INDEX +}; + +static const gunichar title_table[][3] = { + { 0x01c5, 0x01c4, 0x01c6 }, + { 0x01c8, 0x01c7, 0x01c9 }, + { 0x01cb, 0x01ca, 0x01cc }, + { 0x01f2, 0x01f1, 0x01f3 }, + { 0x1f88, 0x0000, 0x1f80 }, + { 0x1f89, 0x0000, 0x1f81 }, + { 0x1f8a, 0x0000, 0x1f82 }, + { 0x1f8b, 0x0000, 0x1f83 }, + { 0x1f8c, 0x0000, 0x1f84 }, + { 0x1f8d, 0x0000, 0x1f85 }, + { 0x1f8e, 0x0000, 0x1f86 }, + { 0x1f8f, 0x0000, 0x1f87 }, + { 0x1f98, 0x0000, 0x1f90 }, + { 0x1f99, 0x0000, 0x1f91 }, + { 0x1f9a, 0x0000, 0x1f92 }, + { 0x1f9b, 0x0000, 0x1f93 }, + { 0x1f9c, 0x0000, 0x1f94 }, + { 0x1f9d, 0x0000, 0x1f95 }, + { 0x1f9e, 0x0000, 0x1f96 }, + { 0x1f9f, 0x0000, 0x1f97 }, + { 0x1fa8, 0x0000, 0x1fa0 }, + { 0x1fa9, 0x0000, 0x1fa1 }, + { 0x1faa, 0x0000, 0x1fa2 }, + { 0x1fab, 0x0000, 0x1fa3 }, + { 0x1fac, 0x0000, 0x1fa4 }, + { 0x1fad, 0x0000, 0x1fa5 }, + { 0x1fae, 0x0000, 0x1fa6 }, + { 0x1faf, 0x0000, 0x1fa7 }, + { 0x1fbc, 0x0000, 0x1fb3 }, + { 0x1fcc, 0x0000, 0x1fc3 }, + { 0x1ffc, 0x0000, 0x1ff3 } +}; + + +/* Table of special cases for case conversion; each record contains + * First, the best single character mapping to lowercase if Lu, + * and to uppercase if Ll, followed by the output mapping for the two cases + * other than the case of the codepoint, in the order [Ll],[Lu],[Lt], + * encoded in UTF-8, separated and terminated by a null character. + */ +static const gchar special_case_table[] = { + "\x00\x53\x53\x00\x53\x73\0" /* offset 0 */ + "\x69\x69\xcc\x87\x00\xc4\xb0\0" /* offset 7 */ + "\x00\x46\x46\x00\x46\x66\0" /* offset 15 */ + "\x00\x46\x49\x00\x46\x69\0" /* offset 22 */ + "\x00\x46\x4c\x00\x46\x6c\0" /* offset 29 */ + "\x00\x46\x46\x49\x00\x46\x66\x69\0" /* offset 36 */ + "\x00\x46\x46\x4c\x00\x46\x66\x6c\0" /* offset 45 */ + "\x00\x53\x54\x00\x53\x74\0" /* offset 54 */ + "\x00\x53\x54\x00\x53\x74\0" /* offset 61 */ + "\x00\xd4\xb5\xd5\x92\x00\xd4\xb5\xd6\x82\0" /* offset 68 */ + "\x00\xd5\x84\xd5\x86\x00\xd5\x84\xd5\xb6\0" /* offset 79 */ + "\x00\xd5\x84\xd4\xb5\x00\xd5\x84\xd5\xa5\0" /* offset 90 */ + "\x00\xd5\x84\xd4\xbb\x00\xd5\x84\xd5\xab\0" /* offset 101 */ + "\x00\xd5\x8e\xd5\x86\x00\xd5\x8e\xd5\xb6\0" /* offset 112 */ + "\x00\xd5\x84\xd4\xbd\x00\xd5\x84\xd5\xad\0" /* offset 123 */ + "\x00\xca\xbc\x4e\x00\xca\xbc\x4e\0" /* offset 134 */ + "\x00\xce\x99\xcc\x88\xcc\x81\x00\xce\x99\xcc\x88\xcc\x81\0" /* offset 143 */ + "\x00\xce\xa5\xcc\x88\xcc\x81\x00\xce\xa5\xcc\x88\xcc\x81\0" /* offset 158 */ + "\x00\x4a\xcc\x8c\x00\x4a\xcc\x8c\0" /* offset 173 */ + "\x00\x48\xcc\xb1\x00\x48\xcc\xb1\0" /* offset 182 */ + "\x00\x54\xcc\x88\x00\x54\xcc\x88\0" /* offset 191 */ + "\x00\x57\xcc\x8a\x00\x57\xcc\x8a\0" /* offset 200 */ + "\x00\x59\xcc\x8a\x00\x59\xcc\x8a\0" /* offset 209 */ + "\x00\x41\xca\xbe\x00\x41\xca\xbe\0" /* offset 218 */ + "\x00\xce\xa5\xcc\x93\x00\xce\xa5\xcc\x93\0" /* offset 227 */ + "\x00\xce\xa5\xcc\x93\xcc\x80\x00\xce\xa5\xcc\x93\xcc\x80\0" /* offset 238 */ + "\x00\xce\xa5\xcc\x93\xcc\x81\x00\xce\xa5\xcc\x93\xcc\x81\0" /* offset 253 */ + "\x00\xce\xa5\xcc\x93\xcd\x82\x00\xce\xa5\xcc\x93\xcd\x82\0" /* offset 268 */ + "\x00\xce\x91\xcd\x82\x00\xce\x91\xcd\x82\0" /* offset 283 */ + "\x00\xce\x97\xcd\x82\x00\xce\x97\xcd\x82\0" /* offset 294 */ + "\x00\xce\x99\xcc\x88\xcc\x80\x00\xce\x99\xcc\x88\xcc\x80\0" /* offset 305 */ + "\x00\xce\x99\xcc\x88\xcc\x81\x00\xce\x99\xcc\x88\xcc\x81\0" /* offset 320 */ + "\x00\xce\x99\xcd\x82\x00\xce\x99\xcd\x82\0" /* offset 335 */ + "\x00\xce\x99\xcc\x88\xcd\x82\x00\xce\x99\xcc\x88\xcd\x82\0" /* offset 346 */ + "\x00\xce\xa5\xcc\x88\xcc\x80\x00\xce\xa5\xcc\x88\xcc\x80\0" /* offset 361 */ + "\x00\xce\xa5\xcc\x88\xcc\x81\x00\xce\xa5\xcc\x88\xcc\x81\0" /* offset 376 */ + "\x00\xce\xa1\xcc\x93\x00\xce\xa1\xcc\x93\0" /* offset 391 */ + "\x00\xce\xa5\xcd\x82\x00\xce\xa5\xcd\x82\0" /* offset 402 */ + "\x00\xce\xa5\xcc\x88\xcd\x82\x00\xce\xa5\xcc\x88\xcd\x82\0" /* offset 413 */ + "\x00\xce\xa9\xcd\x82\x00\xce\xa9\xcd\x82\0" /* offset 428 */ + "\xe1\xbe\x88\xe1\xbc\x88\xce\x99\x00\xe1\xbe\x88\0" /* offset 439 */ + "\xe1\xbe\x89\xe1\xbc\x89\xce\x99\x00\xe1\xbe\x89\0" /* offset 452 */ + "\xe1\xbe\x8a\xe1\xbc\x8a\xce\x99\x00\xe1\xbe\x8a\0" /* offset 465 */ + "\xe1\xbe\x8b\xe1\xbc\x8b\xce\x99\x00\xe1\xbe\x8b\0" /* offset 478 */ + "\xe1\xbe\x8c\xe1\xbc\x8c\xce\x99\x00\xe1\xbe\x8c\0" /* offset 491 */ + "\xe1\xbe\x8d\xe1\xbc\x8d\xce\x99\x00\xe1\xbe\x8d\0" /* offset 504 */ + "\xe1\xbe\x8e\xe1\xbc\x8e\xce\x99\x00\xe1\xbe\x8e\0" /* offset 517 */ + "\xe1\xbe\x8f\xe1\xbc\x8f\xce\x99\x00\xe1\xbe\x8f\0" /* offset 530 */ + "\xe1\xbe\x80\x00\xe1\xbc\x88\xce\x99\0" /* offset 543 */ + "\xe1\xbe\x81\x00\xe1\xbc\x89\xce\x99\0" /* offset 553 */ + "\xe1\xbe\x82\x00\xe1\xbc\x8a\xce\x99\0" /* offset 563 */ + "\xe1\xbe\x83\x00\xe1\xbc\x8b\xce\x99\0" /* offset 573 */ + "\xe1\xbe\x84\x00\xe1\xbc\x8c\xce\x99\0" /* offset 583 */ + "\xe1\xbe\x85\x00\xe1\xbc\x8d\xce\x99\0" /* offset 593 */ + "\xe1\xbe\x86\x00\xe1\xbc\x8e\xce\x99\0" /* offset 603 */ + "\xe1\xbe\x87\x00\xe1\xbc\x8f\xce\x99\0" /* offset 613 */ + "\xe1\xbe\x98\xe1\xbc\xa8\xce\x99\x00\xe1\xbe\x98\0" /* offset 623 */ + "\xe1\xbe\x99\xe1\xbc\xa9\xce\x99\x00\xe1\xbe\x99\0" /* offset 636 */ + "\xe1\xbe\x9a\xe1\xbc\xaa\xce\x99\x00\xe1\xbe\x9a\0" /* offset 649 */ + "\xe1\xbe\x9b\xe1\xbc\xab\xce\x99\x00\xe1\xbe\x9b\0" /* offset 662 */ + "\xe1\xbe\x9c\xe1\xbc\xac\xce\x99\x00\xe1\xbe\x9c\0" /* offset 675 */ + "\xe1\xbe\x9d\xe1\xbc\xad\xce\x99\x00\xe1\xbe\x9d\0" /* offset 688 */ + "\xe1\xbe\x9e\xe1\xbc\xae\xce\x99\x00\xe1\xbe\x9e\0" /* offset 701 */ + "\xe1\xbe\x9f\xe1\xbc\xaf\xce\x99\x00\xe1\xbe\x9f\0" /* offset 714 */ + "\xe1\xbe\x90\x00\xe1\xbc\xa8\xce\x99\0" /* offset 727 */ + "\xe1\xbe\x91\x00\xe1\xbc\xa9\xce\x99\0" /* offset 737 */ + "\xe1\xbe\x92\x00\xe1\xbc\xaa\xce\x99\0" /* offset 747 */ + "\xe1\xbe\x93\x00\xe1\xbc\xab\xce\x99\0" /* offset 757 */ + "\xe1\xbe\x94\x00\xe1\xbc\xac\xce\x99\0" /* offset 767 */ + "\xe1\xbe\x95\x00\xe1\xbc\xad\xce\x99\0" /* offset 777 */ + "\xe1\xbe\x96\x00\xe1\xbc\xae\xce\x99\0" /* offset 787 */ + "\xe1\xbe\x97\x00\xe1\xbc\xaf\xce\x99\0" /* offset 797 */ + "\xe1\xbe\xa8\xe1\xbd\xa8\xce\x99\x00\xe1\xbe\xa8\0" /* offset 807 */ + "\xe1\xbe\xa9\xe1\xbd\xa9\xce\x99\x00\xe1\xbe\xa9\0" /* offset 820 */ + "\xe1\xbe\xaa\xe1\xbd\xaa\xce\x99\x00\xe1\xbe\xaa\0" /* offset 833 */ + "\xe1\xbe\xab\xe1\xbd\xab\xce\x99\x00\xe1\xbe\xab\0" /* offset 846 */ + "\xe1\xbe\xac\xe1\xbd\xac\xce\x99\x00\xe1\xbe\xac\0" /* offset 859 */ + "\xe1\xbe\xad\xe1\xbd\xad\xce\x99\x00\xe1\xbe\xad\0" /* offset 872 */ + "\xe1\xbe\xae\xe1\xbd\xae\xce\x99\x00\xe1\xbe\xae\0" /* offset 885 */ + "\xe1\xbe\xaf\xe1\xbd\xaf\xce\x99\x00\xe1\xbe\xaf\0" /* offset 898 */ + "\xe1\xbe\xa0\x00\xe1\xbd\xa8\xce\x99\0" /* offset 911 */ + "\xe1\xbe\xa1\x00\xe1\xbd\xa9\xce\x99\0" /* offset 921 */ + "\xe1\xbe\xa2\x00\xe1\xbd\xaa\xce\x99\0" /* offset 931 */ + "\xe1\xbe\xa3\x00\xe1\xbd\xab\xce\x99\0" /* offset 941 */ + "\xe1\xbe\xa4\x00\xe1\xbd\xac\xce\x99\0" /* offset 951 */ + "\xe1\xbe\xa5\x00\xe1\xbd\xad\xce\x99\0" /* offset 961 */ + "\xe1\xbe\xa6\x00\xe1\xbd\xae\xce\x99\0" /* offset 971 */ + "\xe1\xbe\xa7\x00\xe1\xbd\xaf\xce\x99\0" /* offset 981 */ + "\xe1\xbe\xbc\xce\x91\xce\x99\x00\xe1\xbe\xbc\0" /* offset 991 */ + "\xe1\xbe\xb3\x00\xce\x91\xce\x99\0" /* offset 1003 */ + "\xe1\xbf\x8c\xce\x97\xce\x99\x00\xe1\xbf\x8c\0" /* offset 1012 */ + "\xe1\xbf\x83\x00\xce\x97\xce\x99\0" /* offset 1024 */ + "\xe1\xbf\xbc\xce\xa9\xce\x99\x00\xe1\xbf\xbc\0" /* offset 1033 */ + "\xe1\xbf\xb3\x00\xce\xa9\xce\x99\0" /* offset 1045 */ + "\x00\xe1\xbe\xba\xce\x99\x00\xe1\xbe\xba\xcd\x85\0" /* offset 1054 */ + "\x00\xce\x86\xce\x99\x00\xce\x86\xcd\x85\0" /* offset 1067 */ + "\x00\xe1\xbf\x8a\xce\x99\x00\xe1\xbf\x8a\xcd\x85\0" /* offset 1078 */ + "\x00\xce\x89\xce\x99\x00\xce\x89\xcd\x85\0" /* offset 1091 */ + "\x00\xe1\xbf\xba\xce\x99\x00\xe1\xbf\xba\xcd\x85\0" /* offset 1102 */ + "\x00\xce\x8f\xce\x99\x00\xce\x8f\xcd\x85\0" /* offset 1115 */ + "\x00\xce\x91\xcd\x82\xce\x99\x00\xce\x91\xcd\x82\xcd\x85\0" /* offset 1126 */ + "\x00\xce\x97\xcd\x82\xce\x99\x00\xce\x97\xcd\x82\xcd\x85\0" /* offset 1141 */ + "\x00\xce\xa9\xcd\x82\xce\x99\x00\xce\xa9\xcd\x82\xcd\x85\0" /* offset 1156 */ +}; + + +/* Table of casefolding cases that can't be derived by lowercasing + */ +static const struct { + guint16 ch; + gchar data[7]; +} casefold_table[] = { + { 0x00b5, "\xce\xbc" }, + { 0x00df, "\x73\x73" }, + { 0x0130, "\x69\xcc\x87" }, + { 0x0149, "\xca\xbc\x6e" }, + { 0x017f, "\x73" }, + { 0x01f0, "\x6a\xcc\x8c" }, + { 0x0345, "\xce\xb9" }, + { 0x0390, "\xce\xb9\xcc\x88\xcc\x81" }, + { 0x03b0, "\xcf\x85\xcc\x88\xcc\x81" }, + { 0x03c2, "\xcf\x83" }, + { 0x03d0, "\xce\xb2" }, + { 0x03d1, "\xce\xb8" }, + { 0x03d5, "\xcf\x86" }, + { 0x03d6, "\xcf\x80" }, + { 0x03f0, "\xce\xba" }, + { 0x03f1, "\xcf\x81" }, + { 0x03f5, "\xce\xb5" }, + { 0x0587, "\xd5\xa5\xd6\x82" }, + { 0x1e96, "\x68\xcc\xb1" }, + { 0x1e97, "\x74\xcc\x88" }, + { 0x1e98, "\x77\xcc\x8a" }, + { 0x1e99, "\x79\xcc\x8a" }, + { 0x1e9a, "\x61\xca\xbe" }, + { 0x1e9b, "\xe1\xb9\xa1" }, + { 0x1f50, "\xcf\x85\xcc\x93" }, + { 0x1f52, "\xcf\x85\xcc\x93\xcc\x80" }, + { 0x1f54, "\xcf\x85\xcc\x93\xcc\x81" }, + { 0x1f56, "\xcf\x85\xcc\x93\xcd\x82" }, + { 0x1f80, "\xe1\xbc\x80\xce\xb9" }, + { 0x1f81, "\xe1\xbc\x81\xce\xb9" }, + { 0x1f82, "\xe1\xbc\x82\xce\xb9" }, + { 0x1f83, "\xe1\xbc\x83\xce\xb9" }, + { 0x1f84, "\xe1\xbc\x84\xce\xb9" }, + { 0x1f85, "\xe1\xbc\x85\xce\xb9" }, + { 0x1f86, "\xe1\xbc\x86\xce\xb9" }, + { 0x1f87, "\xe1\xbc\x87\xce\xb9" }, + { 0x1f88, "\xe1\xbc\x80\xce\xb9" }, + { 0x1f89, "\xe1\xbc\x81\xce\xb9" }, + { 0x1f8a, "\xe1\xbc\x82\xce\xb9" }, + { 0x1f8b, "\xe1\xbc\x83\xce\xb9" }, + { 0x1f8c, "\xe1\xbc\x84\xce\xb9" }, + { 0x1f8d, "\xe1\xbc\x85\xce\xb9" }, + { 0x1f8e, "\xe1\xbc\x86\xce\xb9" }, + { 0x1f8f, "\xe1\xbc\x87\xce\xb9" }, + { 0x1f90, "\xe1\xbc\xa0\xce\xb9" }, + { 0x1f91, "\xe1\xbc\xa1\xce\xb9" }, + { 0x1f92, "\xe1\xbc\xa2\xce\xb9" }, + { 0x1f93, "\xe1\xbc\xa3\xce\xb9" }, + { 0x1f94, "\xe1\xbc\xa4\xce\xb9" }, + { 0x1f95, "\xe1\xbc\xa5\xce\xb9" }, + { 0x1f96, "\xe1\xbc\xa6\xce\xb9" }, + { 0x1f97, "\xe1\xbc\xa7\xce\xb9" }, + { 0x1f98, "\xe1\xbc\xa0\xce\xb9" }, + { 0x1f99, "\xe1\xbc\xa1\xce\xb9" }, + { 0x1f9a, "\xe1\xbc\xa2\xce\xb9" }, + { 0x1f9b, "\xe1\xbc\xa3\xce\xb9" }, + { 0x1f9c, "\xe1\xbc\xa4\xce\xb9" }, + { 0x1f9d, "\xe1\xbc\xa5\xce\xb9" }, + { 0x1f9e, "\xe1\xbc\xa6\xce\xb9" }, + { 0x1f9f, "\xe1\xbc\xa7\xce\xb9" }, + { 0x1fa0, "\xe1\xbd\xa0\xce\xb9" }, + { 0x1fa1, "\xe1\xbd\xa1\xce\xb9" }, + { 0x1fa2, "\xe1\xbd\xa2\xce\xb9" }, + { 0x1fa3, "\xe1\xbd\xa3\xce\xb9" }, + { 0x1fa4, "\xe1\xbd\xa4\xce\xb9" }, + { 0x1fa5, "\xe1\xbd\xa5\xce\xb9" }, + { 0x1fa6, "\xe1\xbd\xa6\xce\xb9" }, + { 0x1fa7, "\xe1\xbd\xa7\xce\xb9" }, + { 0x1fa8, "\xe1\xbd\xa0\xce\xb9" }, + { 0x1fa9, "\xe1\xbd\xa1\xce\xb9" }, + { 0x1faa, "\xe1\xbd\xa2\xce\xb9" }, + { 0x1fab, "\xe1\xbd\xa3\xce\xb9" }, + { 0x1fac, "\xe1\xbd\xa4\xce\xb9" }, + { 0x1fad, "\xe1\xbd\xa5\xce\xb9" }, + { 0x1fae, "\xe1\xbd\xa6\xce\xb9" }, + { 0x1faf, "\xe1\xbd\xa7\xce\xb9" }, + { 0x1fb2, "\xe1\xbd\xb0\xce\xb9" }, + { 0x1fb3, "\xce\xb1\xce\xb9" }, + { 0x1fb4, "\xce\xac\xce\xb9" }, + { 0x1fb6, "\xce\xb1\xcd\x82" }, + { 0x1fb7, "\xce\xb1\xcd\x82\xce\xb9" }, + { 0x1fbc, "\xce\xb1\xce\xb9" }, + { 0x1fbe, "\xce\xb9" }, + { 0x1fc2, "\xe1\xbd\xb4\xce\xb9" }, + { 0x1fc3, "\xce\xb7\xce\xb9" }, + { 0x1fc4, "\xce\xae\xce\xb9" }, + { 0x1fc6, "\xce\xb7\xcd\x82" }, + { 0x1fc7, "\xce\xb7\xcd\x82\xce\xb9" }, + { 0x1fcc, "\xce\xb7\xce\xb9" }, + { 0x1fd2, "\xce\xb9\xcc\x88\xcc\x80" }, + { 0x1fd3, "\xce\xb9\xcc\x88\xcc\x81" }, + { 0x1fd6, "\xce\xb9\xcd\x82" }, + { 0x1fd7, "\xce\xb9\xcc\x88\xcd\x82" }, + { 0x1fe2, "\xcf\x85\xcc\x88\xcc\x80" }, + { 0x1fe3, "\xcf\x85\xcc\x88\xcc\x81" }, + { 0x1fe4, "\xcf\x81\xcc\x93" }, + { 0x1fe6, "\xcf\x85\xcd\x82" }, + { 0x1fe7, "\xcf\x85\xcc\x88\xcd\x82" }, + { 0x1ff2, "\xe1\xbd\xbc\xce\xb9" }, + { 0x1ff3, "\xcf\x89\xce\xb9" }, + { 0x1ff4, "\xcf\x8e\xce\xb9" }, + { 0x1ff6, "\xcf\x89\xcd\x82" }, + { 0x1ff7, "\xcf\x89\xcd\x82\xce\xb9" }, + { 0x1ffc, "\xcf\x89\xce\xb9" }, + { 0x2160, "\xe2\x85\xb0" }, + { 0x2161, "\xe2\x85\xb1" }, + { 0x2162, "\xe2\x85\xb2" }, + { 0x2163, "\xe2\x85\xb3" }, + { 0x2164, "\xe2\x85\xb4" }, + { 0x2165, "\xe2\x85\xb5" }, + { 0x2166, "\xe2\x85\xb6" }, + { 0x2167, "\xe2\x85\xb7" }, + { 0x2168, "\xe2\x85\xb8" }, + { 0x2169, "\xe2\x85\xb9" }, + { 0x216a, "\xe2\x85\xba" }, + { 0x216b, "\xe2\x85\xbb" }, + { 0x216c, "\xe2\x85\xbc" }, + { 0x216d, "\xe2\x85\xbd" }, + { 0x216e, "\xe2\x85\xbe" }, + { 0x216f, "\xe2\x85\xbf" }, + { 0x24b6, "\xe2\x93\x90" }, + { 0x24b7, "\xe2\x93\x91" }, + { 0x24b8, "\xe2\x93\x92" }, + { 0x24b9, "\xe2\x93\x93" }, + { 0x24ba, "\xe2\x93\x94" }, + { 0x24bb, "\xe2\x93\x95" }, + { 0x24bc, "\xe2\x93\x96" }, + { 0x24bd, "\xe2\x93\x97" }, + { 0x24be, "\xe2\x93\x98" }, + { 0x24bf, "\xe2\x93\x99" }, + { 0x24c0, "\xe2\x93\x9a" }, + { 0x24c1, "\xe2\x93\x9b" }, + { 0x24c2, "\xe2\x93\x9c" }, + { 0x24c3, "\xe2\x93\x9d" }, + { 0x24c4, "\xe2\x93\x9e" }, + { 0x24c5, "\xe2\x93\x9f" }, + { 0x24c6, "\xe2\x93\xa0" }, + { 0x24c7, "\xe2\x93\xa1" }, + { 0x24c8, "\xe2\x93\xa2" }, + { 0x24c9, "\xe2\x93\xa3" }, + { 0x24ca, "\xe2\x93\xa4" }, + { 0x24cb, "\xe2\x93\xa5" }, + { 0x24cc, "\xe2\x93\xa6" }, + { 0x24cd, "\xe2\x93\xa7" }, + { 0x24ce, "\xe2\x93\xa8" }, + { 0x24cf, "\xe2\x93\xa9" }, + { 0xfb00, "\x66\x66" }, + { 0xfb01, "\x66\x69" }, + { 0xfb02, "\x66\x6c" }, + { 0xfb03, "\x66\x66\x69" }, + { 0xfb04, "\x66\x66\x6c" }, + { 0xfb05, "\x73\x74" }, + { 0xfb06, "\x73\x74" }, + { 0xfb13, "\xd5\xb4\xd5\xb6" }, + { 0xfb14, "\xd5\xb4\xd5\xa5" }, + { 0xfb15, "\xd5\xb4\xd5\xab" }, + { 0xfb16, "\xd5\xbe\xd5\xb6" }, + { 0xfb17, "\xd5\xb4\xd5\xad" }, +}; + +static const struct { + gunichar ch; + gunichar mirrored_ch; +} bidi_mirroring_table[] = +{ + { 0x0028, 0x0029 }, + { 0x0029, 0x0028 }, + { 0x003c, 0x003e }, + { 0x003e, 0x003c }, + { 0x005b, 0x005d }, + { 0x005d, 0x005b }, + { 0x007b, 0x007d }, + { 0x007d, 0x007b }, + { 0x00ab, 0x00bb }, + { 0x00bb, 0x00ab }, + { 0x2039, 0x203a }, + { 0x203a, 0x2039 }, + { 0x2045, 0x2046 }, + { 0x2046, 0x2045 }, + { 0x207d, 0x207e }, + { 0x207e, 0x207d }, + { 0x208d, 0x208e }, + { 0x208e, 0x208d }, + { 0x2208, 0x220b }, + { 0x2209, 0x220c }, + { 0x220a, 0x220d }, + { 0x220b, 0x2208 }, + { 0x220c, 0x2209 }, + { 0x220d, 0x220a }, + { 0x2215, 0x29f5 }, + { 0x223c, 0x223d }, + { 0x223d, 0x223c }, + { 0x2243, 0x22cd }, + { 0x2252, 0x2253 }, + { 0x2253, 0x2252 }, + { 0x2254, 0x2255 }, + { 0x2255, 0x2254 }, + { 0x2264, 0x2265 }, + { 0x2265, 0x2264 }, + { 0x2266, 0x2267 }, + { 0x2267, 0x2266 }, + { 0x2268, 0x2269 }, + { 0x2269, 0x2268 }, + { 0x226a, 0x226b }, + { 0x226b, 0x226a }, + { 0x226e, 0x226f }, + { 0x226f, 0x226e }, + { 0x2270, 0x2271 }, + { 0x2271, 0x2270 }, + { 0x2272, 0x2273 }, + { 0x2273, 0x2272 }, + { 0x2274, 0x2275 }, + { 0x2275, 0x2274 }, + { 0x2276, 0x2277 }, + { 0x2277, 0x2276 }, + { 0x2278, 0x2279 }, + { 0x2279, 0x2278 }, + { 0x227a, 0x227b }, + { 0x227b, 0x227a }, + { 0x227c, 0x227d }, + { 0x227d, 0x227c }, + { 0x227e, 0x227f }, + { 0x227f, 0x227e }, + { 0x2280, 0x2281 }, + { 0x2281, 0x2280 }, + { 0x2282, 0x2283 }, + { 0x2283, 0x2282 }, + { 0x2284, 0x2285 }, + { 0x2285, 0x2284 }, + { 0x2286, 0x2287 }, + { 0x2287, 0x2286 }, + { 0x2288, 0x2289 }, + { 0x2289, 0x2288 }, + { 0x228a, 0x228b }, + { 0x228b, 0x228a }, + { 0x228f, 0x2290 }, + { 0x2290, 0x228f }, + { 0x2291, 0x2292 }, + { 0x2292, 0x2291 }, + { 0x2298, 0x29b8 }, + { 0x22a2, 0x22a3 }, + { 0x22a3, 0x22a2 }, + { 0x22a6, 0x2ade }, + { 0x22a8, 0x2ae4 }, + { 0x22a9, 0x2ae3 }, + { 0x22ab, 0x2ae5 }, + { 0x22b0, 0x22b1 }, + { 0x22b1, 0x22b0 }, + { 0x22b2, 0x22b3 }, + { 0x22b3, 0x22b2 }, + { 0x22b4, 0x22b5 }, + { 0x22b5, 0x22b4 }, + { 0x22b6, 0x22b7 }, + { 0x22b7, 0x22b6 }, + { 0x22c9, 0x22ca }, + { 0x22ca, 0x22c9 }, + { 0x22cb, 0x22cc }, + { 0x22cc, 0x22cb }, + { 0x22cd, 0x2243 }, + { 0x22d0, 0x22d1 }, + { 0x22d1, 0x22d0 }, + { 0x22d6, 0x22d7 }, + { 0x22d7, 0x22d6 }, + { 0x22d8, 0x22d9 }, + { 0x22d9, 0x22d8 }, + { 0x22da, 0x22db }, + { 0x22db, 0x22da }, + { 0x22dc, 0x22dd }, + { 0x22dd, 0x22dc }, + { 0x22de, 0x22df }, + { 0x22df, 0x22de }, + { 0x22e0, 0x22e1 }, + { 0x22e1, 0x22e0 }, + { 0x22e2, 0x22e3 }, + { 0x22e3, 0x22e2 }, + { 0x22e4, 0x22e5 }, + { 0x22e5, 0x22e4 }, + { 0x22e6, 0x22e7 }, + { 0x22e7, 0x22e6 }, + { 0x22e8, 0x22e9 }, + { 0x22e9, 0x22e8 }, + { 0x22ea, 0x22eb }, + { 0x22eb, 0x22ea }, + { 0x22ec, 0x22ed }, + { 0x22ed, 0x22ec }, + { 0x22f0, 0x22f1 }, + { 0x22f1, 0x22f0 }, + { 0x22f2, 0x22fa }, + { 0x22f3, 0x22fb }, + { 0x22f4, 0x22fc }, + { 0x22f6, 0x22fd }, + { 0x22f7, 0x22fe }, + { 0x22fa, 0x22f2 }, + { 0x22fb, 0x22f3 }, + { 0x22fc, 0x22f4 }, + { 0x22fd, 0x22f6 }, + { 0x22fe, 0x22f7 }, + { 0x2308, 0x2309 }, + { 0x2309, 0x2308 }, + { 0x230a, 0x230b }, + { 0x230b, 0x230a }, + { 0x2329, 0x232a }, + { 0x232a, 0x2329 }, + { 0x2768, 0x2769 }, + { 0x2769, 0x2768 }, + { 0x276a, 0x276b }, + { 0x276b, 0x276a }, + { 0x276c, 0x276d }, + { 0x276d, 0x276c }, + { 0x276e, 0x276f }, + { 0x276f, 0x276e }, + { 0x2770, 0x2771 }, + { 0x2771, 0x2770 }, + { 0x2772, 0x2773 }, + { 0x2773, 0x2772 }, + { 0x2774, 0x2775 }, + { 0x2775, 0x2774 }, + { 0x27d5, 0x27d6 }, + { 0x27d6, 0x27d5 }, + { 0x27dd, 0x27de }, + { 0x27de, 0x27dd }, + { 0x27e2, 0x27e3 }, + { 0x27e3, 0x27e2 }, + { 0x27e4, 0x27e5 }, + { 0x27e5, 0x27e4 }, + { 0x27e6, 0x27e7 }, + { 0x27e7, 0x27e6 }, + { 0x27e8, 0x27e9 }, + { 0x27e9, 0x27e8 }, + { 0x27ea, 0x27eb }, + { 0x27eb, 0x27ea }, + { 0x2983, 0x2984 }, + { 0x2984, 0x2983 }, + { 0x2985, 0x2986 }, + { 0x2986, 0x2985 }, + { 0x2987, 0x2988 }, + { 0x2988, 0x2987 }, + { 0x2989, 0x298a }, + { 0x298a, 0x2989 }, + { 0x298b, 0x298c }, + { 0x298c, 0x298b }, + { 0x298d, 0x2990 }, + { 0x298e, 0x298f }, + { 0x298f, 0x298e }, + { 0x2990, 0x298d }, + { 0x2991, 0x2992 }, + { 0x2992, 0x2991 }, + { 0x2993, 0x2994 }, + { 0x2994, 0x2993 }, + { 0x2995, 0x2996 }, + { 0x2996, 0x2995 }, + { 0x2997, 0x2998 }, + { 0x2998, 0x2997 }, + { 0x29b8, 0x2298 }, + { 0x29c0, 0x29c1 }, + { 0x29c1, 0x29c0 }, + { 0x29c4, 0x29c5 }, + { 0x29c5, 0x29c4 }, + { 0x29cf, 0x29d0 }, + { 0x29d0, 0x29cf }, + { 0x29d1, 0x29d2 }, + { 0x29d2, 0x29d1 }, + { 0x29d4, 0x29d5 }, + { 0x29d5, 0x29d4 }, + { 0x29d8, 0x29d9 }, + { 0x29d9, 0x29d8 }, + { 0x29da, 0x29db }, + { 0x29db, 0x29da }, + { 0x29f5, 0x2215 }, + { 0x29f8, 0x29f9 }, + { 0x29f9, 0x29f8 }, + { 0x29fc, 0x29fd }, + { 0x29fd, 0x29fc }, + { 0x2a2b, 0x2a2c }, + { 0x2a2c, 0x2a2b }, + { 0x2a2d, 0x2a2c }, + { 0x2a2e, 0x2a2d }, + { 0x2a34, 0x2a35 }, + { 0x2a35, 0x2a34 }, + { 0x2a3c, 0x2a3d }, + { 0x2a3d, 0x2a3c }, + { 0x2a64, 0x2a65 }, + { 0x2a65, 0x2a64 }, + { 0x2a79, 0x2a7a }, + { 0x2a7a, 0x2a79 }, + { 0x2a7d, 0x2a7e }, + { 0x2a7e, 0x2a7d }, + { 0x2a7f, 0x2a80 }, + { 0x2a80, 0x2a7f }, + { 0x2a81, 0x2a82 }, + { 0x2a82, 0x2a81 }, + { 0x2a83, 0x2a84 }, + { 0x2a84, 0x2a83 }, + { 0x2a8b, 0x2a8c }, + { 0x2a8c, 0x2a8b }, + { 0x2a91, 0x2a92 }, + { 0x2a92, 0x2a91 }, + { 0x2a93, 0x2a94 }, + { 0x2a94, 0x2a93 }, + { 0x2a95, 0x2a96 }, + { 0x2a96, 0x2a95 }, + { 0x2a97, 0x2a98 }, + { 0x2a98, 0x2a97 }, + { 0x2a99, 0x2a9a }, + { 0x2a9a, 0x2a99 }, + { 0x2a9b, 0x2a9c }, + { 0x2a9c, 0x2a9b }, + { 0x2aa1, 0x2aa2 }, + { 0x2aa2, 0x2aa1 }, + { 0x2aa6, 0x2aa7 }, + { 0x2aa7, 0x2aa6 }, + { 0x2aa8, 0x2aa9 }, + { 0x2aa9, 0x2aa8 }, + { 0x2aaa, 0x2aab }, + { 0x2aab, 0x2aaa }, + { 0x2aac, 0x2aad }, + { 0x2aad, 0x2aac }, + { 0x2aaf, 0x2ab0 }, + { 0x2ab0, 0x2aaf }, + { 0x2ab3, 0x2ab4 }, + { 0x2ab4, 0x2ab3 }, + { 0x2abb, 0x2abc }, + { 0x2abc, 0x2abb }, + { 0x2abd, 0x2abe }, + { 0x2abe, 0x2abd }, + { 0x2abf, 0x2ac0 }, + { 0x2ac0, 0x2abf }, + { 0x2ac1, 0x2ac2 }, + { 0x2ac2, 0x2ac1 }, + { 0x2ac3, 0x2ac4 }, + { 0x2ac4, 0x2ac3 }, + { 0x2ac5, 0x2ac6 }, + { 0x2ac6, 0x2ac5 }, + { 0x2acd, 0x2ace }, + { 0x2ace, 0x2acd }, + { 0x2acf, 0x2ad0 }, + { 0x2ad0, 0x2acf }, + { 0x2ad1, 0x2ad2 }, + { 0x2ad2, 0x2ad1 }, + { 0x2ad3, 0x2ad4 }, + { 0x2ad4, 0x2ad3 }, + { 0x2ad5, 0x2ad6 }, + { 0x2ad6, 0x2ad5 }, + { 0x2ade, 0x22a6 }, + { 0x2ae3, 0x22a9 }, + { 0x2ae4, 0x22a8 }, + { 0x2ae5, 0x22ab }, + { 0x2aec, 0x2aed }, + { 0x2aed, 0x2aec }, + { 0x2af7, 0x2af8 }, + { 0x2af8, 0x2af7 }, + { 0x2af9, 0x2afa }, + { 0x2afa, 0x2af9 }, + { 0x3008, 0x3009 }, + { 0x3009, 0x3008 }, + { 0x300a, 0x300b }, + { 0x300b, 0x300a }, + { 0x300c, 0x300d }, + { 0x300d, 0x300c }, + { 0x300e, 0x300f }, + { 0x300f, 0x300e }, + { 0x3010, 0x3011 }, + { 0x3011, 0x3010 }, + { 0x3014, 0x3015 }, + { 0x3015, 0x3014 }, + { 0x3016, 0x3017 }, + { 0x3017, 0x3016 }, + { 0x3018, 0x3019 }, + { 0x3019, 0x3018 }, + { 0x301a, 0x301b }, + { 0x301b, 0x301a }, + { 0xff08, 0xff09 }, + { 0xff09, 0xff08 }, + { 0xff1c, 0xff1e }, + { 0xff1e, 0xff1c }, + { 0xff3b, 0xff3d }, + { 0xff3d, 0xff3b }, + { 0xff5b, 0xff5d }, + { 0xff5d, 0xff5b }, + { 0xff5f, 0xff60 }, + { 0xff60, 0xff5f }, + { 0xff62, 0xff63 }, + { 0xff63, 0xff62 } +}; + +#endif /* CHARTABLES_H */ diff --git a/3rdparty/clucene/src/CLucene/config/repl_lltot.cpp b/3rdparty/clucene/src/CLucene/config/repl_lltot.cpp new file mode 100644 index 000000000..05a63b887 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/repl_lltot.cpp @@ -0,0 +1,47 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" + +TCHAR* lucene_i64tot( + int64_t value, /* [I] Value to be converted */ + TCHAR* str, /* [O] Destination for the converted value */ + int radix) /* [I] Number base for conversion */ +{ + uint64_t val; + int negative; + TCHAR buffer[65]; + TCHAR* pos; + int digit; + + if (value < 0 && radix == 10) { + negative = 1; + val = -value; + } else { + negative = 0; + val = value; + } /* if */ + + pos = &buffer[64]; + *pos = '\0'; + + do { + digit = val % radix; + val = val / radix; + if (digit < 10) { + *--pos = '0' + digit; + } else { + *--pos = 'a' + digit - 10; + } /* if */ + } while (val != 0L); + + if (negative) { + *--pos = '-'; + } /* if */ + + _tcsncpy(str,pos,&buffer[64] - pos + 1); //needed for unicode to work + return str; +} diff --git a/3rdparty/clucene/src/CLucene/config/repl_tchar.h b/3rdparty/clucene/src/CLucene/config/repl_tchar.h new file mode 100644 index 000000000..ba8aef5c6 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/repl_tchar.h @@ -0,0 +1,126 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _CL_HAVE_TCHAR_H +#if defined(_UCS2) + #define TCHAR wchar_t + + //note: descriptions with * in front have replacement functions + + //formatting functions + #define _sntprintf swprintf //* make a formatted a string + #define _tprintf wprintf //* print a formatted string + + //this one has no replacement functions yet, but it is only used in the tests + #define _vsntprintf vsnwprintf //* print a formatted string using variable arguments + + //we are using the internal functions of the compiler here + //if LUCENE_USE_INTERNAL_CHAR_FUNCTIONS is defined, thesse + //will be replaced by internal functions + #define _istalnum iswalnum //* alpha/numeric char check + #define _istalpha iswalpha //* alpha char check + #define _istspace iswspace //* space char check + #define _istdigit iswdigit //* digit char check + #define _totlower towlower //* convert char to lower case + #define _totupper towupper //* convert char to lower case + #define _tcslwr wcslwr //* convert string to lower case + + //these are the string handling functions + //we may need to create wide-character/multi-byte replacements for these + #define _tcscpy wcscpy //copy a string to another string + #define _tcsncpy wcsncpy //copy a specified amount of one string to another string. + #define _tcscat wcscat //copy a string onto the end of the other string + #define _tcschr wcschr //find location of one character + #define _tcsstr wcsstr //find location of a string + #define _tcslen wcslen //get length of a string + #define _tcscmp wcscmp //case sensitive compare two strings + #define _tcsncmp wcsncmp //case sensitive compare two strings + #define _tcscspn wcscspn //location of any of a set of character in a string + + #ifdef _CL_HAVE_WCSICMP + #define _tcsicmp wcsicmp //* case insensitive compare two string + #else + #define _tcsicmp wcscasecmp //* case insensitive compare two string + #endif + + //conversion functions + #define _tcstod wcstod //convert a string to a double + #ifdef _PA_RISC + #define _tcstoi64 __wcstoll //* convers a string to an 64bit bit integer + #else + #define _tcstoi64 wcstoll //* convers a string to an 64bit bit integer + #endif + #define _i64tot lltow //* converts a 64 bit integer to a string (with base) + +#else //if defined(_ASCII) + #define TCHAR char + + //formatting functions + #define _sntprintf snprintf + #define _tprintf printf + #define _vsntprintf vsnprintf + + //we are using the internal functions of the compiler here + //if LUCENE_USE_INTERNAL_CHAR_FUNCTIONS is defined, thesse + //will be replaced by internal functions + #define _istalnum isalnum + #define _istalpha isalpha + #define _istspace isspace + #define _istdigit isdigit + #define _totlower tolower + #define _totupper toupper + #define _tcslwr strlwr + + //these are the string handling functions + #define _tcscpy strcpy + #define _tcsncpy strncpy + #define _tcscat strcat + #define _tcschr strchr + #define _tcsstr strstr + #define _tcslen strlen + #define _tcscmp strcmp + #define _tcsncmp strncmp + #define _tcsicmp strcasecmp + #define _tcscspn strcspn + + //converstion methods + #define _tcstod strtod + #define _tcstoi64 strtoll + #define _i64tot lltoa +#endif +#else //HAVE_TCHAR_H + #include + +#ifdef UNDER_CE +#include +#define _i64tot i64tot +inline TCHAR* i64tot(__int64 value, TCHAR* str, int radix) +{ + QT_USE_NAMESPACE + _tcscpy(str, (TCHAR *) QString::number(value, radix).utf16()); + return str; +} + +#define _tcstoi64 tcstoi64 +inline __int64 tcstoi64(const TCHAR *nptr, TCHAR **endptr, int base) +{ + QT_USE_NAMESPACE + bool ok; + return QString::fromUtf16((ushort*) nptr).toInt(&ok, base); +} + +#endif + + //some tchar headers miss these... + #ifndef _tcstoi64 + #if defined(_UCS2) + #define _tcstoi64 wcstoll //* convers a string to an 64bit bit integer + #else + #define _tcstoi64 strtoll + #endif + #endif + +#endif //HAVE_TCHAR_H diff --git a/3rdparty/clucene/src/CLucene/config/repl_tcscasecmp.cpp b/3rdparty/clucene/src/CLucene/config/repl_tcscasecmp.cpp new file mode 100644 index 000000000..1bee7b7a6 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/repl_tcscasecmp.cpp @@ -0,0 +1,21 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ + +#include "CLucene/StdHeader.h" + +int lucene_tcscasecmp(const TCHAR * sa, const TCHAR * sb){ + TCHAR ca,cb; + if (sa == sb) + return 0; + + do{ + ca = _totlower( (*(sa++)) ); + cb = _totlower( (*(sb++)) ); + } while ( ca != L'\0' && (ca == cb) ); + + return (int)(ca - cb); +} diff --git a/3rdparty/clucene/src/CLucene/config/repl_tcslwr.cpp b/3rdparty/clucene/src/CLucene/config/repl_tcslwr.cpp new file mode 100644 index 000000000..2ae6abca4 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/repl_tcslwr.cpp @@ -0,0 +1,15 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ + +#include "CLucene/StdHeader.h" + +TCHAR* lucene_tcslwr( TCHAR* str ) +{ + TCHAR* ret = str; + for ( ; *str; str++) *str = _totlower(*str); + return ret; +} diff --git a/3rdparty/clucene/src/CLucene/config/repl_tcstod.cpp b/3rdparty/clucene/src/CLucene/config/repl_tcstod.cpp new file mode 100644 index 000000000..1fd4ca770 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/repl_tcstod.cpp @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ + +#include "CLucene/StdHeader.h" + +#ifndef _ASCII +double lucene_tcstod(const TCHAR *value, TCHAR **end){ + int32_t len = _tcslen(value)+1; + char* avalue=_CL_NEWARRAY(char,len); + char* aend=NULL; + STRCPY_TtoA(avalue,value,len); + + double ret = strtod(avalue,&aend); + *end=(TCHAR*)value+(aend-avalue); + _CLDELETE_CaARRAY(avalue); + + return ret; +} +#endif diff --git a/3rdparty/clucene/src/CLucene/config/repl_tcstoll.cpp b/3rdparty/clucene/src/CLucene/config/repl_tcstoll.cpp new file mode 100644 index 000000000..246d66c80 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/repl_tcstoll.cpp @@ -0,0 +1,46 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ + +#include "CLucene/StdHeader.h" + +int64_t lucene_tcstoi64(const TCHAR* str, TCHAR**end, int radix){ + #define LUCENE_TCSTOI64_RADIX(x,r) ((x>=_T('0') && x<=_T('9'))?x-_T('0'):((x>=_T('a') && x<=_T('z'))?x-_T('a')+10:((x>=_T('A') && x<=_T('Z'))?x-_T('A')+10:1000))) + + if (radix < 2 || radix > 36) + return 0; + + /* Skip white space. */ + while (_istspace (*str)) + ++str; + + int sign=1; + if ( str[0] == _T('+') ) + str++; + else if ( str[0] == _T('-') ){ + sign = -1; + str++; + } + + *end=(TCHAR*)str; + long r = -1; + while ( (r=LUCENE_TCSTOI64_RADIX(*end[0],radix)) >=0 && r=str;p-- ){ + int i=LUCENE_TCSTOI64_RADIX(p[0],radix); + if ( pos == 0 ) + ret=i; + else + ret += (int64_t)pow((qreal)radix,(qreal)pos) * i; //todo: might be quicker with a different pow overload + + pos++; + } + return sign*ret; +} diff --git a/3rdparty/clucene/src/CLucene/config/repl_tprintf.cpp b/3rdparty/clucene/src/CLucene/config/repl_tprintf.cpp new file mode 100644 index 000000000..62cecb78b --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/repl_tprintf.cpp @@ -0,0 +1,149 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "CLucene/util/StringBuffer.h" + +#ifdef __CL_INCLUDE_TPRINTF + +CL_NS_USE(util) + +//print a variable argument to a stream +//currently special number formatting is not supported. it is very minimalistic +void lucene_vfnwprintf(StringBuffer* buffer, size_t count, const wchar_t * format, va_list& valist){ + const wchar_t *iter = format; + StringBuffer* tmp = NULL; + if ( buffer == NULL ) + tmp = _CLNEW StringBuffer; + else + tmp = buffer; + + while (*iter) + { + while (*iter && *iter != '%') + { + tmp->appendChar(*iter++); + } + if (*iter == '%') + { + if (iter[1] == '%') + { + //just print a % + tmp->appendChar('%'); + iter += 2; + continue; + } + + iter++; + switch (*iter) + { + case 's': + { + //todo: this is faulty. it doesn't heed count + + //print a string or null + TCHAR *wstr = va_arg(valist, TCHAR *); + if ( !wstr ) + wstr = _T("(null)"); + + tmp->append(wstr); + iter++; + break; + } + + case 'c': + tmp->appendChar((TCHAR)va_arg(valist, int)); + iter++; + break; + + default: + { + //todo: this is faulty. it doesn't heed count + + if (*iter == 'p') + tmp->appendInt((int32_t)va_arg(valist, long)); + else + { + if (*iter == 'a' || *iter == 'A' || + *iter == 'e' || *iter == 'E' || + *iter == 'f' || *iter == 'F' || + *iter == 'g' || *iter == 'G') + tmp->appendFloat((qreal)va_arg(valist, double),8); + else if (*iter == 'd' || *iter == 'i' ){ + tmp->appendInt((int32_t)va_arg(valist, int)); + }else if (*iter == 'l' ){ + TCHAR b[100]; + _i64tot((int64_t)va_arg(valist, int64_t),b,10); + tmp->append(b); + }/*else{ + TCHAR b[100]; + _i64tot((int64_t)va_arg(valist, void*),b,10); + tmp->append(b); + }*/ + } + iter++; + break; + } + } + } + } + + + if ( buffer == NULL ){ + //we are supposed to be writing to the console +#ifdef _UCS2 + TCHAR* pointer = tmp->getBuffer(); + char ob[MB_LEN_MAX]; + size_t v; + size_t len = tmp->length(); + for (size_t i=0;i 0 ){ + ob[v]='\0'; + fputs(ob,stdout); + } + pointer++; + } + + +#else + fputs(tmp->getBuffer(),stdout); +#endif + _CLDELETE(tmp); + } +} + +//print a list of arguments to a string +int lucene_snwprintf(wchar_t* strbuf, size_t count, const wchar_t * format, ...){ + va_list ap; + va_start(ap, format); + StringBuffer buffer; + lucene_vfnwprintf(&buffer,count,format,ap); + va_end(ap); + + size_t ret = min(count,(size_t)(buffer.length()+1)); + _tcsncpy(strbuf,buffer.getBuffer(),ret); + return ret; +} + +//print a list of arguments to the stdout +void lucene_wprintf(const wchar_t * format, ...){ + va_list ap; + va_start(ap, format); + lucene_vfnwprintf(NULL,LUCENE_INT32_MAX_SHOULDBE,format,ap); + va_end(ap); +} + +//print a variable argument to a string +int lucene_vsnwprintf(wchar_t * strbuf, size_t count, const wchar_t * format, va_list& ap){ + StringBuffer buffer; + lucene_vfnwprintf(&buffer,count,format,ap); + int ret = min((int32_t)count,buffer.length()+1); + _tcsncpy(strbuf,buffer.getBuffer(),ret); + return ret; +} + +#endif //__CL_INCLUDE_TPRINTF diff --git a/3rdparty/clucene/src/CLucene/config/repl_wchar.h b/3rdparty/clucene/src/CLucene/config/repl_wchar.h new file mode 100644 index 000000000..3e05c311c --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/repl_wchar.h @@ -0,0 +1,121 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_repl_wchar_h +#define _lucene_repl_wchar_h + +#ifdef _UCS2 + +#ifndef _CL_HAVE_WCSCPY + //copy a string to another string + #error wcscpy is not defined, and a licensed replacement has not been written yet +#endif + +#ifndef _CL_HAVE_WCSNCPY + //copy a specified amount of one string to another string. + #error wcsncpy is not defined, and a licensed replacement has not been written yet +#endif + +#ifndef _CL_HAVE_WCSCAT + //copy a string onto the end of the other string + #error wcscat is not defined, and a licensed replacement has not been written yet +#endif + +#ifndef _CL_HAVE_WCSCHR + //find location of one character + #error wcschr is not defined, and a licensed replacement has not been written yet +#endif + +#ifndef _CL_HAVE_WCSSTR + //find location of a string + #error wcspy is not defined, and a licensed replacement has not been written yet +#endif + +#ifndef _CL_HAVE_WCSLEN + //get length of a string + #error wcslen is not defined, and a licensed replacement has not been written yet +#endif + +#ifndef _CL_HAVE_WCSCMP + //case sensitive compare two strings + #error wcscmp is not defined, and a licensed replacement has not been written yet +#endif + +#ifndef _CL_HAVE_WCSNCMP + //case sensitive compare two strings of a specified length + #error wcsncmp is not defined, and a licensed replacement has not been written yet +#endif + +#ifndef _CL_HAVE_WCSCSPN + //Return the length of the maximum initial segment + //of WCS which contains only wide-characters not in REJECT. + #error wcscspn is not defined, and a licensed replacement has not been written yet +#endif + +#endif //_UCS2 + +//string function replacements +#if defined(LUCENE_USE_INTERNAL_CHAR_FUNCTIONS) || (defined(_UCS2) && !defined(_CL_HAVE_WCSCASECMP)) || (defined(_ASCII) && !defined(_CL_HAVE_STRCASECMP)) + int lucene_tcscasecmp(const TCHAR *, const TCHAR *); + #undef _tcsicmp + #define _tcsicmp lucene_tcscasecmp +#endif +#if defined(LUCENE_USE_INTERNAL_CHAR_FUNCTIONS) || (defined(_UCS2) && !defined(_CL_HAVE_WCSLWR)) || (defined(_ASCII) && !defined(_CL_HAVE_STRLWR)) + TCHAR* lucene_tcslwr( TCHAR* str ); + #undef _tcslwr + #define _tcslwr lucene_tcslwr +#endif + +//conversion functions +#if (defined(_ASCII) && !defined(_CL_HAVE_LLTOA)) || (defined(_UCS2) && !defined(_CL_HAVE_LLTOW)) + TCHAR* lucene_i64tot( int64_t value, TCHAR* str, int radix); + #undef _i64tot + #define _i64tot lucene_i64tot +#endif +#if (defined(_UCS2) && !defined(_CL_HAVE_WCSTOLL)) || (defined(_ASCII) && !defined(_CL_HAVE_STRTOLL)) + int64_t lucene_tcstoi64(const TCHAR* str, TCHAR**end, int radix); + #undef _tcstoi64 + #define _tcstoi64 lucene_tcstoi64 +#endif +#if defined(_UCS2) && !defined(_CL_HAVE_WCSTOD) + double lucene_tcstod(const TCHAR *value, TCHAR **end); + #undef _tcstod + #define _tcstod lucene_tcstod +#endif + +//printf functions +#if defined(_UCS2) && (!defined(_CL_HAVE_SNWPRINTF) || defined(_CL_HAVE_SWPRINTF_BUG) ) + #undef _sntprintf + #define _sntprintf lucene_snwprintf + int lucene_snwprintf(wchar_t* strbuf, size_t count, const wchar_t * format, ...); + + #ifndef __CL_INCLUDE_TPRINTF + #define __CL_INCLUDE_TPRINTF + #endif +#endif +#if defined(_UCS2) && !defined(_CL_HAVE_WPRINTF) + #undef _tprintf + #define _tprintf lucene_wprintf + void lucene_wprintf(const wchar_t * format, ...); + + #ifndef __CL_INCLUDE_TPRINTF + #define __CL_INCLUDE_TPRINTF + #endif +#endif +#if defined(_UCS2) && (!defined(_CL_HAVE_VSNWPRINTF) || defined(_CL_HAVE_SWPRINTF_BUG) ) + #undef _vsntprintf + #define _vsntprintf lucene_vsnwprintf + int lucene_vsnwprintf(wchar_t * strbuf, size_t count, const wchar_t * format, va_list& ap); + + #ifndef __CL_INCLUDE_TPRINTF + #define __CL_INCLUDE_TPRINTF + #endif +#endif + +//todo: if _CL_HAVE_SNPRINTF_BUG fails(snprintf overflow),we should use our own +//function. but we don't have it currently, and our functions are dubious anyway... + +#endif //end of _lucene_repl_wchar_h diff --git a/3rdparty/clucene/src/CLucene/config/threadCSection.h b/3rdparty/clucene/src/CLucene/config/threadCSection.h new file mode 100644 index 000000000..ab1842051 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/threadCSection.h @@ -0,0 +1,71 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +//NOTE: do not include this file directly, it is included from lucene internally. + +#ifndef lucene_config_threadCSection_h +#define lucene_config_threadCSection_h +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +CL_NS_DEF(util) + + #if !defined(LUCENE_USE_WINDOWS_H) && !defined(_WINDOWS_) && !defined(__MINGW32__) + //we have not explicity included windows.h and windows.h has + //not been included (check _WINDOWS_), then we must define + //our own definitions to the thread locking functions: + struct CRITICAL_SECTION + { + struct critical_section_debug * DebugInfo; + long LockCount; + long RecursionCount; + void * OwningThread; + void * LockSemaphore; + #if defined(_WIN64) + unsigned __int64 SpinCount; + #else + unsigned long SpinCount; + #endif + }; + #endif + + ///a windows implementation of the lock mutex + ///todo: boost has a InterlockedExchange way of locking too. More backwards compatible/faster??? + class mutex_win32 + { + private: + CRITICAL_SECTION mtx; + public: + mutex_win32(const mutex_win32& clone); + mutex_win32(); + ~mutex_win32(); + void lock(); + void unlock(); + }; + + class CLuceneThreadIdCompare + { + public: + + enum + { // parameters for hash table + bucket_size = 4, // 0 < bucket_size + min_buckets = 8 + }; // min_buckets = 2 ^^ N, 0 < N + + bool operator()( DWORD t1, DWORD t2 ) const{ + return t1 < t2; + } + }; + + #define _LUCENE_SLEEP(x) Sleep(x) + #define _LUCENE_THREADMUTEX CL_NS(util)::mutex_win32 + #define _LUCENE_CURRTHREADID GetCurrentThreadId() + #define _LUCENE_THREADID_TYPE DWORD +CL_NS_END + +#endif //lucene_config_threadCSection_h diff --git a/3rdparty/clucene/src/CLucene/config/threadPthread.h b/3rdparty/clucene/src/CLucene/config/threadPthread.h new file mode 100644 index 000000000..d0ed9c4c9 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/threadPthread.h @@ -0,0 +1,59 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +//NOTE: do not include this file directly, it is included from lucene internally. + +#ifndef lucene_config_threadPthread_h +#define lucene_config_threadPthread_h + +#include + +CL_NS_DEF(util) + +///a posix implementation of the lock mutex +///todo: we need a spinlock implemenation for usage in reference counting +class mutex_pthread +{ +private: + pthread_mutex_t mtx; + +public: + mutex_pthread(const mutex_pthread& clone); + mutex_pthread(); + ~mutex_pthread(); + void lock(); + void unlock(); + +private: + #ifndef _CL_HAVE_PTHREAD_MUTEX_RECURSIVE + pthread_t lockOwner; + unsigned int lockCount; + #endif +}; + +#define _LUCENE_SLEEP(x) usleep(x*1000) //_LUCENE_SLEEP should be in millis, usleep is in micros +#define _LUCENE_THREADMUTEX CL_NS(util)::mutex_pthread +#define _LUCENE_CURRTHREADID pthread_self() +#define _LUCENE_THREADID_TYPE pthread_t + +class CLuceneThreadIdCompare +{ +public: + enum + { // parameters for hash table + bucket_size = 4, // 0 < bucket_size + min_buckets = 8 + }; // min_buckets = 2 ^^ N, 0 < N + + bool operator()( pthread_t t1, pthread_t t2 ) const{ + return t1 < t2; + } +}; + + +CL_NS_END + +#endif //lucene_config_threadPthread_h diff --git a/3rdparty/clucene/src/CLucene/config/threads.cpp b/3rdparty/clucene/src/CLucene/config/threads.cpp new file mode 100644 index 000000000..427e58092 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/threads.cpp @@ -0,0 +1,162 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" + +#ifndef _CL_DISABLE_MULTITHREADING +CL_NS_DEF(util) + + +mutexGuard::mutexGuard(const mutexGuard& clone){ + //no autoclone + mrMutex = NULL; +} +mutexGuard::mutexGuard( _LUCENE_THREADMUTEX& rMutex ) : + mrMutex(&rMutex) +{ + mrMutex->lock(); +} +mutexGuard::~mutexGuard() +{ + mrMutex->unlock(); +} + +#if defined(_LUCENE_DONTIMPLEMENT_THREADMUTEX) + //do nothing + #if defined(_LUCENE_PRAGMA_WARNINGS) + #pragma message ("==================Not implementing any thread mutex==================") + #else + #warning "==================Not implementing any thread mutex==================" + #endif + + + +#elif defined(_CL_HAVE_WIN32_THREADS) + #include "CLucene/config/threadCSection.h" + + #if !defined(LUCENE_USE_WINDOWS_H) && !defined(_WINDOWS_) + //we have not explicity included windows.h and windows.h has + //not been included (check _WINDOWS_), then we must define + //our own definitions to the thread locking functions: + extern "C" __declspec(dllimport) void __stdcall InitializeCriticalSection(CRITICAL_SECTION *); + extern "C" __declspec(dllimport) void __stdcall EnterCriticalSection(CRITICAL_SECTION *); + extern "C" __declspec(dllimport) void __stdcall LeaveCriticalSection(CRITICAL_SECTION *); + extern "C" __declspec(dllimport) void __stdcall DeleteCriticalSection(CRITICAL_SECTION *); + extern "C" __declspec(dllimport) unsigned long __stdcall GetCurrentThreadId(); + #endif + + mutex_win32::mutex_win32(const mutex_win32& clone){ + InitializeCriticalSection(&mtx); + } + mutex_win32::mutex_win32() + { + InitializeCriticalSection(&mtx); + } + + mutex_win32::~mutex_win32() + { + DeleteCriticalSection(&mtx); + } + + void mutex_win32::lock() + { + EnterCriticalSection(&mtx); + } + + void mutex_win32::unlock() + { + LeaveCriticalSection(&mtx); + } + + + +#elif defined(_CL_HAVE_PTHREAD) + #include "CLucene/config/threadPthread.h" + + #ifdef _CL_HAVE_PTHREAD_MUTEX_RECURSIVE + bool mutex_pthread_attr_initd=false; + pthread_mutexattr_t mutex_pthread_attr; + #endif + + #ifdef _CL__CND_DEBUG + #define _CLPTHREAD_CHECK(c,m) CND_PRECONDITION(c==0,m) + #else + #define _CLPTHREAD_CHECK(c,m) c; + #endif + + mutex_pthread::mutex_pthread(const mutex_pthread& clone){ + #ifdef _CL_HAVE_PTHREAD_MUTEX_RECURSIVE + _CLPTHREAD_CHECK(pthread_mutex_init(&mtx, &mutex_pthread_attr), "mutex_pthread(clone) constructor failed") + #else + #if defined(__hpux) && defined(_DECTHREADS_) + _CLPTHREAD_CHECK(pthread_mutex_init(&mtx, pthread_mutexattr_default), "mutex_pthread(clone) constructor failed") + #else + _CLPTHREAD_CHECK(pthread_mutex_init(&mtx, 0), "mutex_pthread(clone) constructor failed") + #endif + lockCount=0; + lockOwner=0; + #endif + } + mutex_pthread::mutex_pthread() + { + #ifdef _CL_HAVE_PTHREAD_MUTEX_RECURSIVE + if ( mutex_pthread_attr_initd == false ){ + pthread_mutexattr_init(&mutex_pthread_attr); + pthread_mutexattr_settype(&mutex_pthread_attr, PTHREAD_MUTEX_RECURSIVE); + mutex_pthread_attr_initd = true; + } + _CLPTHREAD_CHECK(pthread_mutex_init(&mtx, &mutex_pthread_attr), "mutex_pthread(clone) constructor failed") + #else + #if defined(__hpux) && defined(_DECTHREADS_) + _CLPTHREAD_CHECK(pthread_mutex_init(&mtx, pthread_mutexattr_default), "mutex_pthread(clone) constructor failed") + #else + _CLPTHREAD_CHECK(pthread_mutex_init(&mtx, 0), "mutex_pthread(clone) constructor failed") + #endif + lockCount=0; + lockOwner=0; + #endif + } + + mutex_pthread::~mutex_pthread() + { + _CLPTHREAD_CHECK(pthread_mutex_destroy(&mtx), "~mutex_pthread destructor failed") + } + + void mutex_pthread::lock() + { + #ifndef _CL_HAVE_PTHREAD_MUTEX_RECURSIVE + pthread_t currentThread = pthread_self(); + if( pthread_equal( lockOwner, currentThread ) ) { + ++lockCount; + } else { + _CLPTHREAD_CHECK(pthread_mutex_lock(&mtx), "mutex_pthread::lock") + lockOwner = currentThread; + lockCount = 1; + } + #else + _CLPTHREAD_CHECK(pthread_mutex_lock(&mtx), "mutex_pthread::lock") + #endif + } + + void mutex_pthread::unlock() + { + #ifndef _CL_HAVE_PTHREAD_MUTEX_RECURSIVE + --lockCount; + if( lockCount == 0 ) + { + lockOwner = 0; + _CLPTHREAD_CHECK(pthread_mutex_unlock(&mtx), "mutex_pthread::unlock") + } + #else + _CLPTHREAD_CHECK(pthread_mutex_unlock(&mtx), "mutex_pthread::unlock") + #endif + } + +#endif //thread impl choice + + +CL_NS_END +#endif //!_CL_DISABLE_MULTITHREADING diff --git a/3rdparty/clucene/src/CLucene/config/utf8.cpp b/3rdparty/clucene/src/CLucene/config/utf8.cpp new file mode 100644 index 000000000..14ccf5aa9 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/config/utf8.cpp @@ -0,0 +1,237 @@ +/* + * Copyright (C) 1999 Tom Tromey + * Copyright (C) 2000 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * + ************************************************ + * Also licensed with permission from Tom Tromey + * and Owen Taylor under the Apache license. + * Original location: + * http://cvs.gnome.org/viewcvs/glib/glib/gutf8.c?rev=1.50&view=log + ************************************************ + * + * Copyright 2003-2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include "CLucene/StdHeader.h" + +typedef unsigned long gunichar; +typedef unsigned char guchar; + +#define UTF8_COMPUTE(Char, Mask, Len) \ + if (Char < 128) \ + { \ + Len = 1; \ + Mask = 0x7f; \ + } \ + else if ((Char & 0xe0) == 0xc0) \ + { \ + Len = 2; \ + Mask = 0x1f; \ + } \ + else if ((Char & 0xf0) == 0xe0) \ + { \ + Len = 3; \ + Mask = 0x0f; \ + } \ + else if ((Char & 0xf8) == 0xf0) \ + { \ + Len = 4; \ + Mask = 0x07; \ + } \ + else if ((Char & 0xfc) == 0xf8) \ + { \ + Len = 5; \ + Mask = 0x03; \ + } \ + else if ((Char & 0xfe) == 0xfc) \ + { \ + Len = 6; \ + Mask = 0x01; \ + } \ + else \ + Len = -1; + +/*#define UTF8_LENGTH(Char) \ + ((Char) < 0x80 ? 1 : \ + ((Char) < 0x800 ? 2 : \ + ((Char) < 0x10000 ? 3 : \ + ((Char) < 0x200000 ? 4 : \ + ((Char) < 0x4000000 ? 5 : 6)))))*/ + + +#define UTF8_GET(Result, Chars, Count, Mask, Len) \ + (Result) = (Chars)[0] & (Mask); \ + for ((Count) = 1; (Count) < (Len); ++(Count)) \ + { \ + if (((Chars)[(Count)] & 0xc0) != 0x80) \ + { \ + (Result) = -1; \ + break; \ + } \ + (Result) <<= 6; \ + (Result) |= ((Chars)[(Count)] & 0x3f); \ + } + + +/** + * lucene_wctoutf8: + * @c: a ISO10646 character code + * @outbuf: output buffer, must have at least 6 bytes of space. + * If %NULL, the length will be computed and returned + * and nothing will be written to @outbuf. + * + * Converts a single character to UTF-8. + * + * Return value: number of bytes written + **/ +size_t lucene_wctoutf8(char * outbuf, const wchar_t ch) +{ + gunichar c = ch; + guchar len = 0; + int first; + int i; + + if (c < 0x80) + { + first = 0; + len = 1; + } + else if (c < 0x800) + { + first = 0xc0; + len = 2; + } + else if (c < 0x10000) + { + first = 0xe0; + len = 3; + } + else if (c < 0x200000) + { + first = 0xf0; + len = 4; + } + else if (c < 0x4000000) + { + first = 0xf8; + len = 5; + } + else + { + first = 0xfc; + len = 6; + } + + if (outbuf) + { + for (i = len - 1; i > 0; --i) + { + outbuf[i] = (char)((c & 0x3f) | 0x80); + c >>= 6; + } + outbuf[0] = c | first; + } + + return len; +} + + +/** + * lucene_utf8towc: + * @p: a pointer to Unicode character encoded as UTF-8 + * + * Converts a sequence of bytes encoded as UTF-8 to a Unicode character. + * If @p does not point to a valid UTF-8 encoded character, results are + * undefined. If you are not sure that the bytes are complete + * valid Unicode characters, you should use lucene_utf8towc_validated() + * instead. + * + * Return value: the resulting character + **/ +size_t lucene_utf8towc(wchar_t *pwc, const char *p, size_t n) +{ + int i, mask = 0; + int result; + unsigned char c = (unsigned char) *p; + int len=0; + + UTF8_COMPUTE (c, mask, len); + if (len == -1) + return 0; + UTF8_GET (result, p, i, mask, len); + + *pwc = result; + return len; +} + + +//this function was not taken from gnome +size_t lucene_wcstoutf8(char * result, const wchar_t * str, size_t result_length){ + char *p=result; + int i = 0; + + while (p < result + result_length-1 && str[i] != 0) + p += lucene_wctoutf8(p,str[i++]); + + *p = '\0'; + + return p-result; +} +//this function was not taken from gnome +size_t lucene_utf8towcs(wchar_t * result, const char * str, size_t result_length){ + char *sp = (char*)str; + wchar_t *rp = result; + int i = 0; + + while (rp < result + result_length && *sp!=0){ + size_t r = lucene_utf8towc(rp,sp,6); + if ( r == -1 ) + return 0; + sp += r; + rp++; + } + + if ( sp-str < result_length ) + *rp = '\0'; + + size_t ret = sp-str; + return ret; +} +//get the number of bytes that make up the utf8 character. +//this function was not taken from gnome +size_t lucene_utf8charlen(const char *p) +{ + int mask = 0; + int len=0; + unsigned char c = (unsigned char) *p; + + UTF8_COMPUTE (c, mask, len); + return len; +} diff --git a/3rdparty/clucene/src/CLucene/debug/condition.cpp b/3rdparty/clucene/src/CLucene/debug/condition.cpp new file mode 100644 index 000000000..855419451 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/debug/condition.cpp @@ -0,0 +1,80 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "condition.h" +#include "CLucene/util/Misc.h" +#ifdef _CL__CND_DEBUG + +#define __CND_STR_PRECONDITION "PRECONDITION" +#define __CND_STR_CONDITION "CONDITION" +#define __CND_STR_WARNING "WARNING" +#define __CND_STR_MESSAGE "MESSAGE" +#define __CND_STR_DEBUGMESSAGE "DEBUG MESSAGE" +#define __CND_STR_EXIT "EXIT" + +#ifndef _CND_DEBUG_DONTIMPLEMENT_OUTDEBUG +void _Cnd_OutDebug( const char* FormattedMsg, const char* StrTitle, const char* File, int32_t Line, int32_t Title, const char* Mes2, int32_t fatal ){ + #ifdef __WINDOWS_H + /*Display a standard messagebox*/ + MessageBox(NULL, FormattedMsg, StrTitle, (fatal==1 ? MB_ICONSTOP:MB_ICONEXCLAMATION) | MB_OK | MB_TASKMODAL); + #else + printf("%s\n",FormattedMsg); + #endif + + #if defined(_CND_DEBUG_WARN_DEBUGGER) /*attempt to signal windows debugger*/ + OutputDebugString(FormattedMsg); + DebugBreak(); /*Position debugger just before exit program*/ + #endif + + if ( fatal ) + debugFatalExit(1); +} +#endif + +void __cnd_FormatDebug( const char* File, int32_t Line, int32_t Title, const char* Mes2, int32_t fatal ) { + char M[512]; + char* StrTitle = NULL; + + if( Mes2 ) + _snprintf(M,512,"file:%s line:%d\n%s",File,Line,Mes2); + else + _snprintf(M,512,"file:%s line:%d",File,Line); + + /*Determine which title to use*/ + switch( Title ) { + case CND_STR_PRECONDITION: { + StrTitle = __CND_STR_PRECONDITION; + break; + } + case CND_STR_CONDITION: { + StrTitle = __CND_STR_CONDITION; + break; + } + case CND_STR_WARNING: { + StrTitle = __CND_STR_WARNING; + break; + } + case CND_STR_MESSAGE: { + StrTitle = __CND_STR_MESSAGE; + break; + } + case CND_STR_DEBUGMESSAGE: { + StrTitle = __CND_STR_DEBUGMESSAGE; + break; + } + case CND_STR_EXIT: { + StrTitle = __CND_STR_EXIT; + break; + } + default: + break; + }/*switch*/ + + _Cnd_OutDebug(M, StrTitle, File, Line, Title, Mes2, fatal); +} +#endif + diff --git a/3rdparty/clucene/src/CLucene/debug/condition.h b/3rdparty/clucene/src/CLucene/debug/condition.h new file mode 100644 index 000000000..ab227e508 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/debug/condition.h @@ -0,0 +1,64 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef __CONDITION_H +#define __CONDITION_H + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +/* +To enable condition debugging uncomment _CND_DEBUG in CLConfig.h +*/ + +#ifdef _CL__CND_DEBUG /* Don't include the debug code */ + #ifndef CND_STR_DEFINES + #define CND_STR_DEFINES + #define CND_STR_PRECONDITION 1 + #define CND_STR_CONDITION 2 + #define CND_STR_WARNING 3 + #define CND_STR_MESSAGE 4 + #define CND_STR_DEBUGMESSAGE 5 + #define CND_STR_EXIT 6 + #endif + + /* _CL__CND_DEBUG defined, include debug code */ + + #ifdef _CND_NODEBUGTEXT + #define CND_PRECONDITION(cond,usermessage) CND__EXITCONDITION(cond,__FILE__,__LINE__,CND_STR_PRECONDITION,NULL) + #define CND_CONDITION(cond,usermessage) CND__EXITCONDITION(cond,__FILE__,__LINE__,CND_STR_CONDITION,NULL) + #define CND_WARNING(cond,usermessage) CND__CONDITION(cond,__FILE__,__LINE__,CND_STR_WARNING,NULL) + #define CND_MESSAGE(cond,usermessage) CND__CONDITION(cond,__FILE__,__LINE__,CND_STR_MESSAGE,NULL) + #define CND_DEBUGMESSAGE(usermessage) CND__MESSAGE(__FILE__,__LINE__,CND_STR_DEBUGMESSAGE,NULL) + #else + #define CND_PRECONDITION(cond,usermessage) CND__EXITCONDITION(cond,__FILE__,__LINE__,CND_STR_PRECONDITION,usermessage) + #define CND_CONDITION(cond,usermessage) CND__EXITCONDITION(cond,__FILE__,__LINE__,CND_STR_CONDITION,usermessage) + #define CND_WARNING(cond,usermessage) CND__CONDITION(cond,__FILE__,__LINE__,CND_STR_WARNING,usermessage) + #define CND_MESSAGE(cond,usermessage) CND__CONDITION(cond,__FILE__,__LINE__,CND_STR_MESSAGE,usermessage) + #define CND_DEBUGMESSAGE(usermessage) CND__MESSAGE(__FILE__,__LINE__,CND_STR_DEBUGMESSAGE,usermessage) + #endif + + //if _CND_DEBUG_DONTIMPLEMENT_OUTDEBUG is defined, then you must implement + //this routine in the client application. The debug callback can then + //be better customised to the host application. + //Here is the default implementation: + void _Cnd_OutDebug( const char* FormattedMsg, const char* StrTitle, const char* File, int32_t Line, int32_t Title, const char* Mes2, int32_t fatal ); + + void __cnd_FormatDebug( const char* File, int32_t Line, int32_t Title, const char* Mes2, int32_t fatal ); + #define CND__EXIT(file,line,title,mes2) {__cnd_FormatDebug(file,line,title,mes2,1);} + #define CND__EXITCONDITION(cond,file,line,title,mes2) {if(!(cond)){__cnd_FormatDebug(file,line,title,mes2,1);}} + #define CND__CONDITION(cond,file,line,title,mes2) {if(!(cond)){__cnd_FormatDebug(file,line,title,mes2,0);}} + #define CND__MESSAGE(file,line,title,mes2) {__cnd_FormatDebug(file,line,title,mes2,0);} +#else + #define CND_PRECONDITION(cond, usermessage) + #define CND_CONDITION(cond, usermessage) + #define CND_WARNING(cond,usermessage) + #define CND_MESSAGE(cond,usermessage) + #define CND_DEBUGMESSAGE(usermessage) +#endif + +#endif diff --git a/3rdparty/clucene/src/CLucene/debug/error.cpp b/3rdparty/clucene/src/CLucene/debug/error.cpp new file mode 100644 index 000000000..53ea0e93b --- /dev/null +++ b/3rdparty/clucene/src/CLucene/debug/error.cpp @@ -0,0 +1,73 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" + +CL_NS_USE(util) + + +#ifdef _LUCENE_DISABLE_EXCEPTIONS + #ifdef _LUCENE_PRAGMA_WARNINGS + #pragma message ("==================Lucene exceptions are disabled==================") + #else + #warning "==================Lucene exceptions are disabled==================" + #endif +#else + CLuceneError::CLuceneError(int num, const char* str, bool ownstr) + { + error_number = num; + _awhat=STRDUP_AtoA(str); + _twhat=NULL; + if ( ownstr ) + _CLDELETE_CaARRAY(str); + } + + CLuceneError::CLuceneError(const CLuceneError& clone) + { + this->error_number = clone.error_number; + this->_awhat = NULL; + this->_twhat = NULL; + + if ( clone._awhat != NULL ) + this->_awhat = STRDUP_AtoA(clone._awhat); + if ( clone._twhat != NULL ) + this->_twhat = STRDUP_TtoT(clone._twhat); + } + CLuceneError::~CLuceneError() throw(){ + _CLDELETE_CARRAY(_twhat); + _CLDELETE_CaARRAY(_awhat); + } + char* CLuceneError::what(){ +#ifdef _ASCII + if ( _twhat != NULL ) + return _twhat; +#endif + if ( _awhat == NULL ) + _awhat = STRDUP_TtoA(_twhat); + return _awhat; + } + TCHAR* CLuceneError::twhat(){ +#ifdef _ASCII + if ( _awhat != NULL ) + return _awhat; +#endif + if ( _twhat == NULL ) + _twhat = STRDUP_AtoT(_awhat); + return _twhat; + } + +#ifndef _ASCII + CLuceneError::CLuceneError(int num, const TCHAR* str, bool ownstr) + { + error_number = 0; + _awhat=NULL; + _twhat=STRDUP_TtoT(str); + if ( ownstr ) + _CLDELETE_CARRAY(str); + } +#endif + +#endif //_LUCENE_DISABLE_EXCEPTIONS diff --git a/3rdparty/clucene/src/CLucene/debug/error.h b/3rdparty/clucene/src/CLucene/debug/error.h new file mode 100644 index 000000000..5abcc802c --- /dev/null +++ b/3rdparty/clucene/src/CLucene/debug/error.h @@ -0,0 +1,74 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_debug_error_ +#define _lucene_debug_error_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#define CL_ERR_UNKNOWN -1 +#define CL_ERR_IO 1 +#define CL_ERR_NullPointer 2 +#define CL_ERR_Runtime 3 +#define CL_ERR_IllegalArgument 4 +#define CL_ERR_Parse 5 +#define CL_ERR_TokenMgr 6 +#define CL_ERR_UnsupportedOperation 7 +#define CL_ERR_InvalidState 8 +#define CL_ERR_IndexOutOfBounds 9 +#define CL_ERR_TooManyClauses 10 +#define CL_ERR_RAMTransaction 11 +#define CL_ERR_InvalidCast 12 +#define CL_ERR_IllegalState 13 + + + +//////////////////////////////////////////////////////// +//error try/throw/catch definitions +//////////////////////////////////////////////////////// +#ifdef _CL_DISABLE_NATIVE_EXCEPTIONS + /*#define try _jpr_Try + #define _CLCATCH _jpr_Catch + #define _CLFINALLY(x) xxxx + #define _CLTHROWA(y) _jpr_Throw + #define _THROWA_DEL(y) _jpr_Throw + #define _RETHROW(x) _jpr_Throw + #define _CLTHROWT(y) _jpr_Throw + + #define _THROWS ,_jpr_Throws*/ +#else + class CLuceneError + { + int error_number; + char* _awhat; + TCHAR* _twhat; + public: + CLuceneError(const CLuceneError& clone); + CLuceneError(int num, const char* str, bool ownstr); +#ifdef _UCS2 + CLuceneError(int num, const TCHAR* str, bool ownstr); +#endif + int number(){return error_number;} + char* what(); + TCHAR* twhat(); + ~CLuceneError() throw(); + }; + + //#define _THROWS //does nothing + #define _CLFINALLY(x) catch(...){ x; throw; } x //note: code x is not run if return is called + #define _CLTHROWA(number, str) throw CLuceneError(number, str,false) + #define _CLTHROWT(number, str) throw CLuceneError(number, str,false) + #define _CLTHROWA_DEL(number, str) throw CLuceneError(number, str,true) //throw a string ensures the value is deleted + #define _CLTHROWT_DEL(number, str) throw CLuceneError(number, str,true) //throw a string ensures the value is deleted + + +#endif //_LUCENE_DISABLE_EXCEPTIONS +// +//////////////////////////////////////////////////////// + +#endif diff --git a/3rdparty/clucene/src/CLucene/debug/lucenebase.h b/3rdparty/clucene/src/CLucene/debug/lucenebase.h new file mode 100644 index 000000000..86cdae1c5 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/debug/lucenebase.h @@ -0,0 +1,75 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_debug_lucenebase_ +#define _lucene_debug_lucenebase_ + +#ifdef _LUCENE_PRAGMA_ONCE +# pragma once +#endif + +CL_NS_DEF(debug) + +//Lucenebase is the superclass of all clucene objects. It provides +//memory debugging tracking and/or reference counting +class LuceneBase{ +public: +#ifdef LUCENE_ENABLE_MEMLEAKTRACKING + static void* operator new (size_t size); + static void operator delete (void *p); + int32_t __cl_initnum; ///< The order that the object was created at. This is then used to do a lookup in the objects list + + static void* operator new (size_t size, char const * file, int32_t line); + static void operator delete (void *p, char const * file, int32_t line); + + static void* __cl_voidpadd(void* data, const char* file, int line, size_t size); ///dummy__see_mem_h_for_details +#endif +#define _CL_POINTER(x) (x==NULL?NULL:(x->__cl_addref()>=0?x:x)) //return a add-ref'd object +#define LUCENE_REFBASE public CL_NS(debug)::LuceneBase //this is the base of classes who *always* need refcounting + +#if defined(_DEBUG) + #if !defined(LUCENE_BASE_CHECK) + #define LUCENE_BASE_CHECK(x) + #endif +#else + #undef LUCENE_BASE_CHECK + #define LUCENE_BASE_CHECK(x) +#endif + +//Macro for creating new arrays +#ifdef LUCENE_ENABLE_MEMLEAKTRACKING + #define _CL_NEWARRAY(type,size) (type*)CL_NS(debug)::LuceneBase::__cl_voidpadd(new type[(size_t)size],__FILE__,__LINE__,(size_t)size); + #define _CLDELETE_ARRAY(x) if (x!=NULL){CL_NS(debug)::LuceneBase::__cl_voidpremove((const void*)x,__FILE__,__LINE__); delete [] x; x=NULL;} + #define _CLDELETE_LARRAY(x) if (x!=NULL){CL_NS(debug)::LuceneBase::__cl_voidpremove((const void*)x,__FILE__,__LINE__);delete [] x;} + #ifndef _CLDELETE_CARRAY + #define _CLDELETE_CARRAY(x) if (x!=NULL){CL_NS(debug)::LuceneBase::__cl_voidpremove((const void*)x,__FILE__,__LINE__);delete [] x; x=NULL;} + #define _CLDELETE_LCARRAY(x) if (x!=NULL){CL_NS(debug)::LuceneBase::__cl_voidpremove((const void*)x,__FILE__,__LINE__);delete [] x;} + #endif +#else + #define _CL_NEWARRAY(type,size) new type[size] + #define _CLDELETE_ARRAY(x) if (x!=NULL){delete [] x; x=NULL;} + #define _CLDELETE_LARRAY(x) if (x!=NULL){delete [] x;} + #ifndef _CLDELETE_CARRAY + #define _CLDELETE_CARRAY(x) if (x!=NULL){delete [] x; x=NULL;} + #define _CLDELETE_LCARRAY(x) if (x!=NULL){delete [] x;} + #endif +#endif +//a shortcut for deleting a carray and all its contents +#define _CLDELETE_CARRAY_ALL(x) {if ( x!=NULL ){ for(int xcda=0;x[xcda]!=NULL;xcda++)_CLDELETE_CARRAY(x[xcda]);}_CLDELETE_ARRAY(x)}; +#define _CLDELETE_ARRAY_ALL(x) {if ( x!=NULL ){ for(int xcda=0;x[xcda]!=NULL;xcda++)_CLDELETE(x[xcda]);}_CLDELETE_ARRAY(x)}; +#ifndef _CLDELETE_CaARRAY + #define _CLDELETE_CaARRAY _CLDELETE_CARRAY + #define _CLDELETE_LCaARRAY _CLDELETE_LCARRAY +#endif + +//Macro for deleting +#ifdef LUCENE_ENABLE_REFCOUNT + #define _CLDELETE(x) if (x!=NULL){ CND_PRECONDITION((x)->__cl_refcount>=0,"__cl_refcount was < 0"); if ((x)->__cl_decref() <= 0)delete x; x=NULL; } + #define _CLLDELETE(x) if (x!=NULL){ CND_PRECONDITION((x)->__cl_refcount>=0,"__cl_refcount was < 0"); if ((x)->__cl_decref() <= 0)delete x; } +#else + #define _CLDELETE(x) if (x!=NULL){ LUCENE_BASE_CHECK(x); delete x; x=NULL; } + #define _CLLDELETE(x) if (x!=NULL){ LUCENE_BASE_CHECK(x); delete x; } +#endif + +//_CLDECDELETE deletes objects which are *always* refcounted +#define _CLDECDELETE(x) if (x!=NULL){ CND_PRECONDITION((x)->__cl_refcount>=0,"__cl_refcount was < 0"); if ((x)->__cl_decref() <= 0)delete x; x=NULL; } +#define _CLLDECDELETE(x) if (x!=NULL){ CND_PRECONDITION((x)->__cl_refcount>=0,"__cl_refcount was < 0"); if ((x)->__cl_decref() <= 0)delete x; } + +//_VDelete should be used for deleting non-clucene objects. +//when using reference counting, _CLDELETE casts the object +//into a LuceneBase*. +#define _CLVDELETE(x) if(x!=NULL){delete x; x=NULL;} + +template +class Array: LUCENE_BASE{ +public: + T* values; + size_t length; + + void deleteAll(){ + for (size_t i=0;ivalues = values; + this->length = length; + } + Array(size_t length){ + this->values = _CL_NEWARRAY(T,length); + this->length = length; + } + ~Array(){} + + const T operator[](size_t _Pos) const + { + if (length <= _Pos){ + _CLTHROWA(CL_ERR_IllegalArgument,"vector subscript out of range"); + } + return (*(values + _Pos)); + } + T operator[](size_t _Pos) + { + if (length <= _Pos){ + _CLTHROWA(CL_ERR_IllegalArgument,"vector subscript out of range"); + } + return (*(values + _Pos)); + } + +}; + +#endif //_lucene_debug_lucenebase_ diff --git a/3rdparty/clucene/src/CLucene/debug/memtracking.cpp b/3rdparty/clucene/src/CLucene/debug/memtracking.cpp new file mode 100644 index 000000000..544a125a5 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/debug/memtracking.cpp @@ -0,0 +1,371 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "CLucene/util/Misc.h" + +bool _lucene_disable_debuglogging = true; //if LUCENE_ENABLE_CONSTRUCTOR_LOG is on, dont do log if this is true +bool _lucene_run_objectcheck = false; //run a memory check before deleting objects +int _lucene_counter_break = -1; //to break at this item, change this + //and put break points at points below + +CL_NS_USE(util) +CL_NS_DEF(debug) + +#ifdef LUCENE_ENABLE_MEMLEAKTRACKING +int32_t _instance_counter = 0; //counter for initnumber + +struct _file{ + int32_t refcount; ///times this has been used + char* value; ///reference to the the basefile +}; //structure for name counting +struct _pointers{ + _file* file; + int32_t initline; + int32_t initnumber; +};//structure for pointer-filename references + +typedef CL_NS(util)::CLSet > defFile; +typedef CL_NS(util)::CLSet,Deletor::Dummy,Deletor::Void<_pointers> > defPointer; +typedef CL_NS(util)::CLSet,Deletor::Dummy,Deletor::Void<_pointers> > defVoid; + +DEFINE_MUTEX(memleak_lock) +defFile LuceneBase_Files(false,true); //list of filenames used +defPointer LuceneBase_Pointers(false,true); //list of pointers counted +defVoid LuceneBase_Voids(false,true); //list of arbitary data added + +//variables to trim filenames to just the base names +char _files_trim_string[CL_MAX_DIR]; +int32_t _files_trim_start=-1; + +//trim the filename and return the refcounted _file* structure +_file* get_file(const char* file){ + if ( _files_trim_start == -1 ){ + //this trims the start of the name file name so + //that the whole of the filename is not stored - more asthetic :) + //need to find the base + _files_trim_start = strlen(__FILE__) - 21; //(length of debug/memtracking.cpp) + strcpy(_files_trim_string,__FILE__); + _files_trim_string[_files_trim_start] = 0; + } + if ( strncmp(file,_files_trim_string,_files_trim_start) == 0 ){ + //this file should be within the same directory area as we found lucenebase.cpp + //to be, lets trim the start + file+=_files_trim_start; + } + + //now return an existing files structure (with refcount++) or create a new one + defFile::iterator itr = LuceneBase_Files.find((const char*)file); + if ( itr != LuceneBase_Files.end() ){ + _file* bf = itr->second; + bf->refcount++; + return bf; + }else{ + _file* ref = new _file; + ref->value = new char[strlen(file)+1]; //cannot use _CL_NEWARRAY otherwise recursion + strcpy(ref->value,file); + + ref->refcount = 1; + LuceneBase_Files.insert(pair(ref->value,ref)); + return ref; + } +} + +void remove_file(_file* bf){ + bf->refcount--; + if ( bf->refcount <= 0 ){ + defFile::iterator fi = LuceneBase_Files.find(bf->value); + CND_PRECONDITION(fi!=LuceneBase_Files.end(),"fi==NULL"); + delete[] bf->value; + LuceneBase_Files.removeitr(fi); + } +} + +#ifdef LUCENE_ENABLE_CONSTRUCTOR_LOG + void constructor_log(const char* type,const char* file,const int line, const int size){ + if ( _lucene_disable_debuglogging ){ + FILE* f = fopen("clucene.log","a"); + char buf[CL_MAX_DIR+5]; + sprintf(buf,"%s,%s,%d,%d\n",type,file,line,size); + fwrite(buf,sizeof(char),strlen(buf),f); + fclose(f); + } + } + #define CONSTRUCTOR_LOG(type,file,line,size) constructor_log(type,file,line,size) +#else + #define CONSTRUCTOR_LOG(type,file,line,size) +#endif + +//////////////////////////////////////////////////////////////////////////////// +// the _CLNEW&_CLDELETE new/delete operators +//////////////////////////////////////////////////////////////////////////////// +void* LuceneBase::operator new (size_t size, const char * file, int32_t line) +{ + SCOPED_LOCK_MUTEX(memleak_lock) + + void* p = malloc (size); + LuceneBase* lb = (LuceneBase*)p; + + //create the pointer struct + _file* br = get_file(file); + _pointers* bp = new _pointers; + bp->file = br; + bp->initnumber = _instance_counter++; + bp->initline = line; + + //associate this object with the pointer + lb->__cl_initnum = bp->initnumber; + + //break if necessary + if ( _lucene_counter_break == lb->__cl_initnum ) + CLDebugBreak(); //put break point here + + //add the pointer object + LuceneBase_Pointers.insert(pair(lb, bp)); + + CONSTRUCTOR_LOG("newobj",file,line,size); + return p; +} +void LuceneBase::operator delete (void *p, char const * file, int32_t line) +{ + SCOPED_LOCK_MUTEX(memleak_lock) + + LuceneBase* lb=(LuceneBase*)p; + + defPointer::iterator itr = LuceneBase_Pointers.find(lb); + if ( itr != LuceneBase_Pointers.end() ){ + _pointers* bp = itr->second; + remove_file(bp->file); + + LuceneBase_Pointers.removeitr(itr); + }else{ + //break + } + free(p); +} + +/////////////////////////////////////////////////////////////////////////// +// the generic new/delete operators +/////////////////////////////////////////////////////////////////////////// +void* LuceneBase::operator new (size_t size) +{ + SCOPED_LOCK_MUTEX(memleak_lock) + + void* p = malloc (size); + LuceneBase* lb = (LuceneBase*)p; + + //create the pointer struct + _file* br = get_file("undefined"); + _pointers* bp = new _pointers; + bp->file = br; + bp->initnumber = _instance_counter++; + bp->initline = -1; + + //associate this object with the pointer + lb->__cl_initnum = bp->initnumber; + + //break if necessary + if ( _lucene_counter_break == lb->__cl_initnum ) + CLDebugBreak(); + + //add the pointer object + LuceneBase_Pointers.insert(pair(lb,bp)); + + CONSTRUCTOR_LOG("newobj","unknown",-1,size); + return p; +} +void LuceneBase::operator delete (void *p) +{ + SCOPED_LOCK_MUTEX(memleak_lock) + + LuceneBase* lb=(LuceneBase*)p; + + defPointer::iterator itr = LuceneBase_Pointers.find(lb); + if ( itr != LuceneBase_Pointers.end() ){ + _pointers* bp = itr->second; + remove_file(bp->file); + LuceneBase_Pointers.removeitr(itr); + }else{ + CLDebugBreak(); + } + free(p); +} + +/////////////////////////////////////////////////////////////////////////// +// other memtracking functions +/////////////////////////////////////////////////////////////////////////// +void LuceneBase::__cl_unregister(const void* obj){ + SCOPED_LOCK_MUTEX(memleak_lock) + + LuceneBase* lb=(LuceneBase*)obj; + defPointer::iterator itr = LuceneBase_Pointers.find(lb); + CND_PRECONDITION(itr != LuceneBase_Pointers.end(),"__cl_unregister object not found"); + _pointers* bp = itr->second; + LuceneBase_Pointers.removeitr(itr); +} + +void* LuceneBase::__cl_voidpadd(void* data, const char* file, int line,size_t size){ + SCOPED_LOCK_MUTEX(memleak_lock) + + _file* br = get_file(file); + _pointers* bp = new _pointers; + bp->file = br; + bp->initnumber = _instance_counter++; + bp->initline = line; + + LuceneBase_Voids.insert(pair(data,bp)); + CONSTRUCTOR_LOG("newarr",file,line,size); + return data; +} +void LuceneBase::__cl_voidpremove(const void* data, const char* file, int line){ + SCOPED_LOCK_MUTEX(memleak_lock) + defVoid::iterator itr = LuceneBase_Voids.find(data); + if ( itr != LuceneBase_Voids.end() ){ + _pointers* bp = itr->second; + remove_file(bp->file); + LuceneBase_Voids.removeitr(itr); + }else{ + printf("Data deleted when not added with _CL_NEWARRAY in %s at %d\n",file,line); + } +} + + +//////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////// +//The lucene base memory leak printout functions +//////////////////////////////////////////////////////////// +//static +void __internalcl_PrintUnclosedObject(bool isObject, string& sb,_pointers* bp,_file* bf, bool print){ + TCHAR ttmp[100]; + char atmp[100]; + + sb.append(" "); + { + _i64tot(bp->initnumber,ttmp,10); + STRCPY_TtoA(atmp,ttmp,100); + sb.append(atmp); + } + if ( isObject ){ + sb.append("(obj). "); + }else{ + sb.append(". "); + } + sb.append(bf->value); + sb.append(", line "); + { + _i64tot(bp->initline,ttmp,10); + STRCPY_TtoA(atmp,ttmp,100); + sb.append(atmp); + } + sb.append("\n"); + + if ( print && sb.length() > 0 ){ + printf("%s\n", sb.c_str()); + sb = ""; + } +} +char* __internalcl_GetUnclosedObjects(bool print){ + TCHAR ttmp[100]; + char atmp[100]; + SCOPED_LOCK_MUTEX(memleak_lock) + + string sb; + bool unknowns = false; + if ( LuceneBase_Pointers.size() > 0 ){ + { + _i64tot(LuceneBase_Pointers.size(),ttmp,10); + STRCPY_TtoA(atmp,ttmp,100); + sb.append(atmp); + } + sb.append(" clucene objects are still open\n"); + + defPointer::iterator itr = LuceneBase_Pointers.begin(); + while ( itr != LuceneBase_Pointers.end() ){ + _pointers* bp = itr->second; + _file* bf = bp->file; + + if ( bp->initline == -1 ) + unknowns = true; + __internalcl_PrintUnclosedObject(true, sb,bp,bf,print); + + ++itr; + } + + defVoid::iterator itr2 = LuceneBase_Voids.begin(); + while ( itr2 != LuceneBase_Voids.end() ){ + _pointers* bp = itr2->second; + _file* bf = bp->file; + + if ( bp->initline == -1 ) + unknowns = true; + __internalcl_PrintUnclosedObject(false, sb,bp,bf,print); + + itr2++; + } + } + + if ( unknowns == true ){ + sb.append("*** Some memory was not created with _CLNEW and was not tracked... ***\n"); + sb.append("*** Use _CLNEW instead of new when creating CLucene objects ***\n"); + sb.append("*** Memory may also have not been freed in the current context ***\n"); + } + + if ( print ){ + if ( sb.length() > 0 ){ + printf("%s\n", sb.c_str()); + sb = ""; + } + return NULL; + }else{ + if ( sb.length() > 0 ) + return STRDUP_AtoA(sb.c_str()); + else + return NULL; + } +} + +void LuceneBase::__cl_ClearMemory(){ + SCOPED_LOCK_MUTEX(memleak_lock) + + while ( LuceneBase_Files.size() > 0 ){ + defFile::iterator fi = LuceneBase_Files.begin(); + _file* f = fi->second; + delete[] f->value; + LuceneBase_Files.removeitr (fi); + } + LuceneBase_Pointers.clear(); + LuceneBase_Voids.clear(); +} +char* LuceneBase::__cl_GetUnclosedObjects(){ + return __internalcl_GetUnclosedObjects(false); +} +//static +int32_t LuceneBase::__cl_GetUnclosedObjectsCount(){ + return LuceneBase_Pointers.size(); +} + +const char* LuceneBase::__cl_GetUnclosedObject(int32_t item){ + SCOPED_LOCK_MUTEX(memleak_lock) + + defPointer::iterator itr=LuceneBase_Pointers.begin(); + int32_t i=0; + for ( ;itr!=LuceneBase_Pointers.end() && isecond->file->value; + else + return NULL; +} +void LuceneBase::__cl_PrintUnclosedObjects(){ + __internalcl_GetUnclosedObjects(true); +} +//////////////////////////////////////////////////////////// + +#endif //LUCENE_ENABLE_MEMLEAKTRACKING +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/document/DateField.cpp b/3rdparty/clucene/src/CLucene/document/DateField.cpp new file mode 100644 index 000000000..ff72b12bb --- /dev/null +++ b/3rdparty/clucene/src/CLucene/document/DateField.cpp @@ -0,0 +1,60 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" + +#include "DateField.h" +#include "CLucene/util/Misc.h" +CL_NS_USE(util) +CL_NS_DEF(document) + +DateField::~DateField(){ +} + +TCHAR* DateField::timeToString(const int64_t time) { + TCHAR* buf = _CL_NEWARRAY(TCHAR,DATEFIELD_DATE_LEN + 1); + timeToString(time,buf); + return buf; +} +void DateField::timeToString(const int64_t time, TCHAR* buf) { + CND_PRECONDITION (buf, "buf == NULL"); + *buf = '\0'; + if (time < 0) + _CLTHROWA (CL_ERR_IllegalArgument,"time too early"); //todo: make richer error + + if (time > DATEFIELD_DATE_MAX) + _CLTHROWA (CL_ERR_IllegalArgument, "time too late (past DATEFIELD_DATE_MAX"); //todo: make richer error + + _i64tot(time, buf, 36); + int32_t bufLen = _tcslen(buf); + + CND_PRECONDITION (bufLen <= DATEFIELD_DATE_LEN, "timeToString length is greater than 9"); + + /* Supply leading zeroes if necessary. */ + if (bufLen < DATEFIELD_DATE_LEN) { + const int32_t nMissingZeroes = DATEFIELD_DATE_LEN - bufLen; + /* Move buffer contents forward to make room for leading zeroes. */ + for (int32_t i = DATEFIELD_DATE_LEN - 1; i >= nMissingZeroes; i--) + buf[i] = buf[i - nMissingZeroes]; + + /* Insert leading zeroes. */ + {// MSVC6 scoping fix + for (int32_t i = 0; i < nMissingZeroes; i++) + buf[i] = '0'; + } + + buf[DATEFIELD_DATE_LEN] = 0; + } + + CND_PRECONDITION (_tcslen(buf) == DATEFIELD_DATE_LEN, "timeToString return is not equal to DATEFIELD_DATE_LEN"); +} + +int64_t DateField::stringToTime(const TCHAR* time) { + TCHAR* end; + return _tcstoi64(time, &end, 36); +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/document/DateField.h b/3rdparty/clucene/src/CLucene/document/DateField.h new file mode 100644 index 000000000..712fe9b62 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/document/DateField.h @@ -0,0 +1,64 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_document_DateField_ +#define _lucene_document_DateField_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +CL_NS_DEF(document) + +//here are some constants used throughout clucene +//make date strings long enough to last a millenium +#define DATEFIELD_DATE_MAX _ILONGLONG(31536000000000) //1000L*365*24*60*60*1000 + +#define DATEFIELD_DATE_LEN 9 ////Long.toString(DATEFIELD_DATE_MAX, Character.MAX_RADIX).length() + +/** +* Provides support for converting dates to strings and vice-versa. +* The strings are structured so that lexicographic sorting orders by date, +* which makes them suitable for use as field values and search terms. +* +*

Note that this class saves dates with millisecond granularity, +* which is bad for {@link RangeQuery} and {@link PrefixQuery}, as those +* queries are expanded to a BooleanQuery with a potentially large number +* of terms when searching. Thus you might want to use +* {@link DateTools} instead. +* +*

+* Note: dates before 1970 cannot be used, and therefore cannot be +* indexed when using this class. See {@link DateTools} for an +* alternative without such a limitation. +* +* @deprecated If you build a new index, use {@link DateTools} instead. This class is included for use with existing +* indices and will be removed in a future release. +*/ +class DateField :LUCENE_BASE { +public: + ~DateField(); + + /** + * Converts a millisecond time to a string suitable for indexing. + * @throws RuntimeException if the time specified in the + * method argument is negative, that is, before 1970 + */ + static TCHAR* timeToString(const int64_t time); + + /** + * Converts a millisecond time to a string suitable for indexing. + * @throws CL_ERR_IllegalArgument if the time specified in the + * method argument is negative, that is, before 1970 + * @param str must be a character array DATEFIELD_DATE_LEN+1 or longer + */ + static void timeToString(const int64_t time, TCHAR* str); + + /** Converts a string-encoded date into a millisecond time. */ + static int64_t stringToTime(const TCHAR* s); +}; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/document/Document.cpp b/3rdparty/clucene/src/CLucene/document/Document.cpp new file mode 100644 index 000000000..a0ce03942 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/document/Document.cpp @@ -0,0 +1,237 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "Document.h" +#include "Field.h" +#include "CLucene/util/StringBuffer.h" + +CL_NS_USE(util) +CL_NS_DEF(document) + + DocumentFieldEnumeration::DocumentFieldList::DocumentFieldList(Field* f, DocumentFieldList* n ) { + //Func - Constructor + //Pre - f != NULL + // n may be NULL + //Post - Instance has been created + CND_PRECONDITION(f != NULL, "f is NULL"); + + field = f; + next = n; + } + DocumentFieldEnumeration::DocumentFieldList::~DocumentFieldList(){ + //Func - Destructor + //Pre - true + //Post - Instance has been destroyed + + // Instead of recursively deleting the field list we do + // it iteratively to avoid stack overflows when + // dealing with several thousands of fields. + + if (!field) { + return; // nothing to do; deleted by different invocation of dtor + } + + DocumentFieldList* cur = next; + while (cur != NULL) + { + DocumentFieldList* temp = cur->next; + cur->next = NULL; + + _CLDELETE(cur); + cur = temp; + } + _CLDELETE(field); + } + + + DocumentFieldEnumeration::DocumentFieldEnumeration(const DocumentFieldList* fl){ + //Func - Constructor + //Pre - fl may be NULL + //Post - Instance has been created + + fields = fl; + } + + DocumentFieldEnumeration::~DocumentFieldEnumeration(){ + //Func - Destructor + //Pre - true + //Post - Instance has been destroyed + } + + bool DocumentFieldEnumeration::hasMoreElements() const { + return fields == NULL ? false : true; + } + + Field* DocumentFieldEnumeration::nextElement() { + //Func - Return the next element in the enumeration + //Pre - true + //Post - The next element is returned or NULL + + + Field* result = NULL; + //Check if fields is still valid + if (fields){ + result = fields->field; + fields = fields->next; + } + return result; + } + + /** Constructs a new document with no fields. */ + Document::Document(){ + //Func - Constructor + //Pre - true + //Post - Instance has been created + boost = 1.0f; + fieldList = NULL; + } + + Document::~Document(){ + //Func - Destructor + //Pre - true + //Post - Instance has been destroyed + boost = 1.0f; + _CLDELETE(fieldList); + } + + void Document::clear(){ + _CLDELETE(fieldList); + } + + void Document::add(Field& field) { + fieldList = _CLNEW DocumentFieldEnumeration::DocumentFieldList(&field, fieldList); + } + + void Document::setBoost(qreal boost) { + this->boost = boost; + } + + qreal Document::getBoost() const { + return boost; + } + + + Field* Document::getField(const TCHAR* name) const{ + CND_PRECONDITION(name != NULL, "name is NULL"); + + for (DocumentFieldEnumeration::DocumentFieldList* list = fieldList; list != NULL; list = list->next) + //cannot use interning here, because name is probably not interned + if ( _tcscmp(list->field->name(), name) == 0 ){ + return list->field; + } + + return NULL; + } + + const TCHAR* Document::get(const TCHAR* field) const { + CND_PRECONDITION(field != NULL, "field is NULL"); + Field *f = getField(field); + if (f!=NULL) + return f->stringValue(); //this returns null it is a binary(reader) + else + return NULL; + } + + DocumentFieldEnumeration* Document::fields() const { + return _CLNEW DocumentFieldEnumeration(fieldList); + } + + + TCHAR* Document::toString() const { + StringBuffer ret(_T("Document<")); + for (DocumentFieldEnumeration::DocumentFieldList* list = fieldList; list != NULL; list = list->next) { + TCHAR* tmp = list->field->toString(); + ret.append( tmp ); + if (list->next != NULL) + ret.append(_T(" ")); + _CLDELETE_ARRAY( tmp ); + } + ret.append(_T(">")); + return ret.toString(); + } + + + + void Document::removeField(const TCHAR* name) { + CND_PRECONDITION(name != NULL, "name is NULL"); + + DocumentFieldEnumeration::DocumentFieldList* previous = NULL; + DocumentFieldEnumeration::DocumentFieldList* current = fieldList; + while (current != NULL) { + //cannot use interning here, because name is probably not interned + if ( _tcscmp(current->field->name(),name) == 0 ){ + if (previous){ + previous->next = current->next; + }else + fieldList = current->next; + current->next=NULL; //ensure fieldlist destructor doesnt delete it + _CLDELETE(current); + return; + } + previous = current; + current = current->next; + } + } + + void Document::removeFields(const TCHAR* name) { + CND_PRECONDITION(name != NULL, "name is NULL"); + + DocumentFieldEnumeration::DocumentFieldList* previous = NULL; + DocumentFieldEnumeration::DocumentFieldList* current = fieldList; + while (current != NULL) { + //cannot use interning here, because name is probably not interned + if ( _tcscmp(current->field->name(),name) == 0 ){ + if (previous){ + previous->next = current->next; + }else + fieldList = current->next; + + current->next=NULL; //ensure fieldlist destructor doesnt delete it + _CLDELETE(current); + + if ( previous ) + current = previous->next; + else + current = fieldList; + }else{ + previous = current; + current = current->next; + } + } + } + + TCHAR** Document::getValues(const TCHAR* name) { + DocumentFieldEnumeration* it = fields(); + int32_t count = 0; + while ( it->hasMoreElements() ){ + Field* f = it->nextElement(); + //cannot use interning here, because name is probably not interned + if ( _tcscmp(f->name(),name) == 0 && f->stringValue() != NULL ) + count++; + } + _CLDELETE(it); + it = fields(); + + //todo: there must be a better way of doing this, we are doing two iterations of the fields + TCHAR** ret = NULL; + if ( count > 0 ){ + //start again + ret = _CL_NEWARRAY(TCHAR*,count+1); + int32_t i=0; + while ( it->hasMoreElements() ){ + Field* fld=it->nextElement(); + if ( _tcscmp(fld->name(),name)== 0 && fld->stringValue() != NULL ){ + ret[i] = stringDuplicate(fld->stringValue()); + i++; + } + } + ret[count]=NULL; + } + _CLDELETE(it); + return ret; + } +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/document/Document.h b/3rdparty/clucene/src/CLucene/document/Document.h new file mode 100644 index 000000000..ba7a283f7 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/document/Document.h @@ -0,0 +1,158 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_document_Document_ +#define _lucene_document_Document_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "Field.h" + +///todo: jlucene has change from using DocumentFieldList/Enumeration +///to using a java List... do we want to do this too? +CL_NS_DEF(document) + +class Document; //predefine +class DocumentFieldEnumeration :LUCENE_BASE{ + class DocumentFieldList :LUCENE_BASE{ + public: + DocumentFieldList(Field* f, DocumentFieldList* n); + ~DocumentFieldList(); + Field* field; + DocumentFieldList* next; + }; + friend class Document; +private: + const DocumentFieldList* fields; +public: + DocumentFieldEnumeration(const DocumentFieldList* fl); + ~DocumentFieldEnumeration(); + bool hasMoreElements() const; + Field* nextElement(); +}; + +/** Documents are the unit of indexing and search. +* +* A Document is a set of fields. Each field has a name and a textual value. +* A field may be {@link Field#isStored() stored} with the document, in which +* case it is returned with search hits on the document. Thus each document +* should typically contain one or more stored fields which uniquely identify +* it. +* +*

Note that fields which are not {@link Field#isStored() stored} are +* not available in documents retrieved from the index, e.g. with {@link +* Hits#doc(int32_t, Document*)}, {@link Searcher#doc(int32_t, Document*)} or {@link +* IndexReader#document(int32_t, Document*)}. +*/ +class Document:LUCENE_BASE { +private: + DocumentFieldEnumeration::DocumentFieldList* fieldList; + qreal boost; +public: + Document(); + ~Document(); + + /** + *

Adds a field to a document. Several fields may be added with + * the same name. In this case, if the fields are indexed, their text is + * treated as though appended for the purposes of search.

+ *

Note that add like the removeField(s) methods only makes sense + * prior to adding a document to an index. These methods cannot + * be used to change the content of an existing index! In order to achieve this, + * a document has to be deleted from an index and a new changed version of that + * document has to be added.

+ * + */ + void add(Field& field); + /** Returns a field with the given name if any exist in this document, or + * null. If multiple fields exists with this name, this method returns the + * first value added. + * Note: name is case sensitive + */ + Field* getField(const TCHAR* name) const; + + /** Returns the string value of the field with the given name if any exist in + * this document, or null. If multiple fields exist with this name, this + * method returns the first value added. If only binary fields with this name + * exist, returns null. + * Note: name is case sensitive + */ + const TCHAR* get(const TCHAR* field) const; + + /** Returns an Enumeration of all the fields in a document. */ + DocumentFieldEnumeration* fields() const; + /** Prints the fields of a document for human consumption. */ + TCHAR* toString() const; + + /** Sets a boost factor for hits on any field of this document. This value + * will be multiplied into the score of all hits on this document. + * + *

Values are multiplied into the value of {@link Field#getBoost()} of + * each field in this document. Thus, this method in effect sets a default + * boost for the fields of this document. + * + * @see Field#setBoost(qreal) + */ + void setBoost(qreal boost); + + /** Returns the boost factor for hits on any field of this document. + * + *

The default value is 1.0. + * + *

Note: This value is not stored directly with the document in the index. + * Documents returned from {@link IndexReader#document(int32_t, Document*)} and + * {@link Hits#doc(int32_t, Document*)} may thus not have the same value present as when + * this document was indexed. + * + * @see #setBoost(qreal) + */ + qreal getBoost() const; + + + /** + *

Removes field with the specified name from the document. + * If multiple fields exist with this name, this method removes the first field that has been added. + * If there is no field with the specified name, the document remains unchanged.

+ *

Note that the removeField(s) methods like the add method only make sense + * prior to adding a document to an index. These methods cannot + * be used to change the content of an existing index! In order to achieve this, + * a document has to be deleted from an index and a new changed version of that + * document has to be added.

+ * Note: name is case sensitive + */ + void removeField(const TCHAR* name); + + /** + *

Removes all fields with the given name from the document. + * If there is no field with the specified name, the document remains unchanged.

+ *

Note that the removeField(s) methods like the add method only make sense + * prior to adding a document to an index. These methods cannot + * be used to change the content of an existing index! In order to achieve this, + * a document has to be deleted from an index and a new changed version of that + * document has to be added.

+ * Note: name is case sensitive + */ + void removeFields(const TCHAR* name); + + /** + * Returns an array of values of the field specified as the method parameter. + * This method can return null. + * Note: name is case sensitive + * + * @param name the name of the field + * @return a String[] of field values + */ + TCHAR** getValues(const TCHAR* name); + + /** + * Empties out the document so that it can be reused + */ + void clear(); +}; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/document/Field.cpp b/3rdparty/clucene/src/CLucene/document/Field.cpp new file mode 100644 index 000000000..8cd88a36b --- /dev/null +++ b/3rdparty/clucene/src/CLucene/document/Field.cpp @@ -0,0 +1,315 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "CLucene/util/Reader.h" +#include "Field.h" +#include "CLucene/util/Misc.h" +#include "CLucene/util/StringIntern.h" +#include "CLucene/util/StringBuffer.h" + +CL_NS_USE(util) +CL_NS_DEF(document) + +Field::Field(const TCHAR* Name, const TCHAR* String, bool store, bool index, bool token, const bool storeTermVector) +{ +//Func - Constructor +//Pre - Name != NULL and contains the name of the field +// String != NULL and contains the value of the field +// store indicates if the field must be stored +// index indicates if the field must be indexed +// token indicates if the field must be tokenized +//Post - The instance has been created + + CND_PRECONDITION(Name != NULL, "Name is NULL"); + CND_PRECONDITION(String != NULL,"String is NULL"); + CND_PRECONDITION(!(!index && storeTermVector),"cannot store a term vector for fields that are not indexed."); + + _name = CLStringIntern::intern( Name CL_FILELINE); + _stringValue = stringDuplicate( String ); + _readerValue = NULL; + _streamValue = NULL; + boost=1.0f; + omitNorms = false; + + int cfg = 0; + if ( store ) + cfg |= STORE_YES; + if ( index && token ) + cfg |= INDEX_TOKENIZED; + else if ( index && !token ) + cfg |= INDEX_UNTOKENIZED; + + if ( storeTermVector ) + _CLTHROWA(CL_ERR_IllegalArgument,"Stored term vector is deprecated with using this constructor"); + + setConfig(cfg); +} + +Field::Field(const TCHAR* Name, Reader* reader, bool store, bool index, bool token, const bool storeTermVector) +{ +//Func - Constructor +//Pre - Name != NULL and contains the name of the field +// reader != NULL and contains a Reader +// store indicates if the field must be stored +// index indicates if the field must be indexed +// token indicates if the field must be tokenized +//Post - The instance has been created + + CND_PRECONDITION(Name != NULL, "Name is NULL"); + CND_PRECONDITION(reader != NULL, "reader is NULL"); + + _name = CLStringIntern::intern( Name CL_FILELINE); + _stringValue = NULL; + _readerValue = reader; + _streamValue = NULL; + boost=1.0f; + omitNorms = false; + + int cfg = 0; + if ( store ) + cfg |= STORE_YES; + if ( index && token ) + cfg |= INDEX_TOKENIZED; + else if ( index && !token ) + cfg |= INDEX_UNTOKENIZED; + + if ( storeTermVector ) + _CLTHROWA(CL_ERR_IllegalArgument,"Stored term vector is deprecated with using this constructor"); + + setConfig(cfg); +} + +Field::Field(const TCHAR* Name, Reader* reader, int config) +{ + CND_PRECONDITION(Name != NULL, "Name is NULL"); + CND_PRECONDITION(reader != NULL, "reader is NULL"); + + _name = CLStringIntern::intern( Name CL_FILELINE); + _stringValue = NULL; + _readerValue = reader; + _streamValue = NULL; + boost=1.0f; + omitNorms = false; + + setConfig(config); +} + + +Field::Field(const TCHAR* Name, const TCHAR* Value, int config) +{ + CND_PRECONDITION(Name != NULL, "Name is NULL"); + CND_PRECONDITION(Value != NULL, "value is NULL"); + + _name = CLStringIntern::intern( Name CL_FILELINE); + _stringValue = stringDuplicate( Value ); + _readerValue = NULL; + _streamValue = NULL; + boost=1.0f; + omitNorms = false; + + setConfig(config); +} + +Field::Field(const TCHAR* Name, jstreams::StreamBase* Value, int config) +{ + CND_PRECONDITION(Name != NULL, "Name is NULL"); + CND_PRECONDITION(Value != NULL, "value is NULL"); + + _name = CLStringIntern::intern( Name CL_FILELINE); + _stringValue = NULL; + _readerValue = NULL; + _streamValue = Value; + boost=1.0f; + omitNorms = false; + + setConfig(config); +} + +Field::~Field(){ +//Func - Destructor +//Pre - true +//Post - Instance has been destroyed + + CLStringIntern::unintern(_name); + _CLDELETE_CARRAY(_stringValue); + _CLDELETE(_readerValue); + _CLVDELETE( _streamValue ); +} + + +/*===============FIELDS=======================*/ +const TCHAR* Field::name() { return _name; } ///* Field::streamValue() { return _streamValue; } ///omitNorms=omitNorms; } + +void Field::setBoost(qreal boost) { this->boost = boost; } +qreal Field::getBoost() { return boost; } + +void Field::setConfig(int x){ + int newConfig=0; + + //set storage settings + if ( (x & STORE_YES) || (x & STORE_COMPRESS) ){ + newConfig |= STORE_YES; + if ( x & STORE_COMPRESS ) + newConfig |= STORE_COMPRESS; + }else + newConfig |= STORE_NO; + + if ( (x & INDEX_NO)==0 ){ + bool index=false; + + if ( x & INDEX_NONORMS ){ + newConfig |= INDEX_NONORMS; + index = true; + } + + if ( x & INDEX_TOKENIZED && x & INDEX_UNTOKENIZED ) + _CLTHROWA(CL_ERR_IllegalArgument,"it doesn't make sense to have an untokenised and tokenised field"); + if ( x & INDEX_TOKENIZED ){ + newConfig |= INDEX_TOKENIZED; + index = true; + } + if ( x & INDEX_UNTOKENIZED ){ + newConfig |= INDEX_UNTOKENIZED; + index = true; + } + if ( !index ) + newConfig |= INDEX_NO; + }else + newConfig |= INDEX_NO; + + if ( newConfig & INDEX_NO && newConfig & STORE_NO ) + _CLTHROWA(CL_ERR_IllegalArgument,"it doesn't make sense to have a field that is neither indexed nor stored"); + + //set termvector settings + if ( (x & TERMVECTOR_NO) == 0 ){ + bool termVector=false; + if ( x & TERMVECTOR_YES ){ + termVector=true; + } + if ( x & TERMVECTOR_WITH_OFFSETS ){ + newConfig |= TERMVECTOR_WITH_OFFSETS; + termVector=true; + } + if ( x & TERMVECTOR_WITH_POSITIONS ){ + newConfig |= TERMVECTOR_WITH_POSITIONS; + termVector=true; + } + if ( termVector ){ + if ( newConfig & INDEX_NO ) + _CLTHROWA(CL_ERR_IllegalArgument,"cannot store a term vector for fields that are not indexed."); + + newConfig |= TERMVECTOR_YES; + }else + newConfig |= TERMVECTOR_NO; + }else + newConfig |= TERMVECTOR_NO; + + config = newConfig; +} + +TCHAR* Field::toString() { + CL_NS(util)::StringBuffer result; + if (isStored()) { + result.append( _T("stored") ); + } + if (isIndexed()) { + if (result.length() > 0) + result.append( _T(",") ); + result.append( _T("indexed") ); + } + if (isTokenized()) { + if (result.length() > 0) + result.append( _T(",") ); + result.append( _T("tokenized") ); + } + if (isTermVectorStored()) { + if (result.length() > 0) + result.append( _T(",") ); + result.append( _T("termVector") ); + } + if (isStoreOffsetWithTermVector()) { + if (result.length() > 0) + result.appendChar( ',' ); + result.append( _T("termVectorOffsets") ); + } + if (isStorePositionWithTermVector()) { + if (result.length() > 0) + result.appendChar( ',' ); + result.append( _T("termVectorPosition") ); + } + if (isBinary()) { + if (result.length() > 0) + result.appendChar( ',' ); + result.append( _T("binary") ); + } + if (getOmitNorms()) { + result.append( _T(",omitNorms") ); + } + result.appendChar('<'); + result.append(name()); + result.appendChar(':'); + + if (_stringValue != NULL) + result.append(_stringValue); + else if ( _readerValue != NULL ) + result.append( _T("Reader") ); + else if ( _streamValue != NULL ) + result.append( _T("Stream") ); + else + result.append( _T("NULL") ); + + result.appendChar('>'); + return result.toString(); +} + + +Field* Field::Keyword(const TCHAR* Name, const TCHAR* Value) { + return _CLNEW Field(Name,Value,Field::STORE_YES | Field::INDEX_UNTOKENIZED); +} + +Field* Field::UnIndexed(const TCHAR* Name, const TCHAR* Value) { + return _CLNEW Field(Name,Value,Field::STORE_YES | Field::INDEX_NO); +} + +Field* Field::Text(const TCHAR* Name, const TCHAR* Value, const bool storeTermVector) { + if ( storeTermVector ) + return _CLNEW Field(Name,Value,Field::STORE_YES | Field::INDEX_TOKENIZED | Field::TERMVECTOR_YES); + else + return _CLNEW Field(Name,Value,Field::STORE_YES | Field::INDEX_TOKENIZED); +} + +Field* Field::UnStored(const TCHAR* Name, const TCHAR* Value, const bool storeTermVector) { + if ( storeTermVector ) + return _CLNEW Field(Name,Value,Field::STORE_NO | Field::INDEX_TOKENIZED | Field::TERMVECTOR_YES); + else + return _CLNEW Field(Name,Value,Field::STORE_NO | Field::INDEX_TOKENIZED); +} + +Field* Field::Text(const TCHAR* Name, Reader* Value, const bool storeTermVector) { + if ( storeTermVector ) + return _CLNEW Field(Name,Value,Field::INDEX_TOKENIZED | Field::TERMVECTOR_YES); + else + return _CLNEW Field(Name,Value,Field::INDEX_TOKENIZED); +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/document/Field.h b/3rdparty/clucene/src/CLucene/document/Field.h new file mode 100644 index 000000000..771a1382b --- /dev/null +++ b/3rdparty/clucene/src/CLucene/document/Field.h @@ -0,0 +1,261 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_document_Field_ +#define _lucene_document_Field_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/util/Reader.h" +#include "CLucene/util/streambase.h" + +CL_NS_DEF(document) +/** +A field is a section of a Document. Each field has two parts, a name and a +value. Values may be free text, provided as a String or as a Reader, or they +may be atomic keywords, which are not further processed. Such keywords may +be used to represent dates, urls, etc. Fields are optionally stored in the +index, so that they may be returned with hits on the document. + +PORTING: CLucene doesn't directly support compressed fields. However, it is easy +to reproduce this functionality by using the GZip streams in the contrib package. +Also note that binary fields are not read immediately in CLucene, a substream +is pointed directly to the field's data, in affect creating a lazy load ability. +This means that large fields are best saved in binary format (even if they are +text), so that they can be loaded lazily. +*/ +class Field :LUCENE_BASE{ +private: + const TCHAR* _name; + TCHAR* _stringValue; + CL_NS(util)::Reader* _readerValue; + jstreams::StreamBase* _streamValue; + + int config; + qreal boost; + bool omitNorms; +public: + enum Store{ + /** Store the original field value in the index. This is useful for short texts + * like a document's title which should be displayed with the results. The + * value is stored in its original form, i.e. no analyzer is used before it is + * stored. + */ + STORE_YES=1, + /** Do not store the field value in the index. */ + STORE_NO=2, + + /** Store the original field value in the index in a compressed form. This is + * useful for long documents and for binary valued fields. + * NOTE: CLucene does not directly support compressed fields, to store a + * compressed field. + * //TODO: need better documentation on how to add a compressed field + * //because actually we still need to write a GZipOutputStream... + */ + STORE_COMPRESS=4 + }; + + enum Index{ + /** Do not index the field value. This field can thus not be searched, + * but one can still access its contents provided it is + * {@link Field::Store stored}. */ + INDEX_NO=16, + /** Index the field's value so it can be searched. An Analyzer will be used + * to tokenize and possibly further normalize the text before its + * terms will be stored in the index. This is useful for common text. + */ + INDEX_TOKENIZED=32, + /** Index the field's value without using an Analyzer, so it can be searched. + * As no analyzer is used the value will be stored as a single term. This is + * useful for unique Ids like product numbers. + */ + INDEX_UNTOKENIZED=64, + /** Index the field's value without an Analyzer, and disable + * the storing of norms. No norms means that index-time boosting + * and field length normalization will be disabled. The benefit is + * less memory usage as norms take up one byte per indexed field + * for every document in the index. + */ + INDEX_NONORMS=128 + }; + + enum TermVector{ + /** Do not store term vectors. */ + TERMVECTOR_NO=256, + /** Store the term vectors of each document. A term vector is a list + * of the document's terms and their number of occurences in that document. */ + TERMVECTOR_YES=512, + /** + * Store the term vector + token position information + * + * @see #YES + */ + TERMVECTOR_WITH_POSITIONS=1024, + /** + * Store the term vector + Token offset information + * + * @see #YES + */ + TERMVECTOR_WITH_OFFSETS=2048 + }; + + _CL_DEPRECATED( another overload ) Field(const TCHAR* name, const TCHAR* value, bool store, bool index, bool token, const bool storeTermVector=false); + _CL_DEPRECATED( another overload ) Field(const TCHAR* name, CL_NS(util)::Reader* reader, bool store, bool index, bool token, const bool storeTermVector=false); + + Field(const TCHAR* name, const TCHAR* value, int configs); + Field(const TCHAR* name, CL_NS(util)::Reader* reader, int configs); + Field(const TCHAR* name, jstreams::StreamBase* stream, int configs); + ~Field(); + + /** Constructs a String-valued Field that is not tokenized, but is indexed + * and stored. Useful for non-text fields, e.g. date or url. + * @deprecated Use new Field(name,value,Field::STORE_YES | Field::INDEX_UNTOKENIZED) + */ + _CL_DEPRECATED( new Field(*) ) static Field* Keyword(const TCHAR* name, const TCHAR* value); + + /** Constructs a String-valued Field that is not tokenized nor indexed, + * but is stored in the index, for return with hits. + * @deprecated Use new Field(name,value,Field::STORE_YES | Field::INDEX_NO) + */ + _CL_DEPRECATED( new Field(*) ) static Field* UnIndexed(const TCHAR* name, const TCHAR* value); + + /** Constructs a String-valued Field that is tokenized and indexed, + * and is stored in the index, for return with hits. Useful for short text + * fields, like "title" or "subject". + * @deprecated Use new Field(name,value,Field::STORE_YES | Field::INDEX_TOKENIZED) + */ + _CL_DEPRECATED( new Field(*) ) static Field* Text(const TCHAR* name, const TCHAR* value, const bool storeTermVector=false); + + /** Constructs a String-valued Field that is tokenized and indexed, + * but that is not stored in the index. + * @deprecated Use new Field(name,value,Field::STORE_NO | Field::INDEX_TOKENIZED) + */ + _CL_DEPRECATED( new Field(*) ) static Field* UnStored(const TCHAR* name, const TCHAR* value, const bool storeTermVector=false); + + /** Constructs a Reader-valued Field that is tokenized and indexed, but is + * *not* stored in the index verbatim. Useful for longer text fields, like + * "body". + * @deprecated Use new Field(name,value, Field::INDEX_TOKENIZED) + */ + _CL_DEPRECATED( new Field(*) ) static Field* Text(const TCHAR* name, CL_NS(util)::Reader* value, const bool storeTermVector=false); + + /** The name of the field (e.g., "date", "subject", "title", "body", etc.) + * as an interned string. */ + const TCHAR* name(); ///* streamValue(); + + // True iff the value of the field is to be stored in the index for return + // with search hits. It is an error for this to be true if a field is + // Reader-valued. + bool isStored(); + + // True iff the value of the field is to be indexed, so that it may be + // searched on. + bool isIndexed(); + + // True iff the value of the field should be tokenized as text prior to + // indexing. Un-tokenized fields are indexed as a single word and may not be + // Reader-valued. + bool isTokenized(); + + /** True if the value of the field is stored and compressed within the index + * NOTE: CLucene does not actually support compressed fields, Instead, a reader + * will be returned with a pointer to a SubIndexInputStream. A GZipInputStream + * and a UTF8 reader must be used to actually read the content. This flag + * will only be set if the index was created by another lucene implementation. + */ + bool isCompressed(); + + //Set configs using XOR. This resets all the settings + //For example, to use term vectors with positions and offsets do: + //object->setConfig(TERMVECTOR_WITH_POSITIONS | TERMVECTOR_WITH_OFFSETS); + void setConfig(int termVector); + + /** True iff the term or terms used to index this field are stored as a term + * vector, available from {@link IndexReader#getTermFreqVector(int32_t,TCHAR*)}. + * These methods do not provide access to the original content of the field, + * only to terms used to index it. If the original content must be + * preserved, use the stored attribute instead. + * + * @see IndexReader#getTermFreqVector(int32_t, String) + */ + bool isTermVectorStored(); + + /** + * True iff terms are stored as term vector together with their offsets + * (start and end positon in source text). + */ + bool isStoreOffsetWithTermVector(); + + /** + * True iff terms are stored as term vector together with their token positions. + */ + bool isStorePositionWithTermVector(); + + /** Returns the boost factor for hits for this field. + * + *

The default value is 1.0. + * + *

Note: this value is not stored directly with the document in the index. + * Documents returned from {@link IndexReader#document(int)} and + * {@link Hits#doc(int)} may thus not have the same value present as when + * this field was indexed. + * + * @see #setBoost(float) + */ + qreal getBoost(); + + /** Sets the boost factor hits on this field. This value will be + * multiplied into the score of all hits on this field of this document. + * + *

The boost is multiplied by {@link Document#getBoost()} of the document + * containing this field. If a document has multiple fields with the same + * name, all such values are multiplied together. This product is then + * multipled by the value {@link Similarity#lengthNorm(String,int)}, and + * rounded by {@link Similarity#encodeNorm(float)} before it is stored in the + * index. One should attempt to ensure that this product does not overflow + * the range of that encoding. + * + * @see Document#setBoost(float) + * @see Similarity#lengthNorm(String, int) + * @see Similarity#encodeNorm(float) + */ + void setBoost(qreal value); + + /** True iff the value of the filed is stored as binary */ + bool isBinary(); + + /** True if norms are omitted for this indexed field */ + bool getOmitNorms(); + + /** Expert: + * + * If set, omit normalization factors associated with this indexed field. + * This effectively disables indexing boosts and length normalization for this field. + */ + void setOmitNorms(bool omitNorms); + + // Prints a Field for human consumption. + TCHAR* toString(); +}; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/index/CompoundFile.cpp b/3rdparty/clucene/src/CLucene/index/CompoundFile.cpp new file mode 100644 index 000000000..efa0e2563 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/CompoundFile.cpp @@ -0,0 +1,380 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +* +* Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "CompoundFile.h" +#include "CLucene/util/Misc.h" + +CL_NS_USE(store) +CL_NS_USE(util) +CL_NS_DEF(index) + +CompoundFileReader::CSIndexInput::CSIndexInput(CL_NS(store)::IndexInput* base, + const int64_t fileOffset, const int64_t length) +{ + this->base = base; + this->fileOffset = fileOffset; + this->_length = length; +} + +void CompoundFileReader::CSIndexInput::readInternal(uint8_t* b, const int32_t len) +{ + SCOPED_LOCK_MUTEX(base->THIS_LOCK) + + int64_t start = getFilePointer(); + if(start + len > _length) + _CLTHROWA(CL_ERR_IO, "read past EOF"); + base->seek(fileOffset + start); + base->readBytes(b, len); +} + +CompoundFileReader::CSIndexInput::~CSIndexInput() +{ +} + +IndexInput* CompoundFileReader::CSIndexInput::clone() const +{ + return _CLNEW CSIndexInput(*this); +} + +CompoundFileReader::CSIndexInput::CSIndexInput(const CSIndexInput& clone) + : BufferedIndexInput(clone) +{ + this->base = clone.base; //no need to clone this.. + this->fileOffset = clone.fileOffset; + this->_length = clone._length; +} + +void CompoundFileReader::CSIndexInput::close() +{ +} + +CompoundFileReader::CompoundFileReader(Directory* dir, const QString& name) + : entries(false, true) +{ + directory = dir; + fileName = name; + + bool success = false; + try { + stream = dir->openInput(name); + + // read the directory and init files + int32_t count = stream->readVInt(); + FileEntry* entry = NULL; + TCHAR tid[CL_MAX_PATH]; + for (int32_t i = 0; i < count; i++) { + int64_t offset = stream->readLong(); + int32_t read = stream->readString(tid, CL_MAX_PATH); + QString aid(QString::fromWCharArray(tid, read)); + + // set length of the previous entry + if (entry != NULL) + entry->length = offset - entry->offset; + + entry = _CLNEW FileEntry(offset); + entries.put(aid, entry); + } + + // set the length of the final entry + if (entry != NULL) + entry->length = stream->length() - entry->offset; + success = true; + } _CLFINALLY ( + if (!success && (stream != NULL)) { + try { + stream->close(); + _CLDELETE(stream); + } catch (CLuceneError& err) { + if (err.number() != CL_ERR_IO) + throw err; + } + } + ) +} + +CompoundFileReader::~CompoundFileReader() +{ + close(); +} + +Directory* CompoundFileReader::getDirectory() +{ + return directory; +} + +QString CompoundFileReader::getName() const +{ + return fileName; +} + +void CompoundFileReader::close() +{ + SCOPED_LOCK_MUTEX(THIS_LOCK) + + if (stream != NULL) { + entries.clear(); + stream->close(); + _CLDELETE(stream); + } +} + +IndexInput* CompoundFileReader::openInput(const QString& id) +{ + SCOPED_LOCK_MUTEX(THIS_LOCK) + + if (stream == NULL) + _CLTHROWA(CL_ERR_IO, "Stream closed"); + + const FileEntry* entry = entries.get(id); + if (entry == NULL) { + char buf[CL_MAX_PATH + 30]; + strcpy(buf,"No sub-file with id "); + strncat(buf, id.toLocal8Bit().constData(), CL_MAX_PATH); + strcat(buf, " found"); + _CLTHROWA(CL_ERR_IO,buf); + } + return _CLNEW CSIndexInput(stream, entry->offset, entry->length); +} + +QStringList CompoundFileReader::list() const +{ + // for (EntriesType::const_iterator i=entries.begin();i!=entries.end();i++){ + // names->push_back(i->first); + // ++i; + // } + + QStringList names; + EntriesType::const_iterator itr; + // TODO: verify this, see old code above ??? + for (itr = entries.begin(); itr != entries.end(); ++itr) + names.push_back(itr->first); + + return names; +} + +bool CompoundFileReader::fileExists(const QString& name) const +{ + return entries.exists(name); +} + +int64_t CompoundFileReader::fileModified(const QString& name) const +{ + return directory->fileModified(fileName); +} + +void CompoundFileReader::touchFile(const QString& name) +{ + directory->touchFile(fileName); +} + +bool CompoundFileReader::doDeleteFile(const QString& name) +{ + _CLTHROWA(CL_ERR_UnsupportedOperation, + "UnsupportedOperationException: CompoundFileReader::doDeleteFile"); +} + +void CompoundFileReader::renameFile(const QString& from, const QString& to) +{ + _CLTHROWA(CL_ERR_UnsupportedOperation, + "UnsupportedOperationException: CompoundFileReader::renameFile"); +} + +int64_t CompoundFileReader::fileLength(const QString& name) const +{ + FileEntry* e = entries.get(name); + if (e == NULL) { + char buf[CL_MAX_PATH + 30]; + strcpy(buf,"File "); + strncat(buf, name.toLocal8Bit().constData(), CL_MAX_PATH); + strcat(buf," does not exist"); + _CLTHROWA(CL_ERR_IO,buf); + } + return e->length; +} + +IndexOutput* CompoundFileReader::createOutput(const QString& name) +{ + _CLTHROWA(CL_ERR_UnsupportedOperation, + "UnsupportedOperationException: CompoundFileReader::createOutput"); +} + +LuceneLock* CompoundFileReader::makeLock(const QString& name) +{ + _CLTHROWA(CL_ERR_UnsupportedOperation, + "UnsupportedOperationException: CompoundFileReader::makeLock"); +} + +QString CompoundFileReader::toString() const +{ + QString ret(QLatin1String("CompoundFileReader@")); + return ret.append(fileName); +} + +CompoundFileWriter::CompoundFileWriter(Directory* dir, const QString& name) + : ids(false) + , entries(true) +{ + if (dir == NULL) + _CLTHROWA(CL_ERR_NullPointer, "directory cannot be null"); + + if (name.isEmpty()) + _CLTHROWA(CL_ERR_NullPointer, "name cannot be null"); + + merged = false; + directory = dir; + fileName = name; +} + +CompoundFileWriter::~CompoundFileWriter() +{ +} + +Directory* CompoundFileWriter::getDirectory() +{ + return directory; +} + +/** Returns the name of the compound file. */ +QString CompoundFileWriter::getName() const +{ + return fileName; +} + +void CompoundFileWriter::addFile(const QString& file) +{ + if (merged) + _CLTHROWA(CL_ERR_IO, "Can't add extensions after merge has been called"); + + if (file.isEmpty()) + _CLTHROWA(CL_ERR_NullPointer, "file cannot be null"); + + if (ids.find(file) != ids.end()) { + char buf[CL_MAX_PATH + 30]; + strcpy(buf, "File "); + strncat(buf, file.toLocal8Bit().constData(), CL_MAX_PATH); + strcat(buf," already added"); + _CLTHROWA(CL_ERR_IO,buf); + } + ids.insert(file); + entries.push_back(_CLNEW WriterFileEntry(file)); +} + +void CompoundFileWriter::close() +{ + if (merged) + _CLTHROWA(CL_ERR_IO, "Merge already performed"); + + if (entries.size() == 0) // isEmpty() + _CLTHROWA(CL_ERR_IO, "No entries to merge have been defined"); + + merged = true; + + // open the compound stream + IndexOutput* os = NULL; + try { + os = directory->createOutput(fileName); + + // Write the number of entries + os->writeVInt(entries.size()); + + // Write the directory with all offsets at 0. + // Remember the positions of directory entries so that we can + // adjust the offsets later + { //msvc6 for scope fix + TCHAR tfile[CL_MAX_PATH]; + for (CLLinkedList::iterator i = entries.begin(); + i != entries.end(); i++) { + WriterFileEntry* fe = *i; + fe->directoryOffset = os->getFilePointer(); + os->writeLong(0); // for now + tfile[fe->file.toWCharArray(tfile)] = '\0'; + os->writeString(tfile, _tcslen(tfile)); + } + } + + // Open the files and copy their data into the stream. + // Remember the locations of each file's data section. + { //msvc6 for scope fix + int32_t bufferLength = 1024; + uint8_t buffer[1024]; + for (CLLinkedList::iterator i = entries.begin(); + i != entries.end(); i++) { + WriterFileEntry* fe = *i; + fe->dataOffset = os->getFilePointer(); + copyFile(fe, os, buffer, bufferLength); + } + } + + { //msvc6 for scope fix + // Write the data offsets into the directory of the compound stream + for (CLLinkedList::iterator i = entries.begin(); + i != entries.end(); i++) { + WriterFileEntry* fe = *i; + os->seek(fe->directoryOffset); + os->writeLong(fe->dataOffset); + } + } + + + } _CLFINALLY ( + if (os != NULL) { + try { + os->close(); + _CLDELETE(os); + } catch (...) { } + } + ); +} + +void CompoundFileWriter::copyFile(WriterFileEntry* source, IndexOutput* os, + uint8_t* buffer, int32_t bufferLength) +{ + IndexInput* is = NULL; + try { + int64_t startPtr = os->getFilePointer(); + + is = directory->openInput(source->file); + int64_t length = is->length(); + int64_t remainder = length; + int32_t chunk = bufferLength; + + while(remainder > 0) { + int32_t len = (int32_t)min((int64_t)chunk, remainder); + is->readBytes(buffer, len); + os->writeBytes(buffer, len); + remainder -= len; + } + + // Verify that remainder is 0 + if (remainder != 0) { + TCHAR buf[CL_MAX_PATH+100]; + _sntprintf(buf, CL_MAX_PATH + 100, _T("Non-zero remainder length ") + _T("after copying: %d (id: %s, length: %d, buffer size: %d)"), + remainder, source->file.toLocal8Bit().constData(), length, chunk); + _CLTHROWT(CL_ERR_IO, buf); + } + + // Verify that the output length diff is equal to original file + int64_t endPtr = os->getFilePointer(); + int64_t diff = endPtr - startPtr; + if (diff != length) { + TCHAR buf[100]; + _sntprintf(buf, 100, _T("Difference in the output file offsets %d ") + _T("does not match the original file length %d"), diff, length); + _CLTHROWT(CL_ERR_IO,buf); + } + } _CLFINALLY ( + if (is != NULL) { + is->close(); + _CLDELETE(is); + } + ); +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/CompoundFile.h b/3rdparty/clucene/src/CLucene/index/CompoundFile.h new file mode 100644 index 000000000..84799a62f --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/CompoundFile.h @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +*/ +#ifndef _lucene_index_compoundfile_h +#define _lucene_index_compoundfile_h + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include "CLucene/store/IndexInput.h" +#include "CLucene/store/IndexOutput.h" +#include "CLucene/store/Directory.h" +#include "CLucene/store/Lock.h" +#include "CLucene/util/VoidList.h" +#include "CLucene/util/VoidMap.h" + +CL_NS_DEF(index) + +// Class for accessing a compound stream. +// This class implements a directory, but is limited to only read operations. +// Directory methods that would normally modify data throw an exception. +class CompoundFileReader : public CL_NS(store)::Directory +{ +private: + /** Implementation of an IndexInput that reads from a portion of the + * compound file. The visibility is left as "package" *only* because + * this helps with testing since JUnit test cases in a different class + * can then access package fields of this class. + */ + class CSIndexInput : public CL_NS(store)::BufferedIndexInput + { + private: + CL_NS(store)::IndexInput* base; + int64_t fileOffset; + int64_t _length; + protected: + /** Expert: implements buffer refill. Reads uint8_ts from the current + * position in the input. + * @param b the array to read uint8_ts into + * @param length the number of uint8_ts to read + */ + void readInternal(uint8_t* b, const int32_t len); + void seekInternal(const int64_t pos) {} + + public: + CSIndexInput(CL_NS(store)::IndexInput* base, const int64_t fileOffset, + const int64_t length); + CSIndexInput(const CSIndexInput& clone); + ~CSIndexInput(); + + /** Closes the stream to futher operations. */ + void close(); + CL_NS(store)::IndexInput* clone() const; + + int64_t length() { return _length; } + + QString getDirectoryType() const { + return CompoundFileReader::DirectoryType(); } + }; + + class FileEntry : LUCENE_BASE + { + public: + FileEntry() + : offset(0), length(0) {} + FileEntry(int64_t _offset) + : offset(_offset), length(0) {} + ~FileEntry() {} + + int64_t offset; + int64_t length; + }; + + // Base info + CL_NS(store)::Directory* directory; + QString fileName; + + CL_NS(store)::IndexInput* stream; + + typedef CL_NS(util)::CLHashMap > EntriesType; + EntriesType entries; +protected: + // Removes an existing file in the directory-> + bool doDeleteFile(const QString& name); + +public: + CompoundFileReader(CL_NS(store)::Directory* dir, const QString& name); + ~CompoundFileReader(); + CL_NS(store)::Directory* getDirectory(); + QString getName() const; + + void close(); + CL_NS(store)::IndexInput* openInput(const QString& id); + + /** Returns an array of strings, one for each file in the directory-> */ + QStringList list() const; + /** Returns true iff a file with the given name exists. */ + bool fileExists(const QString& name) const; + /** Returns the time the named file was last modified. */ + int64_t fileModified(const QString& name) const; + /** Set the modified time of an existing file to now. */ + void touchFile(const QString& name); + /** Renames an existing file in the directory-> + If a file already exists with the new name, then it is replaced. + This replacement should be atomic. */ + void renameFile(const QString& from, const QString& to); + /** Returns the length of a file in the directory. + * @throws IOException if the file does not exist */ + int64_t fileLength(const QString& name) const; + /** Not implemented + * @throws UnsupportedOperationException */ + CL_NS(store)::IndexOutput* createOutput(const QString& name); + /** Not implemented + * @throws UnsupportedOperationException */ + CL_NS(store)::LuceneLock* makeLock(const QString& name); + + QString toString() const; + + static QString DirectoryType() { return QLatin1String("CFS"); } + QString getDirectoryType() const { return DirectoryType(); } +}; + + + +// Combines multiple files into a single compound file. +// The file format:
+//

    +//
  • VInt fileCount
  • +//
  • {Directory} +// fileCount entries with the following structure:
  • +//
      +//
    • int64_t dataOffset
    • +//
    • UTFString extension
    • +//
    +//
  • {File Data} +// fileCount entries with the raw data of the corresponding file
  • +//
+// The fileCount integer indicates how many files are contained in this compound +// file. The {directory} that follows has that many entries. Each directory entry +// contains an encoding identifier, an int64_t pointer to the start of this file's +// data section, and a UTF String with that file's extension. +class CompoundFileWriter : LUCENE_BASE +{ + class WriterFileEntry : LUCENE_BASE { + public: + WriterFileEntry() + : dataOffset(0), directoryOffset(0) {} + WriterFileEntry(const QString& _file) + : file(_file), dataOffset(0), directoryOffset(0) {} + ~WriterFileEntry() {} + + QString file; + // temporary holder for the start of this file's data section + int64_t dataOffset; + // temporary holder for the start of directory entry for this file + int64_t directoryOffset; + }; + + bool merged; + QString fileName; + CL_NS(store)::Directory* directory; + + CL_NS(util)::CLHashSet ids; + + CL_NS(util)::CLLinkedList > entries; + + // Copy the contents of the file with specified extension into the + // provided output stream. Use the provided buffer for moving data + // to reduce memory allocation. + void copyFile(WriterFileEntry* source, CL_NS(store)::IndexOutput* os, + uint8_t* buffer, int32_t bufferLength); + +public: + // Create the compound stream in the specified file. The file name is the + // entire name (no extensions are added). + CompoundFileWriter(CL_NS(store)::Directory* dir, const QString& name); + ~CompoundFileWriter(); + + // Returns the directory of the compound file. + CL_NS(store)::Directory* getDirectory(); + + QString getName() const ; + /* Add a source stream. file is the string by which the + * sub-stream will be known in the compound stream. + * + * @throws IllegalStateException if this writer is closed + * @throws NullPointerException if file is null + * @throws IllegalArgumentException if a file with the same name + * has been added already + */ + void addFile(const QString& file); + /* Merge files with the extensions added up to now. + * All files with these extensions are combined sequentially into the + * compound stream. After successful merge, the source files + * @throws IllegalStateException if close() had been called before or + * if no file has been added to this object + * are deleted. + */ + void close(); +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/index/DocumentWriter.cpp b/3rdparty/clucene/src/CLucene/index/DocumentWriter.cpp new file mode 100644 index 000000000..dcbc31591 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/DocumentWriter.cpp @@ -0,0 +1,571 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#include "CLucene/StdHeader.h" + +#include "DocumentWriter.h" +#include "FieldInfos.h" +#include "IndexWriter.h" +#include "FieldsWriter.h" +#include "Term.h" +#include "TermInfo.h" +#include "TermInfosWriter.h" + +#include "CLucene/analysis/AnalysisHeader.h" + +#include "CLucene/search/Similarity.h" +#include "TermInfosWriter.h" +#include "FieldsWriter.h" + +CL_NS_USE(util) +CL_NS_USE(store) +CL_NS_USE(analysis) +CL_NS_USE(document) +CL_NS_DEF(index) + +/*Posting*/ + +DocumentWriter::Posting::Posting(Term* t, const int32_t position, + TermVectorOffsetInfo* offset) +{ + //Func - Constructor + //Pre - t contains a valid reference to a Term + //Post - Instance has been created + freq = 1; + + term = _CL_POINTER(t); + positions.values = (int32_t*)malloc(sizeof(int32_t)); + positions.values[0] = position; + positions.length = 1; + + if ( offset != NULL ){ + this->offsets.values =(TermVectorOffsetInfo*)malloc(sizeof(TermVectorOffsetInfo)); + this->offsets.values[0] = *offset; + this->offsets.length = 1; + } +} + +DocumentWriter::Posting::~Posting() +{ + //Func - Destructor + //Pre - true + //Post - The instance has been destroyed + + free(positions.values); + if ( this->offsets.values != NULL ) + free(this->offsets.values); + _CLDECDELETE(term); +} + +DocumentWriter::DocumentWriter(Directory* d, Analyzer* a, + CL_NS(search)::Similarity* sim, const int32_t mfl) + : analyzer(a) + , directory(d) + , maxFieldLength(mfl) + , fieldInfos(NULL) + , fieldLengths(NULL) + , similarity(sim) + , termIndexInterval(IndexWriter::DEFAULT_TERM_INDEX_INTERVAL) + , fieldPositions(NULL) + , fieldBoosts(NULL) + , termBuffer(_CLNEW Term) +{ + //Pre - d contains a valid reference to a Directory + // d contains a valid reference to a Analyzer + // mfl > 0 and contains the maximum field length + //Post - Instance has been created + + CND_PRECONDITION(((mfl > 0) || (mfl == IndexWriter::FIELD_TRUNC_POLICY__WARN)), + "mfl is 0 or smaller than IndexWriter::FIELD_TRUNC_POLICY__WARN") + + fieldInfos = NULL; + fieldLengths = NULL; +} + +DocumentWriter::DocumentWriter(CL_NS(store)::Directory* d, + CL_NS(analysis)::Analyzer* a, IndexWriter* writer) + : analyzer(a) + , directory(d) + , maxFieldLength(writer->getMaxFieldLength()) + , fieldInfos(NULL) + , fieldLengths(NULL) + , similarity(writer->getSimilarity()) + , termIndexInterval(writer->getTermIndexInterval()) + , fieldPositions(NULL) + , fieldBoosts(NULL) + , termBuffer(_CLNEW Term) +{ + //Pre - d contains a valid reference to a Directory + // d contains a valid reference to a Analyzer + // mfl > 0 and contains the maximum field length + //Post - Instance has been created + + CND_PRECONDITION(((maxFieldLength > 0) + || (maxFieldLength == IndexWriter::FIELD_TRUNC_POLICY__WARN)), + "mfl is 0 or smaller than IndexWriter::FIELD_TRUNC_POLICY__WARN") + + fieldInfos = NULL; + fieldLengths = NULL; + +} + +DocumentWriter::~DocumentWriter() +{ + //Func - Destructor + //Pre - true + //Post - The instance has been destroyed + clearPostingTable(); + _CLDELETE( fieldInfos ); + _CLDELETE_ARRAY(fieldLengths); + _CLDELETE_ARRAY(fieldPositions); + _CLDELETE_ARRAY(fieldBoosts); + _CLDELETE_ARRAY(fieldOffsets); + + _CLDECDELETE(termBuffer); +} + +void DocumentWriter::clearPostingTable() +{ + PostingTableType::iterator itr = postingTable.begin(); + while (itr != postingTable.end()){ + _CLDELETE(itr->second); + _CLLDECDELETE(itr->first); + ++itr; + } + postingTable.clear(); +} + +void DocumentWriter::addDocument(const QString& segment, Document* doc) +{ + CND_PRECONDITION(fieldInfos == NULL, "fieldInfos!=NULL") + + // write field names + fieldInfos = _CLNEW FieldInfos(); + fieldInfos->add(doc); + + QString buf = Misc::segmentname(segment, QLatin1String(".fnm")); + fieldInfos->write(directory, buf); + + // write field values + FieldsWriter fieldsWriter(directory, segment, fieldInfos); + try { + fieldsWriter.addDocument(doc); + } _CLFINALLY ( + fieldsWriter.close() + ); + + // clear postingTable + clearPostingTable(); + + int32_t fieldInfoSize = fieldInfos->size(); + fieldLengths = _CL_NEWARRAY(int32_t, fieldInfoSize); // init fieldLengths + fieldPositions = _CL_NEWARRAY(int32_t, fieldInfoSize); // init fieldPositions + fieldOffsets = _CL_NEWARRAY(int32_t, fieldInfoSize); // init fieldOffsets + fieldBoosts = _CL_NEWARRAY(qreal, fieldInfoSize); // init fieldBoosts + + qreal fbd = doc->getBoost(); + for (int32_t i = 0; i < fieldInfoSize; ++i) { + fieldLengths[i] = 0; + fieldPositions[i] = 0; + fieldOffsets[i] = 0; + //initialise fieldBoost array with default boost + fieldBoosts[i] = fbd; + } + + // invert doc into postingTable + invertDocument(doc); + + // sort postingTable into an array + Posting** postings = NULL; + int32_t postingsLength = 0; + sortPostingTable(postings, postingsLength); + + //DEBUG: + /*for (int32_t i = 0; i < postingsLength; i++) { + Posting* posting = postings[i]; + + TCHAR* b = posting->term->toString(); + _cout << b << " freq=" << posting->freq; + _CLDELETE(b); + + _cout << " pos=" << posting->positions[0]; + for (int32_t j = 1; j < posting->freq; j++) + _cout <<"," << posting->positions[j]; + + _cout << endl; + }*/ + + + // write postings + writePostings(postings, postingsLength, segment); + + // write norms of indexed fields + writeNorms(segment); + _CLDELETE_ARRAY(postings); +} + +void DocumentWriter::sortPostingTable(Posting**& array, int32_t& arraySize) +{ + // copy postingTable into an array + arraySize = postingTable.size(); + array = _CL_NEWARRAY(Posting*,arraySize); + PostingTableType::iterator postings = postingTable.begin(); + int32_t i=0; + while ( postings != postingTable.end() ){ + array[i] = (Posting*)postings->second; + postings++; + i++; + } + // sort the array + quickSort(array, 0, i - 1); +} + + +void DocumentWriter::invertDocument(const Document* doc) +{ + DocumentFieldEnumeration* fields = doc->fields(); + try { + while (fields->hasMoreElements()) { + Field* field = (Field*)fields->nextElement(); + const TCHAR* fieldName = field->name(); + const int32_t fieldNumber = fieldInfos->fieldNumber(fieldName); + + int32_t length = fieldLengths[fieldNumber]; // length of field + int32_t position = fieldPositions[fieldNumber]; // position in field + if (length>0) + position+=analyzer->getPositionIncrementGap(fieldName); + int32_t offset = fieldOffsets[fieldNumber]; // offset field + + if (field->isIndexed()) { + if (!field->isTokenized()) { // un-tokenized field + //FEATURE: this is bug in java: if using a Reader, then + //field value will not be added. With CLucene, an untokenized + //field with a reader will still be added (if it isn't stored, + //because if it's stored, then the reader has already been read. + const TCHAR* charBuf = NULL; + int64_t dataLen = 0; + + if (field->stringValue() == NULL && !field->isStored() ) { + CL_NS(util)::Reader* r = field->readerValue(); + // this call tries to read the entire stream + // this may invalidate the string for the further calls + // it may be better to do this via a FilterReader + // TODO make a better implementation of this + dataLen = r->read(charBuf, LUCENE_INT32_MAX_SHOULDBE); + if (dataLen == -1) + dataLen = 0; + //todo: would be better to pass the string length, in case + //a null char is passed, but then would need to test the output too. + } else { + charBuf = field->stringValue(); + dataLen = _tcslen(charBuf); + } + + if(field->isStoreOffsetWithTermVector()){ + TermVectorOffsetInfo tio; + tio.setStartOffset(offset); + tio.setEndOffset(offset + dataLen); + addPosition(fieldName, charBuf, position++, &tio ); + }else + addPosition(fieldName, charBuf, position++, NULL); + offset += dataLen; + length++; + } else { // field must be tokenized + CL_NS(util)::Reader* reader; // find or make Reader + bool delReader = false; + if (field->readerValue() != NULL) { + reader = field->readerValue(); + } else if (field->stringValue() != NULL) { + reader = _CLNEW CL_NS(util)::StringReader( + field->stringValue(),_tcslen(field->stringValue()), + false); + delReader = true; + } else { + _CLTHROWA(CL_ERR_IO,"field must have either String or Reader value"); + } + + try { + // Tokenize field and add to postingTable. + CL_NS(analysis)::TokenStream* stream = + analyzer->tokenStream(fieldName, reader); + + try { + CL_NS(analysis)::Token t; + int32_t lastTokenEndOffset = -1; + while (stream->next(&t)) { + position += (t.getPositionIncrement() - 1); + + if(field->isStoreOffsetWithTermVector()){ + TermVectorOffsetInfo tio; + tio.setStartOffset(offset + t.startOffset()); + tio.setEndOffset(offset + t.endOffset()); + addPosition(fieldName, t.termText(), position++, &tio); + } else + addPosition(fieldName, t.termText(), position++, NULL); + + lastTokenEndOffset = t.endOffset(); + length++; + // Apply field truncation policy. + if (maxFieldLength != IndexWriter::FIELD_TRUNC_POLICY__WARN) { + // The client programmer has explicitly authorized us to + // truncate the token stream after maxFieldLength tokens. + if ( length > maxFieldLength) + break; + } else if (length > IndexWriter::DEFAULT_MAX_FIELD_LENGTH) { + const TCHAR* errMsgBase = + _T("Indexing a huge number of tokens from a single") + _T(" field (\"%s\", in this case) can cause CLucene") + _T(" to use memory excessively.") + _T(" By default, CLucene will accept only %s tokens") + _T(" tokens from a single field before forcing the") + _T(" client programmer to specify a threshold at") + _T(" which to truncate the token stream.") + _T(" You should set this threshold via") + _T(" IndexReader::maxFieldLength (set to LUCENE_INT32_MAX") + _T(" to disable truncation, or a value to specify maximum number of fields)."); + + TCHAR defaultMaxAsChar[34]; + _i64tot(IndexWriter::DEFAULT_MAX_FIELD_LENGTH, + defaultMaxAsChar, 10 + ); + int32_t errMsgLen = _tcslen(errMsgBase) + + _tcslen(fieldName) + + _tcslen(defaultMaxAsChar); + TCHAR* errMsg = _CL_NEWARRAY(TCHAR,errMsgLen+1); + + _sntprintf(errMsg, errMsgLen,errMsgBase, fieldName, defaultMaxAsChar); + + _CLTHROWT_DEL(CL_ERR_Runtime,errMsg); + } + } // while token->next + + if(lastTokenEndOffset != -1 ) + offset += lastTokenEndOffset + 1; + } _CLFINALLY ( + stream->close(); + _CLDELETE(stream); + ); + } _CLFINALLY ( + if (delReader) { + _CLDELETE(reader); + } + ); + } // if/else field is to be tokenized + fieldLengths[fieldNumber] = length; // save field length + fieldPositions[fieldNumber] = position; // save field position + fieldBoosts[fieldNumber] *= field->getBoost(); + fieldOffsets[fieldNumber] = offset; + } // if field is to beindexed + } // while more fields available + } _CLFINALLY ( + _CLDELETE(fields); + ); +} + +void DocumentWriter::addPosition(const TCHAR* field, const TCHAR* text, + const int32_t position, TermVectorOffsetInfo* offset) +{ + termBuffer->set(field,text,false); + + Posting* ti = postingTable.get(termBuffer); + if (ti != NULL) { // word seen before + int32_t freq = ti->freq; + if (ti->positions.length == freq) { + // positions array is full, realloc its size + ti->positions.length = freq*2; + ti->positions.values = (int32_t*)realloc(ti->positions.values, ti->positions.length * sizeof(int32_t)); + } + ti->positions.values[freq] = position; // add new position + + if (offset != NULL) { + if (ti->offsets.length == freq){ + ti->offsets.length = freq*2; + ti->offsets.values = (TermVectorOffsetInfo*)realloc(ti->offsets.values, ti->offsets.length * sizeof(TermVectorOffsetInfo)); + } + ti->offsets[freq] = *offset; + } + + ti->freq = freq + 1; // update frequency + } else { // word not seen before + Term* term = _CLNEW Term( field, text, false); + postingTable.put(term, _CLNEW Posting(term, position, offset)); + } +} + +//static +void DocumentWriter::quickSort(Posting**& postings, const int32_t lo, const int32_t hi) +{ + if(lo >= hi) + return; + + int32_t mid = (lo + hi) / 2; + + if(postings[lo]->term->compareTo(postings[mid]->term) > 0) { + Posting* tmp = postings[lo]; + postings[lo] = postings[mid]; + postings[mid] = tmp; + } + + if(postings[mid]->term->compareTo(postings[hi]->term) > 0) { + Posting* tmp = postings[mid]; + postings[mid] = postings[hi]; + postings[hi] = tmp; + + if(postings[lo]->term->compareTo(postings[mid]->term) > 0) { + Posting* tmp2 = postings[lo]; + postings[lo] = postings[mid]; + postings[mid] = tmp2; + } + } + + int32_t left = lo + 1; + int32_t right = hi - 1; + + if (left >= right) + return; + + const Term* partition = postings[mid]->term; //not kept, so no need to finalize + + for( ;; ) { + while(postings[right]->term->compareTo(partition) > 0) + --right; + + while(left < right && postings[left]->term->compareTo(partition) <= 0) + ++left; + + if(left < right) { + Posting* tmp = postings[left]; + postings[left] = postings[right]; + postings[right] = tmp; + --right; + } else { + break; + } + } + + quickSort(postings, lo, left); + quickSort(postings, left + 1, hi); +} + +void DocumentWriter::writePostings(Posting** postings, + const int32_t postingsLength, const QString& segment) +{ + #define __DOCLOSE(obj) \ + if (obj!=NULL) { \ + try { \ + obj->close(); \ + _CLDELETE(obj); \ + } catch(CLuceneError &e) { \ + ierr = e.number(); \ + err = e.what(); \ + } catch(...) { \ + err = "Unknown error while closing posting tables"; \ + } \ + } + + IndexOutput* freq = NULL; + IndexOutput* prox = NULL; + TermInfosWriter* tis = NULL; + TermVectorsWriter* termVectorWriter = NULL; + try { + //open files for inverse index storage + QString buf = Misc::segmentname(segment, QLatin1String(".frq")); + freq = directory->createOutput(buf); + + buf = Misc::segmentname(segment, QLatin1String(".prx")); + prox = directory->createOutput(buf); + + tis = _CLNEW TermInfosWriter(directory, segment, fieldInfos, + termIndexInterval); + TermInfo* ti = _CLNEW TermInfo(); + const TCHAR* currentField = NULL; + for (int32_t i = 0; i < postingsLength; i++) { + Posting* posting = postings[i]; + + // add an entry to the dictionary with pointers to prox and freq files + ti->set(1, freq->getFilePointer(), prox->getFilePointer(), -1); + tis->add(posting->term, ti); + + // add an entry to the freq file + int32_t postingFreq = posting->freq; + if (postingFreq == 1) // optimize freq=1 + freq->writeVInt(1); // set low bit of doc num. + else { + freq->writeVInt(0); // the document number + freq->writeVInt(postingFreq); // frequency in doc + } + + int32_t lastPosition = 0; // write positions + for (int32_t j = 0; j < postingFreq; ++j) { // use delta-encoding + prox->writeVInt(posting->positions.values[j] - lastPosition); + lastPosition = posting->positions.values[j]; + } + + // check to see if we switched to a new field + const TCHAR* termField = posting->term->field(); + if ( currentField == NULL || _tcscmp(currentField,termField) != 0 ) { + //todo, can we do an intern'd check? + // changing field - see if there is something to save + currentField = termField; + FieldInfo* fi = fieldInfos->fieldInfo(currentField); + + if (fi->storeTermVector) { + if (termVectorWriter == NULL) { + termVectorWriter = _CLNEW TermVectorsWriter(directory, + segment, fieldInfos); + termVectorWriter->openDocument(); + } + termVectorWriter->openField(currentField); + } else if (termVectorWriter != NULL) { + termVectorWriter->closeField(); + } + } + if (termVectorWriter != NULL && termVectorWriter->isFieldOpen()) { + termVectorWriter->addTerm(posting->term->text(), postingFreq, + &posting->positions, &posting->offsets); + } + } + if (termVectorWriter != NULL) + termVectorWriter->closeDocument(); + _CLDELETE(ti); + } _CLFINALLY ( + const char* err = NULL; + int32_t ierr = 0; + + // make an effort to close all streams we can but remember and re-throw + // the first exception encountered in this process + __DOCLOSE(freq); + __DOCLOSE(prox); + __DOCLOSE(tis); + __DOCLOSE(termVectorWriter); + if (err != NULL) + _CLTHROWA(ierr,err); + ); +} + +void DocumentWriter::writeNorms(const QString& segment) +{ + for(int32_t n = 0; n < fieldInfos->size(); n++){ + FieldInfo* fi = fieldInfos->fieldInfo(n); + if(fi->isIndexed && !fi->omitNorms) { + qreal norm = fieldBoosts[n] * similarity->lengthNorm( + fi->name, fieldLengths[n]); + + QString fn(segment + QLatin1String(".f%1")); + IndexOutput* norms = directory->createOutput(fn.arg(n)); + try { + norms->writeByte(CL_NS(search)::Similarity::encodeNorm(norm)); + }_CLFINALLY ( + norms->close(); + _CLDELETE(norms); + ) + } + } +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/DocumentWriter.h b/3rdparty/clucene/src/CLucene/index/DocumentWriter.h new file mode 100644 index 000000000..7096ba3ee --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/DocumentWriter.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#ifndef _lucene_index_DocumentWriter_ +#define _lucene_index_DocumentWriter_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include + +#include "CLucene/analysis/AnalysisHeader.h" +#include "CLucene/document/Document.h" +#include "CLucene/store/Directory.h" +#include "FieldInfos.h" +#include "IndexWriter.h" +#include "CLucene/util/VoidMap.h" +#include "CLucene/document/Field.h" +#include "TermInfo.h" +#include "CLucene/search/Similarity.h" +#include "TermInfosWriter.h" +#include "FieldsWriter.h" +#include "Term.h" + +CL_NS_DEF(index) + +class DocumentWriter : LUCENE_BASE +{ +public: + // info about a Term in a doc + class Posting : LUCENE_BASE + { + public: + Term* term; // the Term + int32_t freq; // its frequency in doc + Array positions; // positions it occurs at + Array offsets; + + Posting(Term* t, const int32_t position, TermVectorOffsetInfo* offset); + ~Posting(); + }; + +private: + CL_NS(analysis)::Analyzer* analyzer; + CL_NS(store)::Directory* directory; + FieldInfos* fieldInfos; //array + const int32_t maxFieldLength; + CL_NS(search)::Similarity* similarity; + int32_t termIndexInterval; + + // Keys are Terms, values are Postings. + // Used to buffer a document before it is written to the index. + typedef CL_NS(util)::CLHashtable PostingTableType; + PostingTableType postingTable; + int32_t* fieldLengths; //array + int32_t* fieldPositions; //array + int32_t* fieldOffsets; //array + qreal* fieldBoosts; //array + + Term* termBuffer; +public: + /** This ctor used by test code only. + * + * @param directory The directory to write the document information to + * @param analyzer The analyzer to use for the document + * @param similarity The Similarity function + * @param maxFieldLength The maximum number of tokens a field may have + */ + DocumentWriter(CL_NS(store)::Directory* d, CL_NS(analysis)::Analyzer* a, + CL_NS(search)::Similarity* similarity, const int32_t maxFieldLength); + + DocumentWriter(CL_NS(store)::Directory* directory, + CL_NS(analysis)::Analyzer* analyzer, IndexWriter* writer); + ~DocumentWriter(); + + void addDocument(const QString& segment, CL_NS(document)::Document* doc); + + +private: + // Tokenizes the fields of a document into Postings. + void invertDocument(const CL_NS(document)::Document* doc); + + void addPosition(const TCHAR* field, const TCHAR* text, + const int32_t position, TermVectorOffsetInfo* offset); + + void sortPostingTable(Posting**& array, int32_t& arraySize); + + static void quickSort(Posting**& postings, const int32_t lo, const int32_t hi); + + void writePostings(Posting** postings, const int32_t postingsLength, + const QString& segment); + + void writeNorms(const QString& segment); + + void clearPostingTable(); +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/index/FieldInfo.h b/3rdparty/clucene/src/CLucene/index/FieldInfo.h new file mode 100644 index 000000000..387c4a6ac --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/FieldInfo.h @@ -0,0 +1,16 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_index_FieldInfo_ +#define _lucene_index_FieldInfo_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#error "This header is deprecated, use FieldInfos.h instead" + +#endif diff --git a/3rdparty/clucene/src/CLucene/index/FieldInfos.cpp b/3rdparty/clucene/src/CLucene/index/FieldInfos.cpp new file mode 100644 index 000000000..0c66882f4 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/FieldInfos.cpp @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#include "CLucene/StdHeader.h" +#include "FieldInfos.h" + +#include "CLucene/store/Directory.h" +#include "CLucene/document/Document.h" +#include "CLucene/document/Field.h" +#include "CLucene/util/VoidMap.h" +#include "CLucene/util/Misc.h" +#include "CLucene/util/StringIntern.h" + +CL_NS_USE(store) +CL_NS_USE(document) +CL_NS_USE(util) +CL_NS_DEF(index) + +FieldInfo::FieldInfo(const TCHAR* _fieldName, bool _isIndexed, + int32_t _fieldNumber, bool _storeTermVector, bool _storeOffsetWithTermVector, + bool _storePositionWithTermVector, bool _omitNorms) + : name(CLStringIntern::intern(_fieldName CL_FILELINE)) + , isIndexed(_isIndexed) + , number(_fieldNumber) + , storeTermVector(_storeTermVector) + , storeOffsetWithTermVector(_storeOffsetWithTermVector) + , storePositionWithTermVector(_storeTermVector) + , omitNorms(_omitNorms) +{ +} + +FieldInfo::~FieldInfo() +{ + CL_NS(util)::CLStringIntern::unintern(name); +} + +// #pragma mark -- FieldInfos + +FieldInfos::FieldInfos() + : byName(false, false) + , byNumber(true) +{ +} + +FieldInfos::~FieldInfos() +{ + byName.clear(); + byNumber.clear(); +} + +FieldInfos::FieldInfos(Directory* d, const QString& name) + : byName(false, false) + , byNumber(true) +{ + IndexInput* input = d->openInput(name); + try { + read(input); + } _CLFINALLY ( + input->close(); + _CLDELETE(input); + ); +} + +void FieldInfos::add(const Document* doc) +{ + DocumentFieldEnumeration* fields = doc->fields(); + Field* field; + while (fields->hasMoreElements()) { + field = fields->nextElement(); + add(field->name(), field->isIndexed(), field->isTermVectorStored()); + } + _CLDELETE(fields); +} + +void FieldInfos::add(const TCHAR* name, bool isIndexed, bool storeTermVector, + bool storePositionWithTermVector, bool storeOffsetWithTermVector, bool omitNorms) +{ + FieldInfo* fi = fieldInfo(name); + if (fi == NULL) { + addInternal(name, isIndexed, storeTermVector, + storePositionWithTermVector, + storeOffsetWithTermVector, omitNorms); + } else { + if (fi->isIndexed != isIndexed) { + // once indexed, always index + fi->isIndexed = true; + } + + if (fi->storeTermVector != storeTermVector) { + // once vector, always vector + fi->storeTermVector = true; + } + + if (fi->storePositionWithTermVector != storePositionWithTermVector) { + // once vector, always vector + fi->storePositionWithTermVector = true; + } + + if (fi->storeOffsetWithTermVector != storeOffsetWithTermVector) { + // once vector, always vector + fi->storeOffsetWithTermVector = true; + } + + if (fi->omitNorms != omitNorms) { + // once norms are stored, always store + fi->omitNorms = false; + } + } +} + +void FieldInfos::add(const TCHAR** names, bool isIndexed, bool storeTermVectors, + bool storePositionWithTermVector, bool storeOffsetWithTermVector, bool omitNorms) +{ + int32_t i=0; + while (names[i] != NULL) { + add(names[i], isIndexed, storeTermVectors, storePositionWithTermVector, + storeOffsetWithTermVector, omitNorms); + ++i; + } +} + +int32_t FieldInfos::fieldNumber(const TCHAR* fieldName) const +{ + FieldInfo* fi = fieldInfo(fieldName); + return (fi != NULL) ? fi->number : -1; +} + +FieldInfo* FieldInfos::fieldInfo(const TCHAR* fieldName) const +{ + return byName.get(fieldName); +} + +const TCHAR* FieldInfos::fieldName(const int32_t fieldNumber) const +{ + FieldInfo* fi = fieldInfo(fieldNumber); + return (fi == NULL) ? LUCENE_BLANK_STRING : fi->name; +} + +FieldInfo* FieldInfos::fieldInfo(const int32_t fieldNumber) const +{ + if (fieldNumber < 0 || (size_t)fieldNumber >= byNumber.size()) + return NULL; + return byNumber[fieldNumber]; +} + +int32_t FieldInfos::size() const +{ + return byNumber.size(); +} + +void FieldInfos::write(Directory* d, const QString& name) const +{ + IndexOutput* output = d->createOutput(name); + try { + write(output); + } _CLFINALLY ( + output->close(); + _CLDELETE(output); + ); +} + +void FieldInfos::write(IndexOutput* output) const +{ + output->writeVInt(size()); + FieldInfo* fi; + uint8_t bits; + for (int32_t i = 0; i < size(); ++i) { + fi = fieldInfo(i); + bits = 0x0; + if (fi->isIndexed) + bits |= IS_INDEXED; + + if (fi->storeTermVector) + bits |= STORE_TERMVECTOR; + + if (fi->storePositionWithTermVector) + bits |= STORE_POSITIONS_WITH_TERMVECTOR; + + if (fi->storeOffsetWithTermVector) + bits |= STORE_OFFSET_WITH_TERMVECTOR; + + if (fi->omitNorms) + bits |= OMIT_NORMS; + + output->writeString(fi->name, _tcslen(fi->name)); + output->writeByte(bits); + } +} + +void FieldInfos::read(IndexInput* input) +{ + int32_t size = input->readVInt(); + for (int32_t i = 0; i < size; ++i) { + // we could read name into a string buffer, but we can't be sure what + // the maximum field length will be. + TCHAR* name = input->readString(); + uint8_t bits = input->readByte(); + bool isIndexed = (bits & IS_INDEXED) != 0; + bool storeTermVector = (bits & STORE_TERMVECTOR) != 0; + bool storePositionsWithTermVector = + (bits & STORE_POSITIONS_WITH_TERMVECTOR) != 0; + bool storeOffsetWithTermVector = (bits & STORE_OFFSET_WITH_TERMVECTOR) != 0; + bool omitNorms = (bits & OMIT_NORMS) != 0; + + addInternal(name, isIndexed, storeTermVector, + storePositionsWithTermVector, storeOffsetWithTermVector, omitNorms); + _CLDELETE_CARRAY(name); + } +} + +void FieldInfos::addInternal(const TCHAR* name, bool isIndexed, + bool storeTermVector, bool storePositionWithTermVector, + bool storeOffsetWithTermVector, bool omitNorms) +{ + FieldInfo* fi = _CLNEW FieldInfo(name, isIndexed, byNumber.size(), + storeTermVector, storePositionWithTermVector, storeOffsetWithTermVector, + omitNorms); + byNumber.push_back(fi); + byName.put(fi->name, fi); +} + +bool FieldInfos::hasVectors() const +{ + for (int32_t i = 0; i < size(); i++) { + if (fieldInfo(i)->storeTermVector) + return true; + } + return false; +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/FieldInfos.h b/3rdparty/clucene/src/CLucene/index/FieldInfos.h new file mode 100644 index 000000000..7b6d0f56d --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/FieldInfos.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#ifndef _lucene_index_FieldInfos_ +#define _lucene_index_FieldInfos_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include + +#include "CLucene/store/Directory.h" +#include "CLucene/document/Document.h" +#include "CLucene/util/VoidMap.h" +#include "CLucene/util/VoidList.h" + +CL_NS_DEF(index) + +class FieldInfo : LUCENE_BASE +{ + public: + //name of the field + const TCHAR* name; + + //Is field indexed? true = yes false = no + bool isIndexed; + + //field number + const int32_t number; + + // true if term vector for this field should be stored + bool storeTermVector; + bool storeOffsetWithTermVector; + bool storePositionWithTermVector; + + bool omitNorms; // omit norms associated with indexed fields + + //Func - Constructor + // Initialises FieldInfo. + // na holds the name of the field + // tk indicates whether this field is indexed or not + // nu indicates its number + //Pre - na != NULL and holds the name of the field + // tk is true or false + // number >= 0 + //Post - The FieldInfo instance has been created and initialized. + // name holds the duplicated string of na + // isIndexed = tk + // number = nu + FieldInfo(const TCHAR* fieldName, bool isIndexed, int32_t fieldNumber, + bool storeTermVector, bool storeOffsetWithTermVector, + bool storePositionWithTermVector, bool omitNorms); + + //Func - Destructor + //Pre - true + //Post - The instance has been destroyed + ~FieldInfo(); +}; + +/* Access to the Field Info file that describes document fields and whether or + * not they are indexed. Each segment has a separate Field Info file. Objects + * of this class are thread-safe for multiple readers, but only one thread can + * be adding documents at a time, with no other reader or writer threads + * accessing this object. +*/ +class FieldInfos : LUCENE_BASE +{ +private: + // we now use internd field names, so we can use the voidCompare to + // directly compare the strings + typedef CL_NS(util)::CLHashMap defByName; + defByName byName; + + CL_NS(util)::CLArrayList > byNumber; + +public: + enum { + IS_INDEXED = 0x1, + STORE_TERMVECTOR = 0x2, + STORE_POSITIONS_WITH_TERMVECTOR = 0x4, + STORE_OFFSET_WITH_TERMVECTOR = 0x8, + OMIT_NORMS = 0x10 + }; + + FieldInfos(); + ~FieldInfos(); + + // Construct a FieldInfos object using the directory and the name of the + // file IndexInput + // @param d The directory to open the IndexInput from + // @param name Name of the file to open the IndexInput from in the Directory + // @throws IOException + // @see #read + FieldInfos(CL_NS(store)::Directory* d, const QString& name); + + int32_t fieldNumber(const TCHAR* fieldName)const; + + // Return the fieldinfo object referenced by the fieldNumber. + // @param fieldNumber + // @return the FieldInfo object or null when the given fieldNumber + // doesn't exist. + FieldInfo* fieldInfo(const TCHAR* fieldName) const; + + // Return the fieldName identified by its number. + // @param fieldNumber + // @return the fieldName or an empty string when the field + // with the given number doesn't exist. + const TCHAR* fieldName(const int32_t fieldNumber) const; + + FieldInfo* fieldInfo(const int32_t fieldNumber) const; + + int32_t size()const; + + bool hasVectors() const; + + // Adds field info for a Document. + void add(const CL_NS(document)::Document* doc); + + // Merges in information from another FieldInfos. + void add(FieldInfos* other); + + + /** If the field is not yet known, adds it. If it is known, checks to make + * sure that the isIndexed flag is the same as was given previously for this + * field. If not - marks it as being indexed. Same goes for the TermVector + * parameters. + * + * @param name The name of the field + * @param isIndexed true if the field is indexed + * @param storeTermVector true if the term vector should be stored + * @param storePositionWithTermVector true if the term vector with positions should be stored + * @param storeOffsetWithTermVector true if the term vector with offsets should be stored + */ + void add(const TCHAR* name, bool isIndexed, bool storeTermVector = false, + bool storePositionWithTermVector = false, + bool storeOffsetWithTermVector = false, bool omitNorms = false); + + /** + * Assumes the fields are not storing term vectors + * @param names The names of the fields + * @param isIndexed true if the field is indexed + * @param storeTermVector true if the term vector should be stored + * + * @see #add(String, boolean) + */ + void add(const TCHAR** names, bool isIndexed, bool storeTermVector = false, + bool storePositionWithTermVector = false, + bool storeOffsetWithTermVector = false, bool omitNorms = false); + + void write(CL_NS(store)::Directory* d, const QString& name) const; + void write(CL_NS(store)::IndexOutput* output) const; + +private: + void read(CL_NS(store)::IndexInput* input); + void addInternal(const TCHAR* name, bool isIndexed, bool storeTermVector, + bool storePositionWithTermVector, bool storeOffsetWithTermVector, + bool omitNorms); + +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/index/FieldsReader.cpp b/3rdparty/clucene/src/CLucene/index/FieldsReader.cpp new file mode 100644 index 000000000..e3f9d1cc2 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/FieldsReader.cpp @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#include "CLucene/StdHeader.h" +#include "FieldsReader.h" + +#include "CLucene/util/VoidMap.h" +#include "CLucene/util/Misc.h" +#include "CLucene/store/Directory.h" +#include "CLucene/document/Document.h" +#include "CLucene/document/Field.h" +#include "FieldInfos.h" +#include "FieldsWriter.h" + +CL_NS_USE(store) +CL_NS_USE(document) +CL_NS_USE(util) +CL_NS_DEF(index) + +FieldsReader::FieldsReader(Directory* d, const QString& segment, FieldInfos* fn) + : fieldInfos(fn) +{ + //Func - Constructor + //Pre - d contains a valid reference to a Directory + // segment != NULL + // fn contains a valid reference to a FieldInfos + //Post - The instance has been created + + CND_PRECONDITION(!segment.isEmpty(), "segment != NULL"); + + QString buf = Misc::segmentname(segment, QLatin1String(".fdt")); + fieldsStream = d->openInput(buf); + + buf = Misc::segmentname(segment, QLatin1String(".fdx")); + indexStream = d->openInput(buf); + + _size = (int32_t)indexStream->length() / 8; +} + +FieldsReader::~FieldsReader() +{ + //Func - Destructor + //Pre - true + //Post - The instance has been destroyed + close(); +} + +void FieldsReader::close() +{ + //Func - Closes the FieldsReader + //Pre - true + //Post - The FieldsReader has been closed + if (fieldsStream) { + fieldsStream->close(); + _CLDELETE(fieldsStream); + } + + if(indexStream) { + indexStream->close(); + _CLDELETE(indexStream); + } +} + +int32_t FieldsReader::size() const +{ + return _size; +} + +bool FieldsReader::doc(int32_t n, Document* doc) +{ + if ( n * 8L > indexStream->length() ) + return false; + + indexStream->seek(n * 8L); + int64_t position = indexStream->readLong(); + fieldsStream->seek(position); + + int32_t numFields = fieldsStream->readVInt(); + for (int32_t i = 0; i < numFields; i++) { + int32_t fieldNumber = fieldsStream->readVInt(); + FieldInfo* fi = fieldInfos->fieldInfo(fieldNumber); + + if ( fi == NULL ) + _CLTHROWA(CL_ERR_IO, "Field stream is invalid"); + + uint8_t bits = fieldsStream->readByte(); + if ((bits & FieldsWriter::FIELD_IS_BINARY) != 0) { + int32_t fieldLen = fieldsStream->readVInt(); + FieldsReader::FieldsStreamHolder* subStream = new + FieldsReader::FieldsStreamHolder(fieldsStream, fieldLen); + uint8_t bits = Field::STORE_YES; + Field* f = _CLNEW Field( + fi->name, // name + subStream, // read value + bits); + + doc->add(*f); + + //now skip over the rest of the field + if (fieldsStream->getFilePointer() + fieldLen + == fieldsStream->length()) { + // set to eof + fieldsStream->seek(fieldsStream->getFilePointer() + fieldLen - 1); + fieldsStream->readByte(); + } else { + fieldsStream->seek(fieldsStream->getFilePointer() + fieldLen); + } + } else { + uint8_t bits = Field::STORE_YES; + if (fi->isIndexed && (bits & FieldsWriter::FIELD_IS_TOKENIZED)!=0 ) + bits |= Field::INDEX_TOKENIZED; + else if (fi->isIndexed && (bits & FieldsWriter::FIELD_IS_TOKENIZED) == 0) + bits |= Field::INDEX_UNTOKENIZED; + else + bits |= Field::INDEX_NO; + + if (fi->storeTermVector) { + if (fi->storeOffsetWithTermVector) { + if (fi->storePositionWithTermVector) { + bits |= Field::TERMVECTOR_WITH_OFFSETS; + bits |= Field::TERMVECTOR_WITH_POSITIONS; + } else { + bits |= Field::TERMVECTOR_WITH_OFFSETS; + } + } else if (fi->storePositionWithTermVector) { + bits |= Field::TERMVECTOR_WITH_POSITIONS; + } else { + bits |= Field::TERMVECTOR_YES; + } + } else { + bits |= Field::TERMVECTOR_NO; + } + + if ( (bits & FieldsWriter::FIELD_IS_COMPRESSED) != 0 ) { + bits |= Field::STORE_COMPRESS; + int32_t fieldLen = fieldsStream->readVInt(); + FieldsStreamHolder* subStream = new + FieldsStreamHolder(fieldsStream, fieldLen); + + // TODO: we dont have gzip inputstream available, must alert + // user to somehow use a gzip inputstream + Field* f = _CLNEW Field( + fi->name, // name + subStream, // read value + bits); + + f->setOmitNorms(fi->omitNorms); + doc->add(*f); + + // now skip over the rest of the field + if (fieldsStream->getFilePointer() + fieldLen + == fieldsStream->length()) { + //set to eof + fieldsStream->seek(fieldsStream->getFilePointer() + fieldLen - 1); + fieldsStream->readByte(); + } else { + fieldsStream->seek(fieldsStream->getFilePointer() + fieldLen); + } + } else { + TCHAR* fvalue = fieldsStream->readString(true); + Field* f = _CLNEW Field( + fi->name, // name + fvalue, // read value + bits); + // TODO: could optimise this + _CLDELETE_CARRAY(fvalue); + f->setOmitNorms(fi->omitNorms); + doc->add(*f); + } + } + } + return true; +} + +FieldsReader::FieldsStreamHolder::FieldsStreamHolder(IndexInput* indexInput, + int32_t subLength) +{ + this->indexInput = indexInput->clone(); + this->indexInputStream = new IndexInputStream(this->indexInput); + this->subStream = new jstreams::SubInputStream(indexInputStream, + subLength); + + this->size = subStream->getSize(); + this->position = subStream->getPosition(); + this->error = subStream->getError(); + this->status = subStream->getStatus(); +} + +FieldsReader::FieldsStreamHolder::~FieldsStreamHolder() +{ + delete subStream; + delete indexInputStream; + + indexInput->close(); + _CLDELETE(indexInput); +} + +int32_t FieldsReader::FieldsStreamHolder::read(const char*& start, int32_t _min, + int32_t _max) +{ + int32_t ret = subStream->read(start,_min,_max); + this->position = subStream->getPosition(); + this->error = subStream->getError(); + this->status = subStream->getStatus(); + return ret; +} + +int64_t FieldsReader::FieldsStreamHolder::skip(int64_t ntoskip) +{ + int64_t ret = subStream->skip(ntoskip); + this->position = subStream->getPosition(); + this->error = subStream->getError(); + this->status = subStream->getStatus(); + return ret; +} + +int64_t FieldsReader::FieldsStreamHolder::reset(int64_t pos) +{ + int64_t ret = subStream->reset(pos); + this->position = subStream->getPosition(); + this->error = subStream->getError(); + this->status = subStream->getStatus(); + return ret; +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/FieldsReader.h b/3rdparty/clucene/src/CLucene/index/FieldsReader.h new file mode 100644 index 000000000..53589a5cc --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/FieldsReader.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#ifndef _lucene_index_FieldsReader_ +#define _lucene_index_FieldsReader_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include + +#include "CLucene/store/Directory.h" +#include "CLucene/document/Document.h" +#include "CLucene/util/subinputstream.h" +#include "CLucene/store/IndexInput.h" + +CL_NS_DEF(index) + +class FieldInfos; + +class FieldsReader : LUCENE_BASE +{ +private: + const FieldInfos* fieldInfos; + CL_NS(store)::IndexInput* fieldsStream; + CL_NS(store)::IndexInput* indexStream; + int32_t _size; + + class FieldsStreamHolder : public jstreams::StreamBase + { + CL_NS(store)::IndexInput* indexInput; + CL_NS(store)::IndexInputStream* indexInputStream; + jstreams::SubInputStream* subStream; + + public: + FieldsStreamHolder(CL_NS(store)::IndexInput* indexInput, int32_t subLength); + ~FieldsStreamHolder(); + int32_t read(const char*& start, int32_t _min, int32_t _max); + int64_t skip(int64_t ntoskip); + int64_t reset(int64_t pos); + }; + +public: + FieldsReader(CL_NS(store)::Directory* d, const QString& segment, FieldInfos* fn); + ~FieldsReader(); + void close(); + int32_t size() const; + // loads the fields from n'th document into doc. returns true on success. + bool doc(int32_t n, CL_NS(document)::Document* doc); +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/index/FieldsWriter.cpp b/3rdparty/clucene/src/CLucene/index/FieldsWriter.cpp new file mode 100644 index 000000000..ceb6735cb --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/FieldsWriter.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#include "CLucene/StdHeader.h" +#include "FieldsWriter.h" + +#include "CLucene/util/VoidMap.h" +#include "CLucene/util/Reader.h" +#include "CLucene/util/Misc.h" +#include "CLucene/store/Directory.h" +#include "CLucene/store/IndexOutput.h" +#include "CLucene/document/Document.h" +#include "CLucene/document/Field.h" +#include "FieldInfos.h" + +CL_NS_USE(store) +CL_NS_USE(util) +CL_NS_USE(document) +CL_NS_DEF(index) + +FieldsWriter::FieldsWriter(Directory* d, const QString& segment, FieldInfos* fn) + : fieldInfos(fn) +{ + //Func - Constructor + //Pre - d contains a valid reference to a directory + // segment != NULL and contains the name of the segment + //Post - fn contains a valid reference toa a FieldInfos + + CND_PRECONDITION(!segment.isEmpty(), "segment is NULL"); + + QString buf = Misc::segmentname(segment, QLatin1String(".fdt")); + fieldsStream = d->createOutput(buf); + + buf = Misc::segmentname(segment, QLatin1String(".fdx")); + indexStream = d->createOutput(buf); + + CND_CONDITION(indexStream != NULL, "indexStream is NULL"); +} + +FieldsWriter::~FieldsWriter() +{ + //Func - Destructor + //Pre - true + //Post - Instance has been destroyed + + close(); +} + +void FieldsWriter::close() +{ + //Func - Closes all streams and frees all resources + //Pre - true + //Post - All streams have been closed all resources have been freed + + //Check if fieldsStream is valid + if (fieldsStream) { + //Close fieldsStream + fieldsStream->close(); + _CLDELETE(fieldsStream); + } + + //Check if indexStream is valid + if (indexStream) { + //Close indexStream + indexStream->close(); + _CLDELETE(indexStream); + } +} + +void FieldsWriter::addDocument(Document* doc) +{ + //Func - Adds a document + //Pre - doc contains a valid reference to a Document + // indexStream != NULL + // fieldsStream != NULL + //Post - The document doc has been added + + CND_PRECONDITION(indexStream != NULL, "indexStream is NULL"); + CND_PRECONDITION(fieldsStream != NULL, "fieldsStream is NULL"); + + indexStream->writeLong(fieldsStream->getFilePointer()); + + int32_t storedCount = 0; + DocumentFieldEnumeration* fields = doc->fields(); + while (fields->hasMoreElements()) { + Field* field = fields->nextElement(); + if (field->isStored()) + storedCount++; + } + _CLDELETE(fields); + fieldsStream->writeVInt(storedCount); + + fields = doc->fields(); + while (fields->hasMoreElements()) { + Field* field = fields->nextElement(); + if (field->isStored()) { + fieldsStream->writeVInt(fieldInfos->fieldNumber(field->name())); + + uint8_t bits = 0; + if (field->isTokenized()) + bits |= FieldsWriter::FIELD_IS_TOKENIZED; + if (field->isBinary()) + bits |= FieldsWriter::FIELD_IS_BINARY; + if (field->isCompressed()) + bits |= FieldsWriter::FIELD_IS_COMPRESSED; + + fieldsStream->writeByte(bits); + + if ( field->isCompressed()) { + _CLTHROWA(CL_ERR_Runtime, + "CLucene does not directly support compressed fields. " + "Write a compressed byte array instead"); + } else { + // FEATURE: this problem in Java Lucene too, if using Reader, + // data is not stored. + // + // TODO: this is a logic bug... + // if the field is stored, and indexed, and is using a reader + // the field wont get indexed + // + // if we could write zero prefixed vints (therefore static + // length), then we could write a reader directly to the field + // indexoutput and then go back and write the data length. + // however this is not supported in lucene yet... + // if this is ever implemented, then it would make sense to + // also be able to combine the FieldsWriter and + // DocumentWriter::invertDocument process, and use a + // streamfilter to write the field data while the documentwrite + // analyses the document! how cool would that be! it would cut + // out all these buffers!!! + + // compression is disabled for the current field + if (field->isBinary()) { + // TODO: since we currently don't support static length vints, + // we have to read the entire stream into memory first.... ugly! + jstreams::StreamBase* stream = field->streamValue(); + const char* sd; + // how do we make sure we read the entire index in now??? + // TODO: we need to have a max amount, and guarantee its all + // in or throw an error... + int32_t rl = stream->read(sd,10000000,0); + + if ( rl < 0 ) { + // TODO: could we detect this earlier and not actually + // write the field?? + fieldsStream->writeVInt(0); + } else { + // TODO: if this int could be written with a constant + // length, then the stream could be read and written a + // bit at a time then the length is re-written at the end. + fieldsStream->writeVInt(rl); + fieldsStream->writeBytes((uint8_t*)sd, rl); + } + } else if (field->stringValue() == NULL ) { + // we must be using readerValue + CND_PRECONDITION(!field->isIndexed(), + "Cannot store reader if it is indexed too") + Reader* r = field->readerValue(); + + //read the entire string + const TCHAR* rv; + int64_t rl = r->read(rv, LUCENE_INT32_MAX_SHOULDBE); + if ( rl > LUCENE_INT32_MAX_SHOULDBE ) + _CLTHROWA(CL_ERR_Runtime, "Field length too long"); + else if ( rl < 0 ) + rl = 0; + + fieldsStream->writeString( rv, (int32_t)rl); + } else if (field->stringValue() != NULL ) { + fieldsStream->writeString(field->stringValue(), + _tcslen(field->stringValue())); + } else { + _CLTHROWA(CL_ERR_Runtime, "No values are set for the field"); + } + } + } + } + _CLDELETE(fields); +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/FieldsWriter.h b/3rdparty/clucene/src/CLucene/index/FieldsWriter.h new file mode 100644 index 000000000..7dde5f225 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/FieldsWriter.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#ifndef _lucene_index_FieldsWriter_ +#define _lucene_index_FieldsWriter_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include + +#include "CLucene/document/Document.h" +#include "CLucene/store/Directory.h" +#include "CLucene/store/IndexOutput.h" + +CL_NS_DEF(index) + +class FieldInfos; + +class FieldsWriter : LUCENE_BASE +{ +private: + FieldInfos* fieldInfos; + + CL_NS(store)::IndexOutput* fieldsStream; + CL_NS(store)::IndexOutput* indexStream; + +public: + LUCENE_STATIC_CONSTANT(uint8_t, FIELD_IS_TOKENIZED = 0x1); + LUCENE_STATIC_CONSTANT(uint8_t, FIELD_IS_BINARY = 0x2); + LUCENE_STATIC_CONSTANT(uint8_t, FIELD_IS_COMPRESSED = 0x4); + + FieldsWriter(CL_NS(store)::Directory* d, const QString& segment, FieldInfos* fn); + ~FieldsWriter(); + + void close(); + + void addDocument(CL_NS(document)::Document* doc); +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/index/IndexModifier.cpp b/3rdparty/clucene/src/CLucene/index/IndexModifier.cpp new file mode 100644 index 000000000..1423cc7a8 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/IndexModifier.cpp @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#include "CLucene/StdHeader.h" +#include "IndexModifier.h" + +#include "Term.h" +#include "IndexWriter.h" +#include "IndexReader.h" + +CL_NS_DEF(index) +CL_NS_USE(util) +CL_NS_USE(store) +CL_NS_USE(analysis) +CL_NS_USE(document) + +IndexModifier::IndexModifier(Directory* directory, Analyzer* analyzer, bool create) { + init(directory, analyzer, create); +} + +IndexModifier::IndexModifier(const QString& dirName, Analyzer* analyzer, bool create) { + Directory* dir = FSDirectory::getDirectory(dirName, create); + init(dir, analyzer, create); +} + +void IndexModifier::init(Directory* directory, Analyzer* analyzer, bool create) { + indexWriter = NULL; + indexReader = NULL; + this->analyzer = analyzer; + open = false; + + useCompoundFile = true; + int32_t maxBufferedDocs = IndexWriter::DEFAULT_MAX_BUFFERED_DOCS; + this->maxFieldLength = IndexWriter::DEFAULT_MAX_FIELD_LENGTH; + int32_t mergeFactor = IndexWriter::DEFAULT_MERGE_FACTOR; + + this->directory = _CL_POINTER(directory); + createIndexReader(); + open = true; +} + +IndexModifier::~IndexModifier(){ + close(); +} + +void IndexModifier::assureOpen() const{ + if (!open) { + _CLTHROWA(CL_ERR_IllegalState,"Index is closed"); + } +} + +void IndexModifier::createIndexWriter() { + if (indexWriter == NULL) { + if (indexReader != NULL) { + indexReader->close(); + _CLDELETE(indexReader); + } + indexWriter = _CLNEW IndexWriter(directory, analyzer, false); + indexWriter->setUseCompoundFile(useCompoundFile); + //indexWriter->setMaxBufferedDocs(maxBufferedDocs); + indexWriter->setMaxFieldLength(maxFieldLength); + //indexWriter->setMergeFactor(mergeFactor); + } +} + +void IndexModifier::createIndexReader() { + if (indexReader == NULL) { + if (indexWriter != NULL) { + indexWriter->close(); + _CLDELETE(indexWriter); + } + indexReader = IndexReader::open(directory); + } +} + +void IndexModifier::flush() { + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + assureOpen(); + if (indexWriter != NULL) { + indexWriter->close(); + _CLDELETE(indexWriter); + createIndexWriter(); + } else { + indexReader->close(); + _CLDELETE(indexReader); + createIndexReader(); + } +} + +void IndexModifier::addDocument(Document* doc, Analyzer* docAnalyzer) { + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + assureOpen(); + createIndexWriter(); + if (docAnalyzer != NULL) + indexWriter->addDocument(doc, docAnalyzer); + else + indexWriter->addDocument(doc); +} + +int32_t IndexModifier::deleteDocuments(Term* term) { + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + assureOpen(); + createIndexReader(); + return indexReader->deleteDocuments(term); +} + +void IndexModifier::deleteDocument(int32_t docNum) { + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + assureOpen(); + createIndexReader(); + indexReader->deleteDocument(docNum); +} + +int32_t IndexModifier::docCount() { + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + assureOpen(); + if (indexWriter != NULL) + return indexWriter->docCount(); + else + return indexReader->numDocs(); +} + +void IndexModifier::optimize() { + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + assureOpen(); + createIndexWriter(); + indexWriter->optimize(); +} + +void IndexModifier::setUseCompoundFile(bool useCompoundFile) { + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + assureOpen(); + if (indexWriter != NULL) + indexWriter->setUseCompoundFile(useCompoundFile); + this->useCompoundFile = useCompoundFile; +} + +bool IndexModifier::getUseCompoundFile() { + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + assureOpen(); + createIndexWriter(); + return indexWriter->getUseCompoundFile(); +} + +void IndexModifier::setMaxFieldLength(int32_t maxFieldLength) { + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + assureOpen(); + if (indexWriter != NULL) + indexWriter->setMaxFieldLength(maxFieldLength); + this->maxFieldLength = maxFieldLength; +} + +int32_t IndexModifier::getMaxFieldLength() { + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + assureOpen(); + createIndexWriter(); + return indexWriter->getMaxFieldLength(); +} + +void IndexModifier::setMaxBufferedDocs(int32_t maxBufferedDocs) { + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + assureOpen(); + if (indexWriter != NULL) + indexWriter->setMaxBufferedDocs(maxBufferedDocs); + this->maxBufferedDocs = maxBufferedDocs; +} + +int32_t IndexModifier::getMaxBufferedDocs() { + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + assureOpen(); + createIndexWriter(); + return indexWriter->getMaxBufferedDocs(); +} +void IndexModifier::setMergeFactor(int32_t mergeFactor) { + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + assureOpen(); + if (indexWriter != NULL) + indexWriter->setMergeFactor(mergeFactor); + this->mergeFactor = mergeFactor; +} + +int32_t IndexModifier::getMergeFactor() { + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + assureOpen(); + createIndexWriter(); + return indexWriter->getMergeFactor(); +} + +void IndexModifier::close() { + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + if (indexWriter != NULL) { + indexWriter->close(); + _CLDELETE(indexWriter); + } else { + indexReader->close(); + _CLDELETE(indexReader); + } + _CLDECDELETE(directory) + open = false; +} + +QString IndexModifier::toString() const +{ + QString ret(QLatin1String("Index@")); + return ret.append(directory->toString()); +} + + + +int64_t IndexModifier::getCurrentVersion() const{ + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + return IndexReader::getCurrentVersion(directory); +} + +TermDocs* IndexModifier::termDocs(Term* term){ + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + assureOpen(); + createIndexReader(); + return indexReader->termDocs(term); +} + +TermEnum* IndexModifier::terms(Term* term){ + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + assureOpen(); + createIndexReader(); + if ( term != NULL ) + return indexReader->terms(term); + else + return indexReader->terms(); +} + + + CL_NS(document)::Document* IndexModifier::document(const int32_t n){ + Document* ret = _CLNEW Document; + if (!document(n,ret) ) + _CLDELETE(ret); + return ret; + } +bool IndexModifier::document(int32_t n, CL_NS(document)::Document* doc){ + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + assureOpen(); + createIndexReader(); + return indexReader->document(n, doc); +} +CL_NS(store)::Directory* IndexModifier::getDirectory(){ + return directory; +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/IndexModifier.h b/3rdparty/clucene/src/CLucene/index/IndexModifier.h new file mode 100644 index 000000000..4e9963f5a --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/IndexModifier.h @@ -0,0 +1,316 @@ +/* +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +* +* Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#ifndef _lucene_index_IndexModifier_ +#define _lucene_index_IndexModifier_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include + +#include "CLucene/store/Directory.h" +#include "CLucene/document/Document.h" +#include "CLucene/analysis/AnalysisHeader.h" + +CL_NS_DEF(index) + +class IndexReader; +class IndexWriter; +class Term; +class TermDocs; +class TermEnum; + +/** +* A class to modify an index, i.e. to delete and add documents. This +* class hides {@link IndexReader} and {@link IndexWriter} so that you +* do not need to care about implementation details such as that adding +* documents is done via IndexWriter and deletion is done via IndexReader. +* +*

Note that you cannot create more than one IndexModifier object +* on the same directory at the same time. +* +*

Example usage: +* +*

+* +* +* +* +*
+* +* //note this code will leak memory :) +* Analyzer* analyzer = new StandardAnalyzer();
+* // create an index in /tmp/index, overwriting an existing one:
+* IndexModifier* indexModifier = new IndexModifier("/tmp/index", analyzer, true);
+* Document* doc = new Document*();
+* doc->add(*new Field("id", "1", Field::STORE_YES| Field::INDEX_UNTOKENIZED));
+* doc->add(*new Field("body", "a simple test", Field::STORE_YES, Field::INDEX_TOKENIZED));
+* indexModifier->addDocument(doc);
+* int32_t deleted = indexModifier->deleteDocuments(new Term("id", "1"));
+* printf("Deleted %d document", deleted);
+* indexModifier->flush();
+* printf( "$d docs in index", indexModifier->docCount() );
+* indexModifier->close(); +*
+*
+* +*

Not all methods of IndexReader and IndexWriter are offered by this +* class. If you need access to additional methods, either use those classes +* directly or implement your own class that extends IndexModifier. +* +*

Although an instance of this class can be used from more than one +* thread, you will not get the best performance. You might want to use +* IndexReader and IndexWriter directly for that (but you will need to +* care about synchronization yourself then). +* +*

While you can freely mix calls to add() and delete() using this class, +* you should batch you calls for best performance. For example, if you +* want to update 20 documents, you should first delete all those documents, +* then add all the new documents. +* +*/ +class IndexModifier : LUCENE_BASE +{ +protected: + IndexWriter* indexWriter; + IndexReader* indexReader; + + CL_NS(store)::Directory* directory; + CL_NS(analysis)::Analyzer* analyzer; + bool open; + + // Lucene defaults: + bool useCompoundFile; + int32_t maxBufferedDocs; + int32_t maxFieldLength; + int32_t mergeFactor; + +public: + + /** + * Open an index with write access. + * + * @param directory the index directory + * @param analyzer the analyzer to use for adding new documents + * @param create true to create the index or overwrite + * the existing one; false to append to the existing index + */ + IndexModifier(CL_NS(store)::Directory* directory, + CL_NS(analysis)::Analyzer* analyzer, bool create); + + ~IndexModifier(); + + /** + * Open an index with write access. + * + * @param dirName the index directory + * @param analyzer the analyzer to use for adding new documents + * @param create true to create the index or overwrite + * the existing one; false to append to the existing index + */ + IndexModifier(const QString& dirName, CL_NS(analysis)::Analyzer* analyzer, + bool create); + +protected: + + // Initialize an IndexWriter. @throws IOException + void init(CL_NS(store)::Directory* directory, + CL_NS(analysis)::Analyzer* analyzer, bool create); + + // Throw an IllegalStateException if the index is closed. + // @throws IllegalStateException + void assureOpen() const; + + // Close the IndexReader and open an IndexWriter. @throws IOException + void createIndexWriter(); + + // Close the IndexWriter and open an IndexReader. @throws IOException + void createIndexReader(); + +public: + // Make sure all changes are written to disk. @throws IOException + void flush(); + + // Adds a document to this index, using the provided analyzer instead of + // the one specific in the constructor. If the document contains more than + // {@link #setMaxFieldLength(int32_t)} terms for a given field, the + // remainder are discarded. + // @see IndexWriter#addDocument(Document*, Analyzer*) + // @throws IllegalStateException if the index is closed + void addDocument(CL_NS(document)::Document* doc, CL_NS(analysis)::Analyzer* + docAnalyzer = NULL); + + + /** + * Deletes all documents containing term. + * This is useful if one uses a document field to hold a unique ID string for + * the document. Then to delete such a document, one merely constructs a + * term with the appropriate field and the unique ID string as its text and + * passes it to this method. Returns the number of documents deleted. + * @return the number of documents deleted + * @see IndexReader#deleteDocuments(Term*) + * @throws IllegalStateException if the index is closed + */ + int32_t deleteDocuments(Term* term); + + /** + * Deletes the document numbered docNum. + * @see IndexReader#deleteDocument(int32_t) + * @throws IllegalStateException if the index is closed + */ + void deleteDocument(int32_t docNum); + + /** + * Returns the number of documents currently in this index. + * @see IndexWriter#docCount() + * @see IndexReader#numDocs() + * @throws IllegalStateException if the index is closed + */ + int32_t docCount(); + + /** + * Merges all segments together into a single segment, optimizing an index + * for search. + * @see IndexWriter#optimize() + * @throws IllegalStateException if the index is closed + */ + void optimize(); + + /** + * Setting to turn on usage of a compound file. When on, multiple files + * for each segment are merged into a single file once the segment creation + * is finished. This is done regardless of what directory is in use. + * @see IndexWriter#setUseCompoundFile(bool) + * @throws IllegalStateException if the index is closed + */ + void setUseCompoundFile(bool useCompoundFile); + + /** + * @throws IOException + * @see IndexModifier#setUseCompoundFile(bool) + */ + bool getUseCompoundFile(); + + /** + * The maximum number of terms that will be indexed for a single field in a + * document. This limits the amount of memory required for indexing, so that + * collections with very large files will not crash the indexing process by + * running out of memory.

+ * Note that this effectively truncates large documents, excluding from the + * index terms that occur further in the document. If you know your source + * documents are large, be sure to set this value high enough to accomodate + * the expected size. If you set it to Integer.MAX_VALUE, then the only limit + * is your memory, but you should anticipate an OutOfMemoryError.

+ * By default, no more than 10,000 terms will be indexed for a field. + * @see IndexWriter#setMaxFieldLength(int32_t) + * @throws IllegalStateException if the index is closed + */ + void setMaxFieldLength(int32_t maxFieldLength); + + /** + * @throws IOException + * @see IndexModifier#setMaxFieldLength(int32_t) + */ + int32_t getMaxFieldLength(); + + /* + * The maximum number of terms that will be indexed for a single field in a + * document. This limits the amount of memory required for indexing, so that + * collections with very large files will not crash the indexing process by + * running out of memory.

+ * Note that this effectively truncates large documents, excluding from the + * index terms that occur further in the document. If you know your source + * documents are large, be sure to set this value high enough to accomodate + * the expected size. If you set it to Integer.MAX_VALUE, then the only limit + * is your memory, but you should anticipate an OutOfMemoryError.

+ * By default, no more than 10,000 terms will be indexed for a field. + * @see IndexWriter#setMaxBufferedDocs(int32_t) + * @throws IllegalStateException if the index is closed + */ + void setMaxBufferedDocs(int32_t maxBufferedDocs); + + // @see IndexModifier#setMaxBufferedDocs(int32_t) @throws IOException + int32_t getMaxBufferedDocs(); + + /* + * Determines how often segment indices are merged by addDocument(). With + * smaller values, less RAM is used while indexing, and searches on + * unoptimized indices are faster, but indexing speed is slower. With larger + * values, more RAM is used during indexing, and while searches on unoptimized + * indices are slower, indexing is faster. Thus larger values (> 10) are + * best for batch index creation, and smaller values (< 10) for indices + * that are interactively maintained. + *

This must never be less than 2. The default value is 10. + * + * @see IndexWriter#setMergeFactor(int32_t) + * @throws IllegalStateException if the index is closed + */ + void setMergeFactor(int32_t mergeFactor); + + /** + * @throws IOException + * @see IndexModifier#setMergeFactor(int32_t) + */ + int32_t getMergeFactor(); + + /** + * Close this index, writing all pending changes to disk. + * + * @throws IllegalStateException if the index has been closed before already + */ + void close(); + + QString toString() const; + + /** + * Gets the version number of the currently open index. + */ + int64_t getCurrentVersion() const; + + /** + * Returns an enumeration of all the documents which contain term. + * + * Warning: This is not threadsafe. Make sure you lock the modifier object + * while using the TermDocs. If the IndexReader that the modifier manages + * is closed, the TermDocs object will fail. + */ + TermDocs* termDocs(Term* term = NULL); + + /** + * Returns an enumeration of all terms after a given term. + * If no term is given, an enumeration of all the terms + * in the index is returned. + * The enumeration is ordered by Term.compareTo(). Each term + * is greater than all that precede it in the enumeration. + * + * Warning: This is not threadsafe. Make sure you lock the modifier object + * while using the TermDocs. If the IndexReader that the modifier manages + * is closed, the Document will be invalid + */ + TermEnum* terms(Term* term = NULL); + + /** + * Returns the stored fields of the n-th Document in this index. + * + * Warning: This is not threadsafe. Make sure you lock the modifier object + * while using the TermDocs. If the IndexReader that the modifier manages + * is closed, the Document will be invalid + */ + bool document(const int32_t n, CL_NS(document)::Document* doc); + _CL_DEPRECATED(document(i, document)) + CL_NS(document)::Document* document(const int32_t n); + + // Returns the directory used by this index. + CL_NS(store)::Directory* getDirectory(); +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/index/IndexReader.cpp b/3rdparty/clucene/src/CLucene/index/IndexReader.cpp new file mode 100644 index 000000000..91c735632 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/IndexReader.cpp @@ -0,0 +1,668 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +# include +# include + +#include "CLucene/StdHeader.h" +#include "IndexReader.h" +#include "IndexWriter.h" + +#include "CLucene/store/Directory.h" +#include "CLucene/store/FSDirectory.h" +#include "CLucene/store/Lock.h" +#include "CLucene/document/Document.h" +#include "CLucene/search/Similarity.h" +#include "SegmentInfos.h" +#include "MultiReader.h" +#include "Terms.h" + +CL_NS_USE(util) +CL_NS_USE(store) +CL_NS_DEF(index) + +IndexReader::IndexReader(Directory* dir) + : stale(false) + , hasChanges(false) + , closeDirectory(false) + , directoryOwner(false) + , segmentInfos(NULL) + , directory(_CL_POINTER(dir)) + , writeLock(NULL) +{ +} + +IndexReader::IndexReader(Directory* dir, SegmentInfos* infos, bool close) + : stale(false) + , hasChanges(false) + , closeDirectory(close) + , directoryOwner(true) + , segmentInfos(infos) + , directory(_CL_POINTER(dir)) + , writeLock(NULL) +{ +} + +IndexReader::~IndexReader() +{ + if (writeLock != NULL) { + writeLock->release(); + _CLDELETE(writeLock); + } + _CLDELETE(segmentInfos); + _CLDECDELETE(directory); +} + +IndexReader* IndexReader::open(const QString& path) +{ + //Func - Static method. + // Returns an IndexReader reading the index in an FSDirectory in the named path. + //Pre - path != NULL and contains the path of the index for which an IndexReader must be + // instantiated + // closeDir indicates if the directory needs to be closed + //Post - An IndexReader has been returned that reads tnhe index located at path + + CND_PRECONDITION(!path.isEmpty(), "path is NULL"); + + Directory* dir = FSDirectory::getDirectory(path, false); + IndexReader* reader = open(dir, true); + //because fsdirectory will now have a refcount of 1 more than + //if the reader had been opened with a directory object, + //we need to do a refdec + _CLDECDELETE(dir); + return reader; +} + +IndexReader* IndexReader::open(Directory* directory, bool closeDirectory) +{ + //Func - Static method. + // Returns an IndexReader reading the index in an FSDirectory in the named path. + //Pre - directory represents a directory + // closeDir indicates if the directory needs to be closed + //Post - An IndexReader has been returned that reads the index located at directory + + // in- & inter-process sync + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + + //Instantiate an IndexReader::LockWith which can produce an IndexReader + LuceneLock* lock = directory->makeLock(QLatin1String("commit.lock")); + IndexReader::LockWith with(lock, directory); + + IndexReader* ret = NULL; + try { + //Create an IndexReader reading the index + ret = with.runAndReturn(); + } _CLFINALLY ( + _CLDELETE(lock); + ); + + CND_CONDITION(ret != NULL, "ret is NULL"); + ret->closeDirectory = closeDirectory; + + return ret; +} + +CL_NS(document)::Document* IndexReader::document(const int32_t n) +{ + CL_NS(document)::Document* ret = _CLNEW CL_NS(document)::Document; + if (!document(n, ret)) + _CLDELETE(ret); + return ret; +} + +IndexReader* IndexReader::LockWith::doBody() +{ + //Func - Reads the segmentinfo file and depending on the number of segments found + // it returns a SegmentsReader or a SegmentReader + //Pre - directory != NULL + //Post - Depending on the number of Segments present in directory this method + // returns an empty SegmentsReader when there are no segments, a SegmentReader when + // directory contains 1 segment and a nonempty SegmentsReader when directory + // contains multiple segements + + CND_PRECONDITION(directory != NULL, "directory is NULL"); + + //Instantiate SegmentInfos + SegmentInfos* infos = _CLNEW SegmentInfos; + try { + //Have SegmentInfos read the segments file in directory + infos->read(directory); + } catch(...) { + //make sure infos is cleaned up + _CLDELETE(infos); + throw; + } + + // If there is at least one segment (if infos.size() >= 1), the last + // SegmentReader object will close the directory when the SegmentReader + // object itself is closed (see SegmentReader::doClose). + // If there are no segments, there will be no "last SegmentReader object" + // to fulfill this responsibility, so we need to explicitly close the + // directory in the segmentsreader.close + + //Count the number segments in the directory + const uint32_t nSegs = infos->size(); + + if (nSegs == 1 ) { + // index is optimized + return _CLNEW SegmentReader(infos, infos->info(0)); + } else { + //Instantiate an array of pointers to SegmentReaders of size nSegs (The number of segments in the index) + IndexReader** readers = NULL; + + if (nSegs > 0){ + uint32_t infosize = infos->size(); + readers = _CL_NEWARRAY(IndexReader*,infosize+1); + for (uint32_t i = 0; i < infosize; ++i) { + //Instantiate a SegementReader responsible for reading the i-th segment and store it in + //the readers array + readers[i] = _CLNEW SegmentReader(infos->info(i)); + } + readers[infosize] = NULL; + } + + //return an instance of SegmentsReader which is a reader that manages all Segments + return _CLNEW MultiReader(directory, infos, readers); + }// end if +} + +uint64_t IndexReader::lastModified(const QString& directory) +{ + //Func - Static method + // Returns the time the index in the named directory was last modified. + //Pre - directory != NULL and contains the path name of the directory to check + //Post - The last modified time of the index has been returned + + CND_PRECONDITION(!directory.isEmpty(), "directory is NULL"); + + return FSDirectory::fileModified(directory, QLatin1String("segments")); +} + +int64_t IndexReader::getCurrentVersion(Directory* directory) +{ + // in- & inter-process sync + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + + int64_t ret = 0; + bool locked = false; + LuceneLock* commitLock = directory->makeLock(IndexWriter::COMMIT_LOCK_NAME); + try { + locked = commitLock->obtain(IndexWriter::COMMIT_LOCK_TIMEOUT); + ret = SegmentInfos::readCurrentVersion(directory); + } _CLFINALLY ( + if (locked) + commitLock->release(); + _CLDELETE(commitLock); + ) + return ret; +} + +int64_t IndexReader::getCurrentVersion(const QString& directory) +{ + Directory* dir = FSDirectory::getDirectory(directory, false); + int64_t version = getCurrentVersion(dir); + dir->close(); + _CLDECDELETE(dir); + return version; +} + +int64_t IndexReader::getVersion() +{ + return segmentInfos->getVersion(); +} + +bool IndexReader::isCurrent() +{ + // in- & inter-process sync + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + + bool ret = false; + bool locked = false; + LuceneLock* commitLock = directory->makeLock(IndexWriter::COMMIT_LOCK_NAME); + try { + locked = commitLock->obtain(IndexWriter::COMMIT_LOCK_TIMEOUT); + ret = SegmentInfos::readCurrentVersion(directory) + == segmentInfos->getVersion(); + } _CLFINALLY( + if (locked) + commitLock->release(); + _CLDELETE(commitLock); + ) + return ret; +} + +uint64_t IndexReader::lastModified(const Directory* directory) +{ + //Func - Static method + // Returns the time the index in this directory was last modified. + //Pre - directory contains a valid reference + //Post - The last modified time of the index has been returned + + return directory->fileModified(QLatin1String("segments")); +} + + +bool IndexReader::indexExists(const QString& directory) +{ + //Func - Static method + // Checks if an index exists in the named directory + //Pre - directory != NULL + //Post - Returns true if an index exists at the specified directory-> + // If the directory does not exist or if there is no index in it. + // false is returned. + + CND_PRECONDITION(!directory.isEmpty(), "directory is NULL"); + return QFile(directory + QLatin1String("/segments")).exists(); +} + + +void IndexReader::setNorm(int32_t doc, const TCHAR* field, uint8_t value) +{ + SCOPED_LOCK_MUTEX(THIS_LOCK) + if(directoryOwner) + aquireWriteLock(); + doSetNorm(doc, field, value); + hasChanges = true; +} + +void IndexReader::aquireWriteLock() +{ + if (stale) { + _CLTHROWA(CL_ERR_IO, + "IndexReader out of date and no longer valid for delete, " + "undelete, or setNorm operations"); + } + + if (writeLock == NULL) { + LuceneLock* writeLock = directory->makeLock(QLatin1String("write.lock")); + if (!writeLock->obtain(IndexWriter::WRITE_LOCK_TIMEOUT)) // obtain write lock + _CLTHROWA(CL_ERR_IO,"Index locked for write"); // + writeLock + this->writeLock = writeLock; + + // we have to check whether index has changed since this reader was opened. + // if so, this reader is no longer valid for deletion + if (SegmentInfos::readCurrentVersion(directory) > segmentInfos->getVersion()) { + stale = true; + this->writeLock->release(); + _CLDELETE(this->writeLock); + _CLTHROWA(CL_ERR_IO,"IndexReader out of date and no longer valid " + "for delete, undelete, or setNorm operations"); + } + } +} + + +void IndexReader::setNorm(int32_t doc, const TCHAR* field, qreal value) +{ + setNorm(doc, field, CL_NS(search)::Similarity::encodeNorm(value)); +} + +bool IndexReader::indexExists(const Directory* directory) +{ + //Func - Static method + // Checks if an index exists in the directory + //Pre - directory is a valid reference + //Post - Returns true if an index exists at the specified directory-> + // If the directory does not exist or if there is no index in it. + // false is returned. + + return directory->fileExists(QLatin1String("segments")); +} + +TermDocs* IndexReader::termDocs(Term* term) const +{ + //Func - Returns an enumeration of all the documents which contain + // term. For each document, the document number, the frequency of + // the term in that document is also provided, for use in search scoring. + // Thus, this method implements the mapping: + // + // Term => * + // The enumeration is ordered by document number. Each document number + // is greater than all that precede it in the enumeration. + //Pre - term != NULL + //Post - A reference to TermDocs containing an enumeration of all found documents + // has been returned + + CND_PRECONDITION(term != NULL, "term is NULL"); + + //Reference an instantiated TermDocs instance + TermDocs* _termDocs = termDocs(); + //Seek all documents containing term + _termDocs->seek(term); + //return the enumaration + return _termDocs; +} + +TermPositions* IndexReader::termPositions(Term* term) const +{ + //Func - Returns an enumeration of all the documents which contain term. For each + // document, in addition to the document number and frequency of the term in + // that document, a list of all of the ordinal positions of the term in the document + // is available. Thus, this method implements the mapping: + // + // Term => >* + // + // This positional information faciliates phrase and proximity searching. + // The enumeration is ordered by document number. Each document number is greater than + // all that precede it in the enumeration. + //Pre - term != NULL + //Post - A reference to TermPositions containing an enumeration of all found documents + // has been returned + + CND_PRECONDITION(term != NULL, "term is NULL"); + + //Reference an instantiated termPositions instance + TermPositions* _termPositions = termPositions(); + //Seek all documents containing term + _termPositions->seek(term); + //return the enumeration + return _termPositions; +} + +void IndexReader::deleteDocument(const int32_t docNum) +{ + //Func - Deletes the document numbered docNum. Once a document is deleted it will not appear + // in TermDocs or TermPostitions enumerations. Attempts to read its field with the document + // method will result in an error. The presence of this document may still be reflected in + // the docFreq statistic, though this will be corrected eventually as the index is further modified. + //Pre - docNum >= 0 + //Post - If successful the document identified by docNum has been deleted. If no writelock + // could be obtained an exception has been thrown stating that the index was locked or has no write access + + SCOPED_LOCK_MUTEX(THIS_LOCK) + + CND_PRECONDITION(docNum >= 0, "docNum is negative"); + + if (directoryOwner) + aquireWriteLock(); + + //Have the document identified by docNum deleted + doDelete(docNum); + hasChanges = true; +} + +/** +* Commit changes resulting from delete, undeleteAll, or setNorm operations +* +* @throws IOException +*/ +void IndexReader::commit() +{ + SCOPED_LOCK_MUTEX(THIS_LOCK) + if(hasChanges){ + if(directoryOwner){ + { + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) // in- & inter-process sync + + LuceneLock* commitLock = directory->makeLock(QLatin1String("commit.lock")); + IndexReader::CommitLockWith cl(commitLock,this); + cl.run(); + _CLDELETE(commitLock); + + } + if (writeLock != NULL) { + writeLock->release(); // release write lock + _CLDELETE(writeLock); + } + }else + doCommit(); + } + hasChanges = false; +} + + +void IndexReader::undeleteAll() +{ + SCOPED_LOCK_MUTEX(THIS_LOCK) + if(directoryOwner) + aquireWriteLock(); + doUndeleteAll(); + hasChanges = true; +} + +int32_t IndexReader::deleteDocuments(Term* term) +{ + //Func - Deletes all documents containing term. This is useful if one uses a + // document field to hold a unique ID string for the document. Then to delete such + // a document, one merely constructs a term with the appropriate field and the unique + // ID string as its text and passes it to this method. + //Pre - term != NULL + //Post - All documents containing term have been deleted. The number of deleted documents + // has been returned + + CND_PRECONDITION(term != NULL, "term is NULL"); + + //Search for the documents contain term + TermDocs* docs = termDocs(term); + + //Check if documents have been found + if ( docs == NULL ){ + return 0; + } + + //initialize + int32_t Counter = 0; + try { + //iterate through the found documents + while (docs->next()) { + //Delete the document + deleteDocument(docs->doc()); + ++Counter; + } + }_CLFINALLY( + //Close the enumeration + docs->close(); + ); + + //Delete the enumeration of found documents + _CLDELETE( docs ); + + //Return the number of deleted documents + return Counter; +} + +TCHAR** IndexReader::getFieldNames() +{ + CL_NS(util)::StringArrayWithDeletor array; + getFieldNames(IndexReader::ALL, array); + + array.setDoDelete(false); + TCHAR** ret = _CL_NEWARRAY(TCHAR*,array.size()+1); + int j=0; + CL_NS(util)::StringArrayWithDeletor::iterator itr = array.begin(); + while ( itr != array.end() ){ + ret[j]=*itr; + ++j;++itr; + } + ret[j]=NULL; + return ret; +} + +TCHAR** IndexReader::getFieldNames(bool indexed) +{ + CL_NS(util)::StringArrayWithDeletor array; + getFieldNames(indexed?IndexReader::INDEXED:IndexReader::UNINDEXED, array); + + array.setDoDelete(false); + TCHAR** ret = _CL_NEWARRAY(TCHAR*,array.size()+1); + int j=0; + CL_NS(util)::StringArrayWithDeletor::iterator itr = array.begin(); + while ( itr != array.end() ){ + ret[j]=*itr; + ++j;++itr; + } + ret[j]=NULL; + return ret; +} + +void IndexReader::close() +{ + //Func - Closes files associated with this index and also saves any new deletions to disk. + // No other methods should be called after this has been called. + //Pre - true + //Post - All files associated with this index have been deleted and new deletions have been + // saved to disk + SCOPED_LOCK_MUTEX(THIS_LOCK) + + CloseCallbackMap::iterator iter; + for (iter = closeCallbacks.begin(); iter != closeCallbacks.end(); iter++) { + CloseCallback callback = *iter->first; + callback(this, iter->second); + } + + commit(); + doClose(); + + if(closeDirectory) { + directory->close(); + _CLDECDELETE(directory); + } +} + +bool IndexReader::isLocked(Directory* directory) +{ + //Func - Static method + // Checks if the index in the directory is currently locked. + //Pre - directory is a valid reference to a directory to check for a lock + //Post - Returns true if the index in the named directory is locked otherwise false + + //Check the existence of the file write.lock and return true when it does and false + //when it doesn't + LuceneLock* l1 = directory->makeLock(QLatin1String("write.lock")); + LuceneLock* l2 = directory->makeLock(QLatin1String("commit.lock")); + + bool ret = l1->isLocked() || l2->isLocked(); + + _CLDELETE(l1); + _CLDELETE(l2); + return ret; +} + +bool IndexReader::isLocked(const QString& directory) +{ + //Func - Static method + // Checks if the index in the named directory is currently locked. + //Pre - directory != NULL and contains the directory to check for a lock + //Post - Returns true if the index in the named directory is locked otherwise false + + CND_PRECONDITION(!directory.isEmpty(), "directory is NULL"); + + Directory* dir = FSDirectory::getDirectory(directory, false); + bool ret = isLocked(dir); + dir->close(); + _CLDECDELETE(dir); + + return ret; +} + +/** Returns true if there are norms stored for this field. */ +bool IndexReader::hasNorms(const TCHAR* field) +{ + // backward compatible implementation. + // SegmentReader has an efficient implementation. + return norms(field) != NULL; +} + +void IndexReader::unlock(const QString& path) +{ + FSDirectory* dir = FSDirectory::getDirectory(path, false); + unlock(dir); + dir->close(); + _CLDECDELETE(dir); +} + +void IndexReader::unlock(Directory* directory) +{ + //Func - Static method + // Forcibly unlocks the index in the named directory-> + // Caution: this should only be used by failure recovery code, + // when it is known that no other process nor thread is in fact + // currently accessing this index. + //Pre - directory is a valid reference to a directory + //Post - The directory has been forcibly unlocked + LuceneLock* lock; + + lock = directory->makeLock(QLatin1String("write.lock")); + lock->release(); + _CLDELETE(lock); + + lock = directory->makeLock(QLatin1String("commit.lock")); + lock->release(); + _CLDELETE(lock); +} + +bool IndexReader::isLuceneFile(const QString& filename) +{ + if (filename.isNull() || filename.isEmpty()) + return false; + + size_t len = filename.length(); + if (len < 6) //need at least x.frx + return false; + + if (filename == QLatin1String("segments")) + return true; + + if (filename == QLatin1String("segments.new")) + return true; + + if (filename == QLatin1String("deletable")) + return true; + + QStringList extList; + extList << QLatin1String(".cfs") + << QLatin1String(".fnm") << QLatin1String(".fdx") << QLatin1String(".fdt") + << QLatin1String(".tii") << QLatin1String(".tis") << QLatin1String(".frq") + << QLatin1String(".prx") << QLatin1String(".del") << QLatin1String(".tvx") + << QLatin1String(".tvd") << QLatin1String(".tvf") << QLatin1String(".tvp"); + + QString suffix = filename.right(4); + if (extList.contains(suffix, Qt::CaseInsensitive)) + return true; + + if (suffix.leftRef(2) == QLatin1String(".f")) { + suffix = suffix.remove(0, 2); + if (suffix.length() > 0) { + for (int i = 0; i < suffix.length(); ++i) { + if (!suffix.at(i).isDigit()) + return false; + } + return true; + } + } + return false; +} + +void IndexReader::addCloseCallback(CloseCallback callback, void* parameter) +{ + closeCallbacks.put(callback, parameter); +} + +// #pragma mark -- IndexReader::LockWith + +IndexReader::LockWith::LockWith(CL_NS(store)::LuceneLock* lock, CL_NS(store)::Directory* dir) + : CL_NS(store)::LuceneLockWith(lock, IndexWriter::COMMIT_LOCK_TIMEOUT) +{ + this->directory = dir; +} + +// #pragma mark -- IndexReader::CommitLockWith + +IndexReader::CommitLockWith::CommitLockWith(CL_NS(store)::LuceneLock* lock, IndexReader* r) + : CL_NS(store)::LuceneLockWith(lock,IndexWriter::COMMIT_LOCK_TIMEOUT) + , reader(r) +{ +} + +void IndexReader::CommitLockWith::doBody() +{ + reader->doCommit(); + reader->segmentInfos->write(reader->getDirectory()); +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/IndexReader.h b/3rdparty/clucene/src/CLucene/index/IndexReader.h new file mode 100644 index 000000000..352d16e80 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/IndexReader.h @@ -0,0 +1,485 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#ifndef _lucene_index_IndexReader_ +#define _lucene_index_IndexReader_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include + +#include "CLucene/store/Directory.h" +#include "CLucene/store/FSDirectory.h" +#include "CLucene/store/Lock.h" +#include "CLucene/document/Document.h" +#include "CLucene/index/TermVector.h" +#include "SegmentInfos.h" +#include "Terms.h" + + +CL_NS_DEF(index) + + +/** IndexReader is an abstract class, providing an interface for accessing an + index. Search of an index is done entirely through this abstract interface, + so that any subclass which implements it is searchable. + +

Concrete subclasses of IndexReader are usually constructed with a call to + one of the static open() methods, e.g. {@link #open(String)}. + +

For efficiency, in this API documents are often referred to via + document numbers, non-negative integers which each name a unique + document in the index. These document numbers are ephemeral--they may change + as documents are added to and deleted from an index. Clients should thus not + rely on a given document having the same number between sessions. + +

An IndexReader can be opened on a directory for which an IndexWriter is + opened already, but it cannot be used to delete documents from the index then. +*/ +class IndexReader : LUCENE_BASE +{ +public: + //Callback for classes that need to know if IndexReader is closing. + typedef void (*CloseCallback)(IndexReader*, void*); + + class CloseCallbackCompare:public CL_NS(util)::Compare::_base{ + public: + bool operator()( CloseCallback t1, CloseCallback t2 ) const{ + return t1 > t2; + } + static void doDelete(CloseCallback dummy){ + } + }; + + + enum FieldOption { + // all fields + ALL = 1, + // all indexed fields + INDEXED = 2, + // all fields which are not indexed + UNINDEXED = 4, + // all fields which are indexed with termvectors enables + INDEXED_WITH_TERMVECTOR = 8, + // all fields which are indexed but don't have termvectors enabled + INDEXED_NO_TERMVECTOR = 16, + // all fields where termvectors are enabled. Please note that only standard termvector fields are returned + TERMVECTOR = 32, + // all field with termvectors wiht positions enabled + TERMVECTOR_WITH_POSITION = 64, + // all fields where termvectors with offset position are set + TERMVECTOR_WITH_OFFSET = 128, + // all fields where termvectors with offset and position values set + TERMVECTOR_WITH_POSITION_OFFSET = 256 + }; + + +private: + bool stale; + bool hasChanges; + bool closeDirectory; + bool directoryOwner; + + SegmentInfos* segmentInfos; + CL_NS(store)::Directory* directory; + CL_NS(store)::LuceneLock* writeLock; + + typedef CL_NS(util)::CLSet CloseCallbackMap; + CloseCallbackMap closeCallbacks; + + /** Internal use. Implements commit */ + virtual void doCommit() = 0; + + /** + * Tries to acquire the WriteLock on this directory. + * this method is only valid if this IndexReader is directory owner. + * + * @throws IOException If WriteLock cannot be acquired. + */ + void aquireWriteLock(); +protected: + /** + * Constructor used if IndexReader is not owner of its directory. + * This is used for IndexReaders that are used within other IndexReaders that take care or locking directories. + * + * @param directory Directory where IndexReader files reside. + */ + IndexReader(CL_NS(store)::Directory* dir); + + /** + * Constructor used if IndexReader is owner of its directory. + * If IndexReader is owner of its directory, it locks its directory in case of write operations. + * + * @param directory Directory where IndexReader files reside. + * @param segmentInfos Used for write-l + * @param closeDirectory + */ + IndexReader(CL_NS(store)::Directory* directory, SegmentInfos* segmentInfos, bool closeDirectory); + + + /// Implements close. + virtual void doClose() = 0; + + /** Implements setNorm in subclass.*/ + virtual void doSetNorm(int32_t doc, const TCHAR* field, uint8_t value) = 0; + + /** Implements actual undeleteAll() in subclass. */ + virtual void doUndeleteAll() = 0; + + + /** Implements deletion of the document numbered docNum. + * Applications should call {@link #deleteDocument(int32_t)} or {@link #deleteDocuments(Term*)}. + */ + virtual void doDelete(const int32_t docNum) = 0; + +public: + + DEFINE_MUTEX(THIS_LOCK) + + ///Do not access this directly, only public so that MultiReader can access it + virtual void commit(); + + + /** Undeletes all documents currently marked as deleted in this index.*/ + void undeleteAll(); + + /** + * Get a list of unique field names that exist in this index and have the specified + * field option information. + * @param fldOption specifies which field option should be available for the returned fields + * @return Collection of Strings indicating the names of the fields. + * @see IndexReader.FieldOption + */ + virtual void getFieldNames(FieldOption fldOption, CL_NS(util)::StringArrayWithDeletor& retarray) = 0; + + _CL_DEPRECATED( getFieldNames(FieldOption, StringArrayWithDeletor&) ) virtual TCHAR** getFieldNames(); + _CL_DEPRECATED( getFieldNames(FieldOption, StringArrayWithDeletor&) ) virtual TCHAR** getFieldNames(bool indexed); + + /** Returns the byte-encoded normalization factor for the named field of + * every document. This is used by the search code to score documents. + * + * The number of bytes returned is the size of the IndexReader->maxDoc() + * MEMORY: The values are cached, so don't delete the returned byte array. + * @see Field#setBoost(qreal) + */ + virtual uint8_t* norms(const TCHAR* field) = 0; + + + /** Reads the byte-encoded normalization factor for the named field of every + * document. This is used by the search code to score documents. + * + * @see Field#setBoost(qreal) + */ + virtual void norms(const TCHAR* field, uint8_t* bytes) = 0; + + /** Expert: Resets the normalization factor for the named field of the named + * document. + * + * @see #norms(TCHAR*) + * @see Similarity#decodeNorm(uint8_t) + */ + void setNorm(int32_t doc, const TCHAR* field, qreal value); + + /** Expert: Resets the normalization factor for the named field of the named + * document. The norm represents the product of the field's {@link + * Field#setBoost(qreal) boost} and its {@link Similarity#lengthNorm(TCHAR*, + * int32_t) length normalization}. Thus, to preserve the length normalization + * values when resetting this, one should base the new value upon the old. + * + * @see #norms(TCHAR*) + * @see Similarity#decodeNorm(uint8_t) + */ + void setNorm(int32_t doc, const TCHAR* field, uint8_t value); + + /// Release the write lock, if needed. + virtual ~IndexReader(); + + /// Returns an IndexReader reading the index in an FSDirectory in the named path. + static IndexReader* open(const QString& path); + + /// Returns an IndexReader reading the index in the given Directory. + static IndexReader* open( CL_NS(store)::Directory* directory, bool closeDirectory=false); + + /** + * Returns the time the index in the named directory was last modified. + * Do not use this to check whether the reader is still up-to-date, use + * {@link #isCurrent()} instead. + */ + static uint64_t lastModified(const QString& directory); + + /** + * Returns the time the index in the named directory was last modified. + * Do not use this to check whether the reader is still up-to-date, use + * {@link #isCurrent()} instead. + */ + static uint64_t lastModified(const CL_NS(store)::Directory* directory); + + + /** + * Reads version number from segments files. The version number is + * initialized with a timestamp and then increased by one for each change of + * the index. + * + * @param directory where the index resides. + * @return version number. + * @throws IOException if segments file cannot be read + */ + static int64_t getCurrentVersion(CL_NS(store)::Directory* directory); + + /** + * Reads version number from segments files. The version number is + * initialized with a timestamp and then increased by one for each change of + * the index. + * + * @param directory where the index resides. + * @return version number. + * @throws IOException if segments file cannot be read + */ + static int64_t getCurrentVersion(const QString& directory); + + /** + * Version number when this IndexReader was opened. + */ + int64_t getVersion(); + + /** + * Check whether this IndexReader still works on a current version of the index. + * If this is not the case you will need to re-open the IndexReader to + * make sure you see the latest changes made to the index. + * + * @throws IOException + */ + bool isCurrent(); + + + /** + * Return an array of term frequency vectors for the specified document. + * The array contains a vector for each vectorized field in the document. + * Each vector contains terms and frequencies for all terms in a given vectorized field. + * If no such fields existed, the method returns null. The term vectors that are + * returned my either be of type TermFreqVector or of type TermPositionsVector if + * positions or offsets have been stored. + * + * @param docNumber document for which term frequency vectors are returned + * @return array of term frequency vectors. May be null if no term vectors have been + * stored for the specified document. + * @throws IOException if index cannot be accessed + * @see org.apache.lucene.document.Field.TermVector + */ + virtual bool getTermFreqVectors(int32_t docNumber, Array& result) =0; + + /** + * Return a term frequency vector for the specified document and field. The + * returned vector contains terms and frequencies for the terms in + * the specified field of this document, if the field had the storeTermVector + * flag set. If termvectors had been stored with positions or offsets, a + * TermPositionsVector is returned. + * + * @param docNumber document for which the term frequency vector is returned + * @param field field for which the term frequency vector is returned. + * @return term frequency vector May be null if field does not exist in the specified + * document or term vector was not stored. + * @throws IOException if index cannot be accessed + * @see org.apache.lucene.document.Field.TermVector + */ + virtual TermFreqVector* getTermFreqVector(int32_t docNumber, const TCHAR* field) = 0; + + /** + * Returns true if an index exists at the specified directory. + * If the directory does not exist or if there is no index in it. + * @param directory the directory to check for an index + * @return true if an index exists; false otherwise + */ + static bool indexExists(const QString& directory); + + /** + * Returns true if an index exists at the specified directory. + * If the directory does not exist or if there is no index in it. + * @param directory the directory to check for an index + * @return true if an index exists; false otherwise + * @throws IOException if there is a problem with accessing the index + */ + static bool indexExists(const CL_NS(store)::Directory* directory); + + /** Returns the number of documents in this index. */ + virtual int32_t numDocs() = 0; + + /** Returns one greater than the largest possible document number. + * This may be used to, e.g., determine how big to allocate an array which + * will have an element for every document number in an index. + */ + virtual int32_t maxDoc() const = 0; + + /** Gets the stored fields of the nth + * Document in this index. + * The fields are not cleared before retrieving the document, so the + * object should be new or just cleared. + */ + virtual bool document(int32_t n, CL_NS(document)::Document*) =0; + + _CL_DEPRECATED( document(i, document) ) CL_NS(document)::Document* document(const int32_t n); + + /** Returns true if document n has been deleted */ + virtual bool isDeleted(const int32_t n) = 0; + + /** Returns true if any documents have been deleted */ + virtual bool hasDeletions() const = 0; + + /** Returns true if there are norms stored for this field. */ + virtual bool hasNorms(const TCHAR* field); + + /** Returns an enumeration of all the terms in the index. + * The enumeration is ordered by Term.compareTo(). Each term + * is greater than all that precede it in the enumeration. + * @memory Caller must clean up + */ + virtual TermEnum* terms() const =0; + + /** Returns an enumeration of all terms after a given term. + * The enumeration is ordered by Term.compareTo(). Each term + * is greater than all that precede it in the enumeration. + * @memory Caller must clean up + */ + virtual TermEnum* terms(const Term* t) const = 0; + + /** Returns the number of documents containing the term t. */ + virtual int32_t docFreq(const Term* t) const = 0; + + /* Returns an unpositioned TermPositions enumerator. + * @memory Caller must clean up + */ + virtual TermPositions* termPositions() const = 0; + + /** Returns an enumeration of all the documents which contain + * term. For each document, in addition to the document number + * and frequency of the term in that document, a list of all of the ordinal + * positions of the term in the document is available. Thus, this method + * implements the mapping: + * + *

    + * Term    =>    <docNum, freq, + * <pos1, pos2, ... + * posfreq-1> + * >* + *
+ *

This positional information faciliates phrase and proximity searching. + *

The enumeration is ordered by document number. Each document number is + * greater than all that precede it in the enumeration. + * @memory Caller must clean up + */ + TermPositions* termPositions(Term* term) const; + + /** Returns an unpositioned {@link TermDocs} enumerator. + * @memory Caller must clean up + */ + virtual TermDocs* termDocs() const = 0; + + /** Returns an enumeration of all the documents which contain + * term. For each document, the document number, the frequency of + * the term in that document is also provided, for use in search scoring. + * Thus, this method implements the mapping: + *

    Term    =>    <docNum, freq>*
+ *

The enumeration is ordered by document number. Each document number + * is greater than all that precede it in the enumeration. + * @memory Caller must clean up + */ + TermDocs* termDocs(Term* term) const; + + /** Deletes the document numbered docNum. Once a document is + * deleted it will not appear in TermDocs or TermPostitions enumerations. + * Attempts to read its field with the {@link #document} + * method will result in an error. The presence of this document may still be + * reflected in the {@link #docFreq} statistic, though + * this will be corrected eventually as the index is further modified. + */ + void deleteDocument(const int32_t docNum); + + ///@deprecated. Use deleteDocument instead. + _CL_DEPRECATED( deleteDocument ) void deleteDoc(const int32_t docNum) + { deleteDocument(docNum); } + + /** Deletes all documents containing term. + * This is useful if one uses a document field to hold a unique ID string for + * the document. Then to delete such a document, one merely constructs a + * term with the appropriate field and the unique ID string as its text and + * passes it to this method. + * See {@link #deleteDocument(int)} for information about when this deletion will + * become effective. + * @return the number of documents deleted + */ + int32_t deleteDocuments(Term* term); + + ///@deprecated. Use deleteDocuments instead. + _CL_DEPRECATED( deleteDocuments ) int32_t deleteTerm(Term* term){ return deleteDocuments(term); } + + /** + * Closes files associated with this index and also saves any new deletions to disk. + * No other methods should be called after this has been called. + */ + void close(); + + ///Checks if the index in the named directory is currently locked. + static bool isLocked(CL_NS(store)::Directory* directory); + + ///Checks if the index in the named directory is currently locked. + static bool isLocked(const QString& directory); + + + ///Forcibly unlocks the index in the named directory. + ///Caution: this should only be used by failure recovery code, + ///when it is known that no other process nor thread is in fact + ///currently accessing this index. + static void unlock(CL_NS(store)::Directory* directory); + static void unlock(const QString& path); + + /** Returns the directory this index resides in. */ + CL_NS(store)::Directory* getDirectory() { return directory; } + + /** Returns true if the file is a lucene filename (based on extension or filename) */ + static bool isLuceneFile(const QString& filename); + + /** + * For classes that need to know when the IndexReader closes (such as caches, etc), + * should pass their callback function to this. + */ + void addCloseCallback(CloseCallback callback, void* parameter); + +protected: + class LockWith : public CL_NS(store)::LuceneLockWith + { + public: + LockWith(CL_NS(store)::LuceneLock* lock, CL_NS(store)::Directory* dir); + + //Reads the segmentinfo file and depending on the number of segments found + //it returns a MultiReader or a SegmentReader + IndexReader* doBody(); + + private: + CL_NS(store)::Directory* directory; + }; + friend class IndexReader::LockWith; + + class CommitLockWith : public CL_NS(store)::LuceneLockWith + { + public: + CommitLockWith(CL_NS(store)::LuceneLock* lock, IndexReader* r); + void doBody(); + + private: + IndexReader* reader; + }; + friend class IndexReader::CommitLockWith; +}; + +CL_NS_END +#endif + + diff --git a/3rdparty/clucene/src/CLucene/index/IndexWriter.cpp b/3rdparty/clucene/src/CLucene/index/IndexWriter.cpp new file mode 100644 index 000000000..5504cf6fa --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/IndexWriter.cpp @@ -0,0 +1,697 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#include "CLucene/StdHeader.h" +#include "IndexWriter.h" + +#include "CLucene/document/Document.h" +#include "CLucene/store/Directory.h" +#include "CLucene/store/Lock.h" +#include "CLucene/util/VoidList.h" +#include "DocumentWriter.h" +#include "SegmentInfos.h" +#include "SegmentMerger.h" + +CL_NS_USE(store) +CL_NS_USE(util) +CL_NS_USE(document) +CL_NS_USE(analysis) +CL_NS_DEF(index) + +const QLatin1String IndexWriter::WRITE_LOCK_NAME("write.lock"); +const QLatin1String IndexWriter::COMMIT_LOCK_NAME("commit.lock"); + +IndexWriter::IndexWriter(const QString& path, Analyzer* a, const bool create, + const bool _closeDir) + : directory(FSDirectory::getDirectory(path, create)) + , analyzer(a) + , segmentInfos(true) + , closeDir(_closeDir) +{ + //Func - Constructor + // Constructs an IndexWriter for the index in path. + //Pre - path != NULL and contains a named directory path + // a holds a valid reference to an analyzer and analyzes the text to + // be indexed create indicates if the indexWriter must create a new + // index located at path or just open it + //Post - If create is true, then a new, empty index has been created in + // path, replacing the index already there, if any. The named + // directory path is owned by this Instance + + CND_PRECONDITION(!path.isEmpty(), "path is NULL"); + + //Continue initializing the instance by _IndexWriter + _IndexWriter(create); +} + +IndexWriter::IndexWriter(Directory* d, Analyzer* a, const bool create, + const bool _closeDir) + : directory(_CL_POINTER(d)) + , analyzer(a) + , segmentInfos(true) + , closeDir(_closeDir) +{ + //Func - Constructor + // Constructs an IndexWriter for the index in path. + //Pre - d contains a valid reference to a directory + // a holds a valid reference to an analyzer and analyzes the text to + // be indexed create indicates if the indexWriter must create a new + // index located at path or just open it + //Post - If create is true, then a new, empty index has been created in + // path, replacing the index already there, if any. The directory d + // is not owned by this Instance + + //Continue initializing the instance by _IndexWriter + _IndexWriter ( create ); +} + +void IndexWriter::_IndexWriter(const bool create) +{ + //Func - Initialises the instances + //Pre - create indicates if the indexWriter must create a new index + // located at path or just open it + + similarity = CL_NS(search)::Similarity::getDefault(); + + useCompoundFile = true; + if ( directory->getDirectoryType() == RAMDirectory::DirectoryType() ) + useCompoundFile = false; + + //Create a ramDirectory + ramDirectory = _CLNEW TransactionalRAMDirectory; + + CND_CONDITION(ramDirectory != NULL, "ramDirectory is NULL"); + + //Initialize the writeLock to + writeLock = NULL; + + //initialise the settings... + maxFieldLength = DEFAULT_MAX_FIELD_LENGTH; + mergeFactor = DEFAULT_MERGE_FACTOR; + maxMergeDocs = DEFAULT_MAX_MERGE_DOCS; + writeLockTimeout = WRITE_LOCK_TIMEOUT; + commitLockTimeout = COMMIT_LOCK_TIMEOUT; + minMergeDocs = DEFAULT_MAX_BUFFERED_DOCS; + termIndexInterval = DEFAULT_TERM_INDEX_INTERVAL; + + //Create a new lock using the name "write.lock" + LuceneLock* newLock = directory->makeLock(IndexWriter::WRITE_LOCK_NAME); + + //Condition check to see if newLock has been allocated properly + CND_CONDITION(newLock != NULL, + "No memory could be allocated for LuceneLock newLock"); + + //Try to obtain a write lock + if (!newLock->obtain(writeLockTimeout)){ + //Write lock could not be obtained so delete it + _CLDELETE(newLock); + //Reset the instance + _finalize(); + //throw an exception because no writelock could be created or obtained + _CLTHROWA(CL_ERR_IO, "Index locked for write or no write access." ); + } + + //The Write Lock has been obtained so save it for later use + this->writeLock = newLock; + + //Create a new lock using the name "commit.lock" + LuceneLock* lock = directory->makeLock(IndexWriter::COMMIT_LOCK_NAME); + + //Condition check to see if lock has been allocated properly + CND_CONDITION(lock != NULL, "No memory could be allocated for LuceneLock lock"); + + LockWith2 with(lock, commitLockTimeout, this, NULL, create); + { + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) // in- & inter-process sync + with.run(); + } + + //Release the commit lock + _CLDELETE(lock); + + isOpen = true; +} + +IndexWriter::~IndexWriter() +{ + //Func - Destructor + //Pre - true + //Post - The instance has been destroyed + close(); + _finalize(); +} + +void IndexWriter::close() +{ + //Func - Flushes all changes to an index, closes all associated files, and + // closes the directory that the index is stored in. + //Pre - closeDir indicates if the directory must be closed or not + //Post - All the changes have been flushed to disk and the write lock has + // been released. The ramDirectory has also been closed. The + // directory has been closed if the reference count of the directory + // reaches zero + + SCOPED_LOCK_MUTEX(THIS_LOCK) + if (isOpen) { + //Flush the Ram Segments + flushRamSegments(); + //Close the ram directory + if (ramDirectory != NULL) { + ramDirectory->close(); + _CLDECDELETE(ramDirectory); + } + + //Check if this instance must close the directory + if (closeDir) + directory->close(); + _CLDECDELETE(directory); + + // release write lock + if (writeLock != NULL) { + writeLock->release(); + _CLDELETE(writeLock); + } + isOpen = false; + } +} + +void IndexWriter::_finalize() +{ + //Func - Releases all the resources of the instance + //Pre - true + //Post - All the releases have been released + + if(writeLock != NULL) { + //release write lock + writeLock->release(); + _CLDELETE( writeLock ); + } + + //Delete the ramDirectory + if (ramDirectory != NULL) { + ramDirectory->close(); + _CLDECDELETE(ramDirectory); + } +} + +int32_t IndexWriter::docCount() +{ + //Func - Counts the number of documents in the index + //Pre - true + //Post - The number of documents have been returned + + SCOPED_LOCK_MUTEX(THIS_LOCK) + + //Initialize count + int32_t count = 0; + + //Iterate through all segmentInfos + for (int32_t i = 0; i < segmentInfos.size(); i++) { + //Get the i-th SegmentInfo + SegmentInfo* si = segmentInfos.info(i); + //Retrieve the number of documents of the segment and add it to count + count += si->docCount; + } + return count; +} + +void IndexWriter::addDocument(Document* doc, Analyzer* analyzer) +{ + //Func - Adds a document to the index + //Pre - doc contains a valid reference to a document + // ramDirectory != NULL + //Post - The document has been added to the index of this IndexWriter + CND_PRECONDITION(ramDirectory != NULL, "ramDirectory is NULL"); + + if (analyzer == NULL) + analyzer = this->analyzer; + + ramDirectory->transStart(); + try { + QString segmentName = newSegmentName(); + CND_CONDITION(!segmentName.isEmpty(), "segmentName is NULL"); + try { + //Create the DocumentWriter using a ramDirectory and analyzer + // supplied by the IndexWriter (this). + DocumentWriter* dw = _CLNEW DocumentWriter(ramDirectory, analyzer, + this ); + CND_CONDITION(dw != NULL, "dw is NULL"); + try { + //Add the client-supplied document to the new segment. + dw->addDocument(segmentName, doc); + } _CLFINALLY ( + _CLDELETE(dw); + ); + + //Create a new SegmentInfo instance about this new segment. + SegmentInfo* si = _CLNEW SegmentInfo(segmentName, 1, ramDirectory); + CND_CONDITION(si != NULL, "Si is NULL"); + { + SCOPED_LOCK_MUTEX(THIS_LOCK) + + //Add the info object for this particular segment to the list + // of all segmentInfos-> + segmentInfos.add(si); + + //Check to see if the segments must be merged + maybeMergeSegments(); + } + } _CLFINALLY() + } catch (...) { + ramDirectory->transAbort(); + throw; +} + ramDirectory->transCommit(); +} + +void IndexWriter::optimize() +{ + //Func - Optimizes the index for which this Instance is responsible + //Pre - true + //Post - + SCOPED_LOCK_MUTEX(THIS_LOCK) + + //Flush the RamSegments to disk + flushRamSegments(); + while (segmentInfos.size() > 1 + || (segmentInfos.size() == 1 + && (SegmentReader::hasDeletions(segmentInfos.info(0)) + || segmentInfos.info(0)->getDir()!=directory + || (useCompoundFile + && (!SegmentReader::usesCompoundFile(segmentInfos.info(0)) + || SegmentReader::hasSeparateNorms(segmentInfos.info(0))))))) { + int32_t minSegment = segmentInfos.size() - mergeFactor; + mergeSegments(minSegment < 0 ? 0 : minSegment); + } +} + + +QString IndexWriter::newSegmentName() +{ + SCOPED_LOCK_MUTEX(THIS_LOCK) + return QLatin1Char('_') + QString::number(segmentInfos.counter++, 36); +} + +void IndexWriter::flushRamSegments() +{ + //Func - Merges all RAM-resident segments. + //Pre - ramDirectory != NULL + //Post - The RAM-resident segments have been merged to disk + + CND_PRECONDITION(ramDirectory != NULL, "ramDirectory is NULL"); + + int32_t minSegment = segmentInfos.size()-1; //don't make this unsigned... + CND_CONDITION(minSegment >= -1, "minSegment must be >= -1"); + + int32_t docCount = 0; + //Iterate through all the segements and check if the directory is a ramDirectory + while (minSegment >= 0 && + segmentInfos.info(minSegment)->getDir() == ramDirectory) { + docCount += segmentInfos.info(minSegment)->docCount; + minSegment--; + } + if (minSegment < 0 || // add one FS segment? + (docCount + segmentInfos.info(minSegment)->docCount) > mergeFactor || + !(segmentInfos.info(segmentInfos.size()-1)->getDir() == ramDirectory)) + minSegment++; + + CND_CONDITION(minSegment >= 0, "minSegment must be >= 0"); + if (minSegment >= segmentInfos.size()) + return; // none to merge + mergeSegments(minSegment); +} + +void IndexWriter::maybeMergeSegments() { + //Func - Incremental Segment Merger + //Pre - + //Post - + + int64_t targetMergeDocs = minMergeDocs; + + // find segments smaller than current target size + while (targetMergeDocs <= maxMergeDocs) { + int32_t minSegment = segmentInfos.size(); + int32_t mergeDocs = 0; + + while (--minSegment >= 0) { + SegmentInfo* si = segmentInfos.info(minSegment); + if (si->docCount >= targetMergeDocs) + break; + mergeDocs += si->docCount; + } + + if (mergeDocs >= targetMergeDocs){ + // found a merge to do + mergeSegments(minSegment+1); + }else + break; + + //increase target size + targetMergeDocs *= mergeFactor; + } +} + +void IndexWriter::mergeSegments(const uint32_t minSegment) +{ + mergeSegments(minSegment, segmentInfos.size()); +} + +void IndexWriter::mergeSegments(const uint32_t minSegment, const uint32_t end) +{ + CLVector segmentsToDelete(false); + QString mergedName = newSegmentName(); +#ifdef _CL_DEBUG_INFO + fprintf(_CL_DEBUG_INFO, "merging segments\n"); +#endif + SegmentMerger merger(this, mergedName); + for (size_t i = minSegment; i < end; i++) { + SegmentInfo* si = segmentInfos.info(i); +#ifdef _CL_DEBUG_INFO + fprintf(_CL_DEBUG_INFO, " %s (%d docs)\n", + si->name.toLocal8Bit().constData(), si->docCount); +#endif + SegmentReader* reader = _CLNEW SegmentReader(si); + merger.add(reader); + // if we own the directory + if ((reader->getDirectory() == this->directory) + || (reader->getDirectory() == this->ramDirectory)) { + // queue segment for deletion + segmentsToDelete.push_back(reader); + } + } + + int32_t mergedDocCount = merger.merge(); + +#ifdef _CL_DEBUG_INFO + fprintf(_CL_DEBUG_INFO, "\n into %s (%d docs)\n", + mergedName.toLocal8Bit().constData(), mergedDocCount); +#endif + + segmentInfos.clearto(minSegment);// remove old infos & add new + segmentInfos.add(_CLNEW SegmentInfo(mergedName, mergedDocCount, directory)); + + // close readers before we attempt to delete now-obsolete segments + merger.closeReaders(); + + LuceneLock* lock = directory->makeLock(IndexWriter::COMMIT_LOCK_NAME); + LockWith2 with (lock, commitLockTimeout, this, &segmentsToDelete, true); + { + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) // in- & inter-process sync + with.run(); + } + _CLDELETE( lock ); + + if (useCompoundFile) { + QStringList filesToDelete; + merger.createCompoundFile(mergedName + QLatin1String(".tmp"), filesToDelete); + + LuceneLock* lock = directory->makeLock(IndexWriter::COMMIT_LOCK_NAME); + LockWithCFS with(lock, commitLockTimeout, directory, this, mergedName, + filesToDelete); + { + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) // in- & inter-process sync + with.run(); + } + _CLDELETE(lock); + } +} + +void IndexWriter::deleteSegments(CLVector* segments) +{ + QStringList deletable; + + {//scope delete deleteArray object + QStringList deleteArray; + readDeleteableFiles(deleteArray); + deleteFiles(deleteArray, deletable); // try to delete deleteable + } + + QStringList files; + for (uint32_t i = 0; i < segments->size(); i++) { + SegmentReader* reader = (*segments)[i]; + files.clear(); + reader->files(files); + if (reader->getDirectory() == this->directory) + deleteFiles(files, deletable); // try to delete our files + else + deleteFiles(files, reader->getDirectory()); // delete, eg, RAM files + } + + writeDeleteableFiles(deletable); // note files we can't delete +} + +void IndexWriter::deleteFiles(const QStringList& files) +{ + QStringList currentDeletable; + readDeleteableFiles(currentDeletable); + + // try to delete deleteable + QStringList deletable; + deleteFiles(currentDeletable, deletable); + + // try to delete our files + deleteFiles(files, deletable); + + // note files we can't delete + writeDeleteableFiles(deletable); +} + +void IndexWriter::readDeleteableFiles(QStringList& result) +{ + if (!directory->fileExists(QLatin1String("deletable"))) + return; + + IndexInput* input = directory->openInput(QLatin1String("deletable")); + try { + // read file names + TCHAR tname[CL_MAX_PATH]; + for (int32_t i = input->readInt(); i > 0; i--) { + int32_t read = input->readString(tname, CL_MAX_PATH); + result.push_back(QString::fromWCharArray(tname, read)); + } + } _CLFINALLY ( + input->close(); + _CLDELETE(input); + ); +} + +void IndexWriter::deleteFiles(const QStringList& files, QStringList& deletable) +{ + QStringList::const_iterator itr; + for (itr = files.begin(); itr != files.end(); ++itr) { + if (!getDirectory()->fileExists((*itr))) + continue; + + if (!getDirectory()->deleteFile((*itr), false)) { + if (directory->fileExists((*itr))) { +#ifdef _CL_DEBUG_INFO + fprintf(_CL_DEBUG_INFO, "%s; Will re-try later.\n", err.what()); +#endif + // add to deletable + deletable.push_back((*itr)); + } + } + } +} + +void IndexWriter::deleteFiles(const QStringList& files, Directory* directory) +{ + QStringList::const_iterator itr; + for (itr = files.begin(); itr != files.end(); ++itr) + directory->deleteFile((*itr), true); +} + +void IndexWriter::writeDeleteableFiles(const QStringList& files) +{ + IndexOutput* output = directory->createOutput(QLatin1String("deleteable.new")); + try { + output->writeInt(files.size()); + + TCHAR tfile[CL_MAX_PATH]; + QStringList::const_iterator itr; + for (itr = files.begin(); itr != files.end(); ++itr) { + tfile[(*itr).toWCharArray(tfile)] = '\0'; + output->writeString(tfile, _tcslen(tfile)); + } + } _CLFINALLY ( + output->close(); + _CLDELETE(output); + ); + + directory->renameFile(QLatin1String("deleteable.new"), + QLatin1String("deletable")); +} + +void IndexWriter::addIndexes(Directory** dirs) +{ + //Func - Add several indexes located in different directories into the current + // one managed by this instance + //Pre - dirs != NULL and contains directories of several indexes + // dirsLength > 0 and contains the number of directories + //Post - The indexes located in the directories in dirs have been merged with + // the pre(current) index. The Resulting index has also been optimized + + SCOPED_LOCK_MUTEX(THIS_LOCK) + + CND_PRECONDITION(dirs != NULL, "dirs is NULL"); + + // start with zero or 1 seg so optimize the current + optimize(); + + int32_t start = segmentInfos.size(); + + //Iterate through the directories + for (int32_t i = 0; dirs[i] != NULL; ++i) { + // DSR: Changed SegmentInfos constructor arg (see bug discussion below). + SegmentInfos sis(false); + sis.read(dirs[i]); + for (int32_t j = 0; j < sis.size(); j++) + segmentInfos.add(sis.info(j)); // add each info + } + + // commented out by tbusch to solve a bug and to be conform with + // java lucene + + // merge newly added segments in log(n) passes + //while (segmentInfos.size() > start + mergeFactor) { + // for (int32_t base = start; base < segmentInfos.size(); base++) { + // int32_t end = min(segmentInfos.size(), base + mergeFactor); + // if (end - base > 1) + // mergeSegments(base, end); + // } + //} + + // cleanup + optimize(); +} + + +void IndexWriter::addIndexes(IndexReader** readers) +{ + SCOPED_LOCK_MUTEX(THIS_LOCK) + optimize(); // start with zero or 1 seg + + QString mergedName = newSegmentName(); + SegmentMerger merger(this, mergedName); + + CLVector segmentsToDelete; + SegmentReader* sReader = NULL; + if (segmentInfos.size() == 1) { // add existing index, if any + sReader = _CLNEW SegmentReader(segmentInfos.info(0)); + merger.add(sReader); + segmentsToDelete.push_back(sReader); // queue segment for deletion + } + + int32_t readersLength = 0; + while (readers[readersLength] != NULL) + merger.add(readers[readersLength++]); + + int32_t docCount = merger.merge(); // merge 'em + + // pop old infos & add new + segmentInfos.clearto(0); + segmentInfos.add(_CLNEW SegmentInfo(mergedName, docCount, directory)); + + if (sReader != NULL) { + sReader->close(); + _CLDELETE(sReader); + } + + LuceneLock* lock = directory->makeLock(IndexWriter::COMMIT_LOCK_NAME); + LockWith2 with(lock, commitLockTimeout, this, &segmentsToDelete, true); + { + // in- & inter-process sync + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + with.run(); + } + _CLDELETE(lock); + + if (useCompoundFile) { + QStringList filesToDelete; + merger.createCompoundFile(mergedName + QLatin1String(".tmp"), + filesToDelete); + + LuceneLock* cfslock = directory->makeLock(IndexWriter::COMMIT_LOCK_NAME); + LockWithCFS with(cfslock, commitLockTimeout, directory, this, mergedName, + filesToDelete); + { + // in- & inter-process sync + SCOPED_LOCK_MUTEX(directory->THIS_LOCK) + with.run(); + } + _CLDELETE(cfslock); + } +} + +// #pragma mark -- IndexWriter::LockWith2 + +IndexWriter::LockWith2::LockWith2(CL_NS(store)::LuceneLock* lock, + int64_t lockWaitTimeout, + IndexWriter* indexWriter, + CL_NS(util)::CLVector* std, + bool _create) + : CL_NS(store)::LuceneLockWith(lock, lockWaitTimeout) + , create(_create) + , writer(indexWriter) + , segmentsToDelete(std) +{ +} + +void IndexWriter::LockWith2::doBody() +{ + //Func - Writes segmentInfos to or reads segmentInfos from disk + //Pre - writer != NULL + //Post - if create is true then segementInfos has been written to disk + // otherwise segmentInfos has been read from disk + + CND_PRECONDITION(writer != NULL, "writer is NULL"); + + if (create) { + writer->segmentInfos.write(writer->getDirectory()); + // delete now-unused segments + if (segmentsToDelete != NULL) + writer->deleteSegments(segmentsToDelete); + } else { + writer->segmentInfos.read(writer->getDirectory()); + } +} + +// #pragma mark -- IndexWriter::LockWithCFS + +IndexWriter::LockWithCFS::LockWithCFS(CL_NS(store)::LuceneLock* lock, + int64_t lockWaitTimeout, + CL_NS(store)::Directory* dir, + IndexWriter* indexWriter, + const QString& segmentName, + const QStringList& ftd) + : CL_NS(store)::LuceneLockWith(lock, lockWaitTimeout) + , segName(segmentName) + , writer(indexWriter) + , directory(dir) + , filesToDelete(ftd) +{ +} + +void IndexWriter::LockWithCFS::doBody() +{ + //Func - Writes segmentInfos to or reads segmentInfos from disk + //Pre - writer != NULL + //Post - if create is true then segementInfos has been written to disk + // otherwise segmentInfos has been read from disk + + CND_PRECONDITION(directory != NULL, "directory is NULL"); + CND_PRECONDITION(!segName.isEmpty(), "mergedName is NULL"); + + // make compound file visible for SegmentReaders + directory->renameFile(segName + QLatin1String(".tmp"), + segName + QLatin1String(".cfs")); + // delete now unused files of segment + writer->deleteFiles(filesToDelete); +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/IndexWriter.h b/3rdparty/clucene/src/CLucene/index/IndexWriter.h new file mode 100644 index 000000000..80476c864 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/IndexWriter.h @@ -0,0 +1,425 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#ifndef _lucene_index_IndexWriter_ +#define _lucene_index_IndexWriter_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include "CLucene/analysis/AnalysisHeader.h" +#include "CLucene/util/VoidList.h" +#include "CLucene/search/Similarity.h" +#include "CLucene/store/Lock.h" +#include "CLucene/store/TransactionalRAMDirectory.h" + +#include "SegmentHeader.h" + +CL_NS_DEF(index) + +/** +An IndexWriter creates and maintains an index. + +The third argument to the +constructor +determines whether a new index is created, or whether an existing index is +opened for the addition of new documents. + +In either case, documents are added with the addDocument method. +When finished adding documents, close should be called. + +

If an index will not have more documents added for a while and optimal search +performance is desired, then the optimize +method should be called before the index is closed. + +

Opening an IndexWriter creates a lock file for the directory in use. Trying to open +another IndexWriter on the same directory will lead to an IOException. The IOException +is also thrown if an IndexReader on the same directory is used to delete documents +from the index. + +@see IndexModifier IndexModifier supports the important methods of IndexWriter plus deletion +*/ +class IndexWriter : LUCENE_BASE +{ + class LockWith2 : public CL_NS(store)::LuceneLockWith + { + public: + LockWith2(CL_NS(store)::LuceneLock* lock, + int64_t lockWaitTimeout, + IndexWriter* wr, + CL_NS(util)::CLVector* std, + bool create); + + ~LockWith2() {} + + void doBody(); + + private: + bool create; + IndexWriter* writer; + CL_NS(util)::CLVector* segmentsToDelete; + }; + friend class LockWith2; + + class LockWithCFS : public CL_NS(store)::LuceneLockWith + { + public: + LockWithCFS(CL_NS(store)::LuceneLock* lock, + int64_t lockWaitTimeout, + CL_NS(store)::Directory* dir, + IndexWriter* wr, + const QString& segName, + const QStringList& ftd); + + ~LockWithCFS() {} + + void doBody(); + + private: + QString segName; + IndexWriter* writer; + CL_NS(store)::Directory* directory; + QStringList filesToDelete; + }; + friend class IndexWriter::LockWithCFS; + + // indicates if the writers is open - this way close can be called multiple + // times + bool isOpen; + + // how to analyze text + CL_NS(analysis)::Analyzer* analyzer; + + CL_NS(search)::Similarity* similarity; // how to normalize + + /** Use compound file setting. Normally defaults to true, except when + * using a RAMDirectory. This minimizes the number of files used. + * Setting this to false may improve indexing performance, but + * may also cause file handle problems. + */ + bool useCompoundFile; + bool closeDir; + + // for temp segs + CL_NS(store)::TransactionalRAMDirectory* ramDirectory; + + CL_NS(store)::LuceneLock* writeLock; + + void _IndexWriter(const bool create); + + void _finalize(); + + // where this index resides + CL_NS(store)::Directory* directory; + + + int32_t getSegmentsCounter() { return segmentInfos.counter; } + int32_t maxFieldLength; + int32_t mergeFactor; + int32_t minMergeDocs; + int32_t maxMergeDocs; + int32_t termIndexInterval; + + int64_t writeLockTimeout; + int64_t commitLockTimeout; +public: + DEFINE_MUTEX(THIS_LOCK) + + // Release the write lock, if needed. + SegmentInfos segmentInfos; + + // Release the write lock, if needed. + ~IndexWriter(); + + /** + * The Java implementation of Lucene silently truncates any tokenized + * field if the number of tokens exceeds a certain threshold. Although + * that threshold is adjustable, it is easy for the client programmer + * to be unaware that such a threshold exists, and to become its + * unwitting victim. + * CLucene implements a less insidious truncation policy. Up to + * DEFAULT_MAX_FIELD_LENGTH tokens, CLucene behaves just as JLucene + * does. If the number of tokens exceeds that threshold without any + * indication of a truncation preference by the client programmer, + * CLucene raises an exception, prompting the client programmer to + * explicitly set a truncation policy by adjusting maxFieldLength. + */ + LUCENE_STATIC_CONSTANT(int32_t, DEFAULT_MAX_FIELD_LENGTH = 10000); + LUCENE_STATIC_CONSTANT(int32_t, FIELD_TRUNC_POLICY__WARN = -1); + int32_t getMaxFieldLength() const{ return maxFieldLength; } + void setMaxFieldLength(int32_t val){ maxFieldLength = val; } + + /** + * Default value is 10. Change using {@link #setMaxBufferedDocs(int)}. + */ + LUCENE_STATIC_CONSTANT(int32_t, DEFAULT_MAX_BUFFERED_DOCS = 10); + /** Determines the minimal number of documents required before the buffered + * in-memory documents are merging and a new Segment is created. + * Since Documents are merged in a {@link RAMDirectory}, + * large value gives faster indexing. At the same time, mergeFactor limits + * the number of files open in a FSDirectory. + * + *

The default value is DEFAULT_MAX_BUFFERED_DOCS.*/ + void setMaxBufferedDocs(int32_t val){ minMergeDocs = val; } + /** + * @see #setMaxBufferedDocs + */ + int32_t getMaxBufferedDocs(){ return minMergeDocs; } + + /** + * Default value for the write lock timeout (1,000). + */ + LUCENE_STATIC_CONSTANT(int64_t, WRITE_LOCK_TIMEOUT = 1000); + /** + * Sets the maximum time to wait for a write lock (in milliseconds). + */ + void setWriteLockTimeout(int64_t writeLockTimeout) + { this->writeLockTimeout = writeLockTimeout; } + /** + * @see #setWriteLockTimeout + */ + int64_t getWriteLockTimeout() { return writeLockTimeout; } + + /** + * Default value for the commit lock timeout (10,000). + */ + LUCENE_STATIC_CONSTANT(int64_t, COMMIT_LOCK_TIMEOUT = 10000); + /** + * Sets the maximum time to wait for a commit lock (in milliseconds). + */ + void setCommitLockTimeout(int64_t commitLockTimeout) + { this->commitLockTimeout = commitLockTimeout; } + /** + * @see #setCommitLockTimeout + */ + int64_t getCommitLockTimeout() { return commitLockTimeout; } + + static const QLatin1String WRITE_LOCK_NAME; //"write.lock"; + static const QLatin1String COMMIT_LOCK_NAME; //"commit.lock"; + + /** + * Default value is 10. Change using {@link #setMergeFactor(int)}. + */ + LUCENE_STATIC_CONSTANT(int32_t, DEFAULT_MERGE_FACTOR = 10); + /* Determines how often segment indices are merged by addDocument(). With + * smaller values, less RAM is used while indexing, and searches on + * unoptimized indices are faster, but indexing speed is slower. With larger + * values more RAM is used while indexing and searches on unoptimized indices + * are slower, but indexing is faster. Thus larger values (> 10) are best + * for batched index creation, and smaller values (< 10) for indices that are + * interactively maintained. + * + *

This must never be less than 2. The default value is 10. + */ + int32_t getMergeFactor() const{ return mergeFactor; } + void setMergeFactor(int32_t val){ mergeFactor = val; } + + + /** Expert: The fraction of terms in the "dictionary" which should be stored + * in RAM. Smaller values use more memory, but make searching slightly + * faster, while larger values use less memory and make searching slightly + * slower. Searching is typically not dominated by dictionary lookup, so + * tweaking this is rarely useful. + */ + LUCENE_STATIC_CONSTANT(int32_t, DEFAULT_TERM_INDEX_INTERVAL = 128); + /** Expert: Set the interval between indexed terms. Large values cause less + * memory to be used by IndexReader, but slow random-access to terms. Small + * values cause more memory to be used by an IndexReader, and speed + * random-access to terms. + * + * This parameter determines the amount of computation required per query + * term, regardless of the number of documents that contain that term. In + * particular, it is the maximum number of other terms that must be + * scanned before a term is located and its frequency and position information + * may be processed. In a large index with user-entered query terms, query + * processing time is likely to be dominated not by term lookup but rather + * by the processing of frequency and positional data. In a small index + * or when many uncommon query terms are generated (e.g., by wildcard + * queries) term lookup may become a dominant cost. + * + * In particular, numUniqueTerms/interval terms are read into + * memory by an IndexReader, and, on average, interval/2 terms + * must be scanned for each random term access. + * + * @see #DEFAULT_TERM_INDEX_INTERVAL + */ + void setTermIndexInterval(int32_t interval) { termIndexInterval = interval; } + /** Expert: Return the interval between indexed terms. + * + * @see #setTermIndexInterval(int) + */ + int32_t getTermIndexInterval() { return termIndexInterval; } + + /** Determines the minimal number of documents required before the buffered + * in-memory documents are merging and a new Segment is created. + * Since Documents are merged in a {@link RAMDirectory}, + * large value gives faster indexing. At the same time, mergeFactor limits + * the number of files open in a FSDirectory. + * + *

The default value is 10.*/ + int32_t getMinMergeDocs() const{ return minMergeDocs; } + void setMinMergeDocs(int32_t val){ minMergeDocs = val; } + + /** Determines the largest number of documents ever merged by addDocument(). + * Small values (e.g., less than 10,000) are best for interactive indexing, + * as this limits the length of pauses while indexing to a few seconds. + * Larger values are best for batched indexing and speedier searches. + * + *

The default value is {@link #DEFAULT_MAX_MERGE_DOCS}. + */ + LUCENE_STATIC_CONSTANT(int32_t, DEFAULT_MAX_MERGE_DOCS = LUCENE_INT32_MAX_SHOULDBE); + /**Determines the largest number of documents ever merged by addDocument(). + * Small values (e.g., less than 10,000) are best for interactive indexing, + * as this limits the length of pauses while indexing to a few seconds. + * Larger values are best for batched indexing and speedier searches. + * + *

The default value is {@link Integer#MAX_VALUE}. + */ + int32_t getMaxMergeDocs() const{ return maxMergeDocs; } + void setMaxMergeDocs(int32_t val){ maxMergeDocs = val; } + + /** + * Constructs an IndexWriter for the index in path. + * Text will be analyzed with a. If create + * is true, then a new, empty index will be created in + * path, replacing the index already there, if any. + * + * @param path the path to the index directory + * @param a the analyzer to use + * @param create true to create the index or overwrite + * the existing one; false to append to the existing + * index + * @throws IOException if the directory cannot be read/written to, or + * if it does not exist, and create is + * false + */ + IndexWriter(const QString& path, CL_NS(analysis)::Analyzer* a, + const bool create, const bool closeDir = true); + + + /**Constructs an IndexWriter for the index in d. Text will be + * analyzed with a. If create is true, then a new, + * empty index will be created in d, replacing the index already + * there, if any. + */ + IndexWriter(CL_NS(store)::Directory* d, CL_NS(analysis)::Analyzer* a, + const bool create, const bool closeDir = false); + + // Flushes all changes to an index, closes all associated files, and closes + // the directory that the index is stored in. + void close(); + + // Returns the number of documents currently in this index. synchronized + int32_t docCount(); + + + // Adds a document to this index, using the provided analyzer instead of + // the value of {@link #getAnalyzer()}. If the document contains more than + // {@link #setMaxFieldLength(int)} terms for a given field, the remainder + // are discarded. + void addDocument(CL_NS(document)::Document* doc, + CL_NS(analysis)::Analyzer* analyzer = NULL); + + + // Merges all segments together into a single segment, optimizing an index + // for search. synchronized + void optimize(); + + + /**Merges all segments from an array of indices into this index. + * + *

This may be used to parallelize batch indexing. A large document + * collection can be broken into sub-collections. Each sub-collection can be + * indexed in parallel, on a different thread, process or machine. The + * complete index can then be created by merging sub-collection indices + * with this method. + * + *

After this completes, the index is optimized. + *@synchronized + */ + void addIndexes(CL_NS(store)::Directory** dirs); + + /** Merges the provided indexes into this index. + *

After this completes, the index is optimized.

+ *

The provided IndexReaders are not closed.

+ */ + void addIndexes(IndexReader** readers); + + + /** Returns the directory this index resides in. */ + CL_NS(store)::Directory* getDirectory() { return directory; } + + /** Get the current setting of whether to use the compound file format. + * Note that this just returns the value you set with setUseCompoundFile(boolean) + * or the default. You cannot use this to query the status of an existing index. + * @see #setUseCompoundFile(boolean) + */ + bool getUseCompoundFile() { return useCompoundFile; } + + /** Setting to turn on usage of a compound file. When on, multiple files + * for each segment are merged into a single file once the segment creation + * is finished. This is done regardless of what directory is in use. + */ + void setUseCompoundFile(bool value) { useCompoundFile = value; } + + + /** Expert: Set the Similarity implementation used by this IndexWriter. + * + * @see Similarity#setDefault(Similarity) + */ + void setSimilarity(CL_NS(search)::Similarity* similarity) + { this->similarity = similarity; } + + /** Expert: Return the Similarity implementation used by this IndexWriter. + * + *

This defaults to the current value of {@link Similarity#getDefault()}. + */ + CL_NS(search)::Similarity* getSimilarity() { return this->similarity; } + + /** Returns the analyzer used by this index. */ + CL_NS(analysis)::Analyzer* getAnalyzer() { return analyzer; } + +private: + /** Merges all RAM-resident segments. */ + void flushRamSegments(); + + /** Incremental segment merger. */ + void maybeMergeSegments(); + + // Pops segments off of segmentInfos stack down to minSegment, merges them, + // and pushes the merged index onto the top of the segmentInfos stack. + void mergeSegments(const uint32_t minSegment); + + // Merges the named range of segments, replacing them in the stack with a + // single segment. + void mergeSegments(const uint32_t minSegment, const uint32_t end); + + // Some operating systems (e.g. Windows) don't permit a file to be deleted + // while it is opened for read (e.g. by another process or thread). So we + // assume that when a delete fails it is because the file is open in another + // process, and queue the file for subsequent deletion. + void deleteSegments(CL_NS(util)::CLVector* segments); + + void deleteFiles(const QStringList& files); + void readDeleteableFiles(QStringList& files); + void deleteFiles(const QStringList& files, QStringList& deletable); + void deleteFiles(const QStringList& files, CL_NS(store)::Directory* directory); + void writeDeleteableFiles(const QStringList& files); + + // synchronized + QString newSegmentName(); +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/index/MultiReader.cpp b/3rdparty/clucene/src/CLucene/index/MultiReader.cpp new file mode 100644 index 000000000..1260d04dc --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/MultiReader.cpp @@ -0,0 +1,722 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "MultiReader.h" + +#include "IndexReader.h" +#include "CLucene/document/Document.h" +#include "Terms.h" +#include "SegmentMergeQueue.h" + +CL_NS_USE(store) +CL_NS_USE(util) +CL_NS_DEF(index) + +MultiReader::MultiReader(IndexReader** subReaders): + IndexReader(subReaders == NULL || subReaders[0] == NULL ? NULL : subReaders[0]->getDirectory()), + normsCache(true, true) +{ + initialize(subReaders); +} + +MultiReader::MultiReader(Directory* directory, SegmentInfos* sis, IndexReader** subReaders): + IndexReader(directory, sis, false), + normsCache(true, true) +{ + initialize(subReaders); +} + + +MultiReader::~MultiReader() { +//Func - Destructor +//Pre - true +//Post - The instance has been destroyed all IndexReader instances +// this instance managed have been destroyed to + + _CLDELETE_ARRAY(ones); + _CLDELETE_ARRAY(starts); + + //Iterate through the subReaders and destroy each reader + if (subReaders && subReadersLength > 0) { + for (int32_t i = 0; i < subReadersLength; i++) { + _CLDELETE(subReaders[i]); + } + } + //Destroy the subReaders array + _CLDELETE_ARRAY(subReaders); +} + +void MultiReader::initialize(IndexReader** subReaders){ + this->subReadersLength = 0; + this->subReaders = subReaders; + + //count the subReaders size + if ( subReaders != NULL ){ + while ( subReaders[subReadersLength] != NULL ){ + subReadersLength++; + } + } + _maxDoc = 0; + _numDocs = -1; + ones = NULL; + + starts = _CL_NEWARRAY(int32_t,subReadersLength + 1); // build starts array + for (int32_t i = 0; i < subReadersLength; i++) { + starts[i] = _maxDoc; + + // compute maxDocs + _maxDoc += subReaders[i]->maxDoc(); + if (subReaders[i]->hasDeletions()) + _hasDeletions = true; + } + starts[subReadersLength] = _maxDoc; +} + +bool MultiReader::getTermFreqVectors(int32_t n, Array& result){ + int32_t i = readerIndex(n); // find segment num + return subReaders[i]->getTermFreqVectors(n - starts[i], result); // dispatch to segment +} + +TermFreqVector* MultiReader::getTermFreqVector(int32_t n, const TCHAR* field){ + int32_t i = readerIndex(n); // find segment num + return subReaders[i]->getTermFreqVector(n - starts[i], field); +} + + +int32_t MultiReader::numDocs() { + SCOPED_LOCK_MUTEX(THIS_LOCK) + if (_numDocs == -1) { // check cache + int32_t n = 0; // cache miss--recompute + for (int32_t i = 0; i < subReadersLength; i++) + n += subReaders[i]->numDocs(); // sum from readers + _numDocs = n; + } + return _numDocs; +} + +int32_t MultiReader::maxDoc() const { + return _maxDoc; +} + +bool MultiReader::document(int32_t n, CL_NS(document)::Document* doc){ + int32_t i = readerIndex(n); // find segment num + return subReaders[i]->document(n - starts[i],doc); // dispatch to segment reader +} + +bool MultiReader::isDeleted(const int32_t n) { + int32_t i = readerIndex(n); // find segment num + return subReaders[i]->isDeleted(n - starts[i]); // dispatch to segment reader +} + +uint8_t* MultiReader::norms(const TCHAR* field){ + SCOPED_LOCK_MUTEX(THIS_LOCK) + uint8_t* bytes; + bytes = normsCache.get(field); + if (bytes != NULL){ + return bytes; // cache hit + } + + if ( !hasNorms(field) ) + return fakeNorms(); + + bytes = _CL_NEWARRAY(uint8_t,maxDoc()); + for (int32_t i = 0; i < subReadersLength; i++) + subReaders[i]->norms(field, bytes + starts[i]); + + //Unfortunately the data in the normCache can get corrupted, since it's being loaded with string + //keys that may be deleted while still in use by the map. To prevent this field is duplicated + //and then stored in the normCache + TCHAR* key = STRDUP_TtoT(field); + //update cache + normsCache.put(key, bytes); + + return bytes; +} + +void MultiReader::norms(const TCHAR* field, uint8_t* result) { + SCOPED_LOCK_MUTEX(THIS_LOCK) + uint8_t* bytes = normsCache.get(field); + if (bytes==NULL && !hasNorms(field)) + bytes=fakeNorms(); + + if (bytes != NULL){ // cache hit + int32_t len = maxDoc(); + memcpy(result,bytes,len * sizeof(int32_t)); + } + + for (int32_t i = 0; i < subReadersLength; i++) // read from segments + subReaders[i]->norms(field, result + starts[i]); +} + + +void MultiReader::doSetNorm(int32_t n, const TCHAR* field, uint8_t value){ + normsCache.remove(field); // clear cache + int32_t i = readerIndex(n); // find segment num + subReaders[i]->setNorm(n-starts[i], field, value); // dispatch +} + +TermEnum* MultiReader::terms() const { + return _CLNEW MultiTermEnum(subReaders, starts, NULL); +} + +TermEnum* MultiReader::terms(const Term* term) const { + return _CLNEW MultiTermEnum(subReaders, starts, term); +} + +int32_t MultiReader::docFreq(const Term* t) const { + int32_t total = 0; // sum freqs in Multi + for (int32_t i = 0; i < subReadersLength; i++) + total += subReaders[i]->docFreq(t); + return total; +} + +TermDocs* MultiReader::termDocs() const { + TermDocs* ret = _CLNEW MultiTermDocs(subReaders, starts); + return ret; +} + +TermPositions* MultiReader::termPositions() const { + TermPositions* ret = (TermPositions*)_CLNEW MultiTermPositions(subReaders, starts); + return ret; +} + +void MultiReader::doDelete(const int32_t n) { + _numDocs = -1; // invalidate cache + int32_t i = readerIndex(n); // find segment num + subReaders[i]->deleteDocument(n - starts[i]); // dispatch to segment reader + _hasDeletions = true; +} + +int32_t MultiReader::readerIndex(const int32_t n) const { // find reader for doc n: + int32_t lo = 0; // search starts array + int32_t hi = subReadersLength - 1; // for first element less + // than n, return its index + while (hi >= lo) { + int32_t mid = (lo + hi) >> 1; + int32_t midValue = starts[mid]; + if (n < midValue) + hi = mid - 1; + else if (n > midValue) + lo = mid + 1; + else{ // found a match + while (mid+1 < subReadersLength && starts[mid+1] == midValue) { + mid++; // scan to last match + } + return mid; + } + } + return hi; +} + +bool MultiReader::hasNorms(const TCHAR* field) { + for (int i = 0; i < subReadersLength; i++) { + if (subReaders[i]->hasNorms(field)) + return true; + } + return false; +} +uint8_t* MultiReader::fakeNorms() { + if (ones==NULL) + ones=SegmentReader::createFakeNorms(maxDoc()); + return ones; +} + +void MultiReader::doUndeleteAll(){ + for (int32_t i = 0; i < subReadersLength; i++) + subReaders[i]->undeleteAll(); + _hasDeletions = false; + _numDocs = -1; +} +void MultiReader::doCommit() { + for (int32_t i = 0; i < subReadersLength; i++) + subReaders[i]->commit(); +} + +void MultiReader::doClose() { + SCOPED_LOCK_MUTEX(THIS_LOCK) + for (int32_t i = 0; i < subReadersLength; i++){ + subReaders[i]->close(); + } +} + + +void MultiReader::getFieldNames(FieldOption fldOption, StringArrayWithDeletor& retarray){ + StringArrayWithDeletor temp; + CLHashList hashList; + for (int32_t i = 0; i < subReadersLength; i++) { + IndexReader* reader = subReaders[i]; + reader->getFieldNames(fldOption, temp); + + //create a unique list of names. + StringArrayWithDeletor::iterator itr = temp.begin(); + while ( itr != temp.end() ){ + if ( hashList.find(*itr) == hashList.end() ) + hashList.insert(STRDUP_TtoT(*itr)); + itr++; + } + } + //move the items into the return + CLHashList::iterator itr = hashList.begin(); + while ( itr != hashList.end() ){ + retarray.push_back(*itr);//no need to copy, already done! + itr++; + } +} + + +MultiTermDocs::MultiTermDocs(){ +//Func - Default constructor +// Initialises an empty MultiTermDocs. +// This constructor is needed to allow the constructor of MultiTermPositions +// initialise the instance by itself +//Pre - true +//Post - An empty + + subReaders = NULL; + subReadersLength = 0; + starts = NULL; + base = 0; + pointer = 0; + current = NULL; + term = NULL; + readerTermDocs = NULL; +} + +MultiTermDocs::MultiTermDocs(IndexReader** r, const int32_t* s){ +//Func - Constructor +//Pre - if r is NULL then rLen must be 0 else if r != NULL then rLen > 0 +// s != NULL +//Post - The instance has been created + + //count readers + subReadersLength = 0; + subReaders = r; + + CND_PRECONDITION(s != NULL, "s is NULL"); + + if ( subReaders != NULL ){ + while ( subReaders[subReadersLength] != NULL ) + subReadersLength++; + } + + starts = s; + base = 0; + pointer = 0; + current = NULL; + term = NULL; + + readerTermDocs = NULL; + + //Check if there are subReaders + if(subReaders != NULL && subReadersLength > 0){ + readerTermDocs = _CL_NEWARRAY(TermDocs*, subReadersLength+1); + + CND_CONDITION(readerTermDocs != NULL,"No memory could be allocated for readerTermDocs"); + + //Initialize the readerTermDocs pointer array to NULLs + for ( int32_t i=0;idoc(); +} +int32_t MultiTermDocs::freq() const { + CND_PRECONDITION(current!=NULL,"current==NULL, check that next() was called"); + return current->freq(); +} + +void MultiTermDocs::seek(TermEnum* termEnum){ + seek(termEnum->term(false)); +} + +void MultiTermDocs::seek( Term* tterm) { +//Func - Resets the instance for a new search +//Pre - tterm != NULL +//Post - The instance has been reset for a new search + + CND_PRECONDITION(tterm != NULL, "tterm is NULL"); + + //Assigning tterm is done as below for a reason + //The construction ensures that if seek is called from within + //MultiTermDocs with as argument this->term (seek(this->term)) that the assignment + //will succeed and all referencecounters represent the correct situation + + //Get a pointer from tterm and increase its reference counter + Term *TempTerm = _CL_POINTER(tterm); + + //Finialize term to ensure we decrease the reference counter of the instance which term points to + _CLDECDELETE(term); + + //Assign TempTerm to term + term = TempTerm; + + base = 0; + pointer = 0; + current = NULL; +} + +bool MultiTermDocs::next() { + if (current != NULL && current->next()) { + return true; + } else if (pointer < subReadersLength) { + base = starts[pointer]; + current = termDocs(pointer++); + return next(); + } else + return false; +} + +int32_t MultiTermDocs::read(int32_t* docs, int32_t* freqs, int32_t length) { + while (true) { + while (current == NULL) { + if (pointer < subReadersLength) { // try next segment + base = starts[pointer]; + current = termDocs(pointer++); + } else { + return 0; + } + } + int32_t end = current->read(docs, freqs,length); + if (end == 0) { // none left in segment + current = NULL; + } else { // got some + int32_t b = base; // adjust doc numbers + for (int32_t i = 0; i < end; i++) + docs[i] += b; + return end; + } + } +} + +bool MultiTermDocs::skipTo(const int32_t target) { + do { + if (!next()) + return false; + } while (target > doc()); + return true; +} + +void MultiTermDocs::close() { +//Func - Closes all MultiTermDocs managed by this instance +//Pre - true +//Post - All the MultiTermDocs have been closed + + + //Check if readerTermDocs is valid + if (readerTermDocs){ + TermDocs* curTD = NULL; + //iterate through the readerTermDocs array + for (int32_t i = 0; i < subReadersLength; i++) { + //Retrieve the i-th TermDocs instance + curTD = readerTermDocs[i]; + + //Check if it is a valid pointer + if (curTD != NULL) { + //Close it + curTD->close(); + _CLDELETE(curTD); + } + } + + _CLDELETE_ARRAY(readerTermDocs); + } + + //current previously pointed to a member of readerTermDocs; ensure that + //it doesn't now point to invalid memory. + current = NULL; + base = 0; + pointer = 0; + + _CLDECDELETE(term); +} + +TermDocs* MultiTermDocs::termDocs(const IndexReader* reader) const { + TermDocs* ret = reader->termDocs(); + return ret; +} + +TermDocs* MultiTermDocs::termDocs(const int32_t i) const { + if (term == NULL) + return NULL; + TermDocs* result = readerTermDocs[i]; + if (result == NULL){ + readerTermDocs[i] = termDocs(subReaders[i]); + result = readerTermDocs[i]; + } + result->seek(term); + + return result; +} + + +MultiTermEnum::MultiTermEnum( + IndexReader** subReaders, const int32_t *starts, const Term* t){ +//Func - Constructor +// Opens all enumerations of all readers +//Pre - readers != NULL and contains an array of IndexReader instances each responsible for +// reading a single segment +// subReadersLength >= 0 and represents the number of readers in the readers array +// starts is an array of +//Post - An instance of has been created + +//Pre - if readers is NULL then subReadersLength must be 0 else if readers != NULL then subReadersLength > 0 +// s != NULL +//Post - The instance has been created + + int32_t subReadersLength = 0; + if ( subReaders != NULL ){ + while ( subReaders[subReadersLength] != NULL ) + subReadersLength++; + } + CND_PRECONDITION(starts != NULL,"starts is NULL"); + + //Temporary variables + IndexReader* reader = NULL; + TermEnum* termEnum = NULL; + SegmentMergeInfo* smi = NULL; + _docFreq = 0; + _term = NULL; + queue = _CLNEW SegmentMergeQueue(subReadersLength); + + CND_CONDITION (queue != NULL, "Could not allocate memory for queue"); + + //iterate through all the readers + for ( int32_t i=0;iterms(t); + }else{ + //termEnum is an enumeration of all the Terms and TermInfos in the set. + termEnum = reader->terms(); + } + + //Instantiate an new SegmentMerginfo + smi = _CLNEW SegmentMergeInfo(starts[i], termEnum, reader); + + // Note that in the call termEnum->getTerm(false) below false is required because + // otherwise a reference is leaked. By passing false getTerm is + // ordered to return an unowned reference instead. (Credits for DSR) + if (t == NULL ? smi->next() : termEnum->term(false) != NULL){ + // initialize queue + queue->put(smi); + } else{ + //Close the SegmentMergeInfo + smi->close(); + //And have it deleted + _CLDELETE(smi); + } + } + + //Check if the queue has elements + if (t != NULL && queue->size() > 0) { + next(); + } +} + +MultiTermEnum::~MultiTermEnum(){ +//Func - Destructor +//Pre - true +//Post - All the resource have been freed and the instance has been deleted + + //Close the enumeration + close(); + + //Delete the queue + _CLDELETE(queue); +} + +bool MultiTermEnum::next(){ +//Func - Move the current term to the next in the set of enumerations +//Pre - true +//Post - Returns true if term has been moved to the next in the set of enumerations +// Returns false if this was not possible + + SegmentMergeInfo* top = queue->top(); + if (top == NULL) { + _CLDECDELETE(_term); + _term = NULL; + return false; + } + + //The getTerm method requires the client programmer to indicate whether he + // owns the returned reference, so we can discard ours + // right away. + _CLDECDELETE(_term); + + //Assign term the term of top and make sure the reference counter is increased + _term = _CL_POINTER(top->term); + _docFreq = 0; + + //Find the next term + while (top != NULL && _term->compareTo(top->term) == 0) { + //don't delete, this is the top + queue->pop(); + // increment freq + _docFreq += top->termEnum->docFreq(); + if (top->next()){ + // restore queue + queue->put(top); + }else{ + // done with a segment + top->close(); + _CLDELETE(top); + } + top = queue->top(); + } + + return true; +} + + +Term* MultiTermEnum::term() { +//Func - Returns the current term of the set of enumerations +//Pre - pointer is true or false and indicates if the reference counter +// of term must be increased or not +// next() must have been called once! +//Post - pointer = true -> term has been returned with an increased reference counter +// pointer = false -> term has been returned + + return _CL_POINTER(_term); +} + +Term* MultiTermEnum::term(bool pointer) { + if ( pointer ) + return _CL_POINTER(_term); + else + return _term; +} + +int32_t MultiTermEnum::docFreq() const { +//Func - Returns the document frequency of the current term in the set +//Pre - termInfo != NULL +// next() must have been called once +//Post - The document frequency of the current enumerated term has been returned + + return _docFreq; +} + + +void MultiTermEnum::close() { +//Func - Closes the set of enumerations in the queue +//Pre - queue holds a valid reference to a SegmentMergeQueue +//Post - The queue has been closed all SegmentMergeInfo instance have been deleted by +// the closing of the queue +// term has been finalized and reset to NULL + + // Needed when this enumeration hasn't actually been exhausted yet + _CLDECDELETE(_term); + + //Close the queue This will destroy all SegmentMergeInfo instances! + queue->close(); + +} + + + + + +MultiTermPositions::MultiTermPositions(IndexReader** r, const int32_t* s){ +//Func - Constructor +//Pre - if r is NULL then rLen must be 0 else if r != NULL then rLen > 0 +// s != NULL +//Post - The instance has been created + + subReaders = r; + subReadersLength = 0; + if ( subReaders != NULL ){ + while ( subReaders[subReadersLength] != NULL ) + subReadersLength ++ ; + } + + CND_PRECONDITION(s != NULL, "s is NULL"); + + starts = s; + base = 0; + pointer = 0; + current = NULL; + term = NULL; + + readerTermDocs = NULL; + + //Check if there are readers + if(subReaders != NULL && subReadersLength > 0){ + readerTermDocs = (TermDocs**)_CL_NEWARRAY(SegmentTermPositions*,subReadersLength); + + CND_CONDITION(readerTermDocs != NULL,"No memory could be allocated for readerTermDocs"); + + //Initialize the readerTermDocs pointer array + for ( int32_t i=0;icurrent to always +// be a SegmentTermPositions rather than merely a SegmentTermDocs. +// To that end, we override the termDocs(IndexReader&) method to produce +// a SegmentTermPositions via the underlying reader's termPositions method +// rather merely producing a SegmentTermDocs via the reader's termDocs +// method. + + TermPositions* tp = reader->termPositions(); + TermDocs* ret = tp->__asTermDocs(); + + CND_CONDITION(ret != NULL, + "Dynamic downcast in MultiTermPositions::termDocs from" + " TermPositions to TermDocs failed." + ); + return ret; + } + +int32_t MultiTermPositions::nextPosition() { + //Func - + //Pre - current != NULL + //Post - + CND_PRECONDITION(current != NULL,"current is NULL"); + + TermPositions* curAsTP = current->__asTermPositions(); + + CND_CONDITION(curAsTP != NULL, + "Dynamic downcast in MultiTermPositions::nextPosition from" + " SegmentTermDocs to TermPositions failed." + ) + return curAsTP->nextPosition(); +} + + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/MultiReader.h b/3rdparty/clucene/src/CLucene/index/MultiReader.h new file mode 100644 index 000000000..1d76814e1 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/MultiReader.h @@ -0,0 +1,202 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_index_MultiReader +#define _lucene_index_MultiReader + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "SegmentHeader.h" +#include "IndexReader.h" +#include "CLucene/document/Document.h" +#include "Terms.h" +#include "SegmentMergeQueue.h" + +CL_NS_DEF(index) + +/** An IndexReader which reads multiple indexes, appending their content. +*/ +class MultiTermDocs:public virtual TermDocs { +private: +protected: + TermDocs** readerTermDocs; + + IndexReader** subReaders; + int32_t subReadersLength; + const int32_t* starts; + Term* term; + + int32_t base; + int32_t pointer; + + TermDocs* current; // == segTermDocs[pointer] +public: + MultiTermDocs(); + MultiTermDocs(IndexReader** subReaders, const int32_t* s); + virtual ~MultiTermDocs(); + + int32_t doc() const; + int32_t freq() const; + + void seek(TermEnum* termEnum); + void seek(Term* tterm); + bool next(); + + /** Optimized implementation. */ + int32_t read(int32_t* docs, int32_t* freqs, int32_t length); + + /** As yet unoptimized implementation. */ + bool skipTo(const int32_t target); + + void close(); + + virtual TermPositions* __asTermPositions(); +protected: + virtual TermDocs* termDocs(const IndexReader* reader) const; +private: + TermDocs* termDocs(const int32_t i) const; + +}; + + +//MultiTermEnum represents the enumeration of all terms of all readers +class MultiTermEnum:public TermEnum { +private: + SegmentMergeQueue* queue; + + Term* _term; + int32_t _docFreq; +public: + //Constructor + //Opens all enumerations of all readers + MultiTermEnum(IndexReader** subReaders, const int32_t* starts, const Term* t); + + //Destructor + ~MultiTermEnum(); + + //Move the current term to the next in the set of enumerations + bool next(); + + //Returns a pointer to the current term of the set of enumerations + Term* term(); + Term* term(bool pointer); + + //Returns the document frequency of the current term in the set + int32_t docFreq() const; + + //Closes the set of enumerations in the queue + void close(); + + + const char* getObjectName(){ return MultiTermEnum::getClassName(); } + static const char* getClassName(){ return "MultiTermEnum"; } +}; + + +class MultiTermPositions:public MultiTermDocs,public TermPositions { +public: + MultiTermPositions(IndexReader** subReaders, const int32_t* s); + ~MultiTermPositions() {}; + int32_t nextPosition(); + + + virtual TermDocs* __asTermDocs(); + virtual TermPositions* __asTermPositions(); +protected: + TermDocs* termDocs(const IndexReader* reader) const; +}; + + +class MultiReader:public IndexReader{ +private: + bool _hasDeletions; + IndexReader** subReaders; + int32_t subReadersLength; + int32_t* starts; // 1st docno for each segment + + CL_NS(util)::CLHashtable > normsCache; + int32_t _maxDoc; + int32_t _numDocs; + void initialize(IndexReader** subReaders); + + int32_t readerIndex(const int32_t n) const; + + bool hasNorms(const TCHAR* field); + uint8_t* ones; + uint8_t* fakeNorms(); +protected: + void doSetNorm(int32_t n, const TCHAR* field, uint8_t value); + void doUndeleteAll(); + void doCommit(); + // synchronized + void doClose(); + + // synchronized + void doDelete(const int32_t n); +public: + /** Construct reading the named set of readers. */ + MultiReader(CL_NS(store)::Directory* directory, SegmentInfos* sis, IndexReader** subReaders); + + /** + *

Construct a MultiReader aggregating the named set of (sub)readers. + * Directory locking for delete, undeleteAll, and setNorm operations is + * left to the subreaders.

+ *

Note that all subreaders are closed if this Multireader is closed.

+ * @param subReaders set of (sub)readers + * @throws IOException + */ + MultiReader(IndexReader** subReaders); + + ~MultiReader(); + + /** Return an array of term frequency vectors for the specified document. + * The array contains a vector for each vectorized field in the document. + * Each vector vector contains term numbers and frequencies for all terms + * in a given vectorized field. + * If no such fields existed, the method returns null. + */ + bool getTermFreqVectors(int32_t n, Array& result); + TermFreqVector* getTermFreqVector(int32_t n, const TCHAR* field); + + + // synchronized + int32_t numDocs(); + + int32_t maxDoc() const; + + bool document(int32_t n, CL_NS(document)::Document* doc); + + bool isDeleted(const int32_t n); + bool hasDeletions() const{ return _hasDeletions; } + + // synchronized + uint8_t* norms(const TCHAR* field); + void norms(const TCHAR* field, uint8_t* result); + + TermEnum* terms() const; + TermEnum* terms(const Term* term) const; + + //Returns the document frequency of the current term in the set + int32_t docFreq(const Term* t=NULL) const; + TermDocs* termDocs() const; + TermPositions* termPositions() const; + + + /** + * @see IndexReader#getFieldNames(IndexReader.FieldOption fldOption) + */ + void getFieldNames(FieldOption fldOption, CL_NS(util)::StringArrayWithDeletor& retarray); +}; + + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/index/SegmentHeader.h b/3rdparty/clucene/src/CLucene/index/SegmentHeader.h new file mode 100644 index 000000000..00b08991d --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/SegmentHeader.h @@ -0,0 +1,314 @@ +/* +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +* +* Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#ifndef _lucene_index_SegmentHeader_ +#define _lucene_index_SegmentHeader_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include "SegmentInfos.h" +#include "CLucene/util/BitSet.h" +#include "CLucene/util/VoidMap.h" +#include "Term.h" +#include "FieldInfos.h" +#include "FieldsReader.h" +#include "IndexReader.h" +#include "TermInfosReader.h" +#include "CompoundFile.h" +#include "CLucene/util/ThreadLocal.h" + +CL_NS_DEF(index) + +class SegmentReader; + +class SegmentTermDocs : public virtual TermDocs +{ + int32_t _doc; + int32_t skipInterval; + int32_t numSkips; + int32_t skipCount; + CL_NS(store)::IndexInput* skipStream; + int32_t skipDoc; + int64_t freqPointer; + int64_t proxPointer; + int64_t skipPointer; + bool haveSkipped; + +protected: + // SegmentReader parent + const SegmentReader* parent; + CL_NS(store)::IndexInput* freqStream; + int32_t count; + int32_t df; + int32_t _freq; + CL_NS(util)::BitSet* deletedDocs; +public: + virtual ~SegmentTermDocs(); + + virtual void seek(TermEnum* termEnum); + virtual void seek(Term* term); + virtual void seek(const TermInfo* ti); + + virtual void close(); + virtual int32_t doc()const; + virtual int32_t freq()const; + + virtual bool next(); + + /** Optimized implementation. */ + virtual int32_t read(int32_t* docs, int32_t* freqs, int32_t length); + + /** Optimized implementation. */ + virtual bool skipTo(const int32_t target); + + virtual TermPositions* __asTermPositions(); + + // \param Parent must be a segment reader + SegmentTermDocs( const SegmentReader* Parent); +protected: + virtual void skippingDoc(){} + virtual void skipProx(int64_t proxPointer){} +}; + + +class SegmentTermPositions : public SegmentTermDocs, public TermPositions +{ +private: + CL_NS(store)::IndexInput* proxStream; + int32_t proxCount; + int32_t position; + +public: + // \param Parent must be a segment reader + SegmentTermPositions(const SegmentReader* Parent); + ~SegmentTermPositions(); + + void seek(const TermInfo* ti); + void close(); + int32_t nextPosition(); + bool next(); + int32_t read(int32_t* docs, int32_t* freqs, int32_t length); + virtual TermDocs* __asTermDocs(); + virtual TermPositions* __asTermPositions(); + + //resolve SegmentTermDocs/TermPositions ambiguity + void seek(Term* term){ SegmentTermDocs::seek(term); } + void seek(TermEnum* termEnum){ SegmentTermDocs::seek(termEnum); } + int32_t doc() const{ return SegmentTermDocs::doc(); } + int32_t freq() const{ return SegmentTermDocs::freq(); } + bool skipTo(const int32_t target){ return SegmentTermDocs::skipTo(target); } + +protected: + void skippingDoc(); + /** Called by super.skipTo(). */ + void skipProx(int64_t proxPointer); +}; + +// An IndexReader responsible for reading 1 segment of an index +class SegmentReader : public IndexReader +{ + /** + * The class Norm represents the normalizations for a field. + * These normalizations are read from an IndexInput in into an array of bytes called bytes + */ + class Norm : LUCENE_BASE + { + int32_t number; + SegmentReader* reader; + QString segment; // segment name + + public: + CL_NS(store)::IndexInput* in; + uint8_t* bytes; + bool dirty; + //Constructor + Norm(CL_NS(store)::IndexInput* instrm, int32_t number, + SegmentReader* reader, const QString& segment); + //Destructor + ~Norm(); + + void reWrite(); + }; + friend class SegmentReader::Norm; + + //Holds the name of the segment that is being read + QString segment; + + //Indicates if there are documents marked as deleted + bool deletedDocsDirty; + bool normsDirty; + bool undeleteAll; + + //Holds all norms for all fields in the segment + typedef CL_NS(util)::CLHashtable NormsType; + NormsType _norms; + + uint8_t* ones; + uint8_t* fakeNorms(); + + // Compound File Reader when based on a compound file segment + CompoundFileReader* cfsReader; + // Reads the Field Info file + FieldsReader* fieldsReader; + TermVectorsReader* termVectorsReaderOrig; + CL_NS(util)::ThreadLocal >termVectorsLocal; + + void initialize(SegmentInfo* si); + + // Create a clone from the initial TermVectorsReader and store it in the + // ThreadLocal. @return TermVectorsReader + TermVectorsReader* getTermVectorsReader(); + +protected: + // Marks document docNum as deleted + void doDelete(const int32_t docNum); + void doUndeleteAll(); + void doCommit(); + void doSetNorm(int32_t doc, const TCHAR* field, uint8_t value); + + // can return null if norms aren't stored + uint8_t* getNorms(const TCHAR* field); + +public: + /** + Func - Constructor. + Opens all files of a segment + .fnm -> Field Info File + Field names are stored in the field info file, with suffix .fnm. + .frq -> Frequency File + The .frq file contains the lists of documents which contain + each term, along with the frequency of the term in that document. + .prx -> Prox File + The prox file contains the lists of positions that each term occurs + at within documents. + .tis -> Term Info File + This file is sorted by Term. Terms are ordered first lexicographically + by the term's field name, and within that lexicographically by the term's text. + .del -> Deletion File + The .del file is optional, and only exists when a segment contains deletions + .f[0-9]* -> Norm File + Contains s, for each document, a byte that encodes a value that is + multiplied into the score for hits on that field: + */ + SegmentReader(SegmentInfo* si); + + SegmentReader(SegmentInfos* sis, SegmentInfo* si); + // Destructor. + virtual ~SegmentReader(); + + // Closes all streams to the files of a single segment + void doClose(); + + // Checks if a segment managed by SegmentInfo si has deletions + static bool hasDeletions(const SegmentInfo* si); + bool hasDeletions() const; + bool hasNorms(const TCHAR* field) const; + + // Returns all file names managed by this SegmentReader + void files(QStringList& retarray); + // Returns an enumeration of all the Terms and TermInfos in the set. + TermEnum* terms() const; + // Returns an enumeration of terms starting at or after the named term t + TermEnum* terms(const Term* t) const; + + // Gets the document identified by n + bool document(int32_t n, CL_NS(document)::Document* doc); + + // Checks if the n-th document has been marked deleted + bool isDeleted(const int32_t n); + + // Returns an unpositioned TermDocs enumerator. + TermDocs* termDocs() const; + // Returns an unpositioned TermPositions enumerator. + TermPositions* termPositions() const; + + // Returns the number of documents which contain the term t + int32_t docFreq(const Term* t) const; + + // Returns the actual number of documents in the segment + int32_t numDocs(); + // Returns the number of all the documents in the segment including the + // ones that have been marked deleted + int32_t maxDoc() const; + + // Returns the bytes array that holds the norms of a named field. + // Returns fake norms if norms aren't available + uint8_t* norms(const TCHAR* field); + + // Reads the Norms for field from disk + void norms(const TCHAR* field, uint8_t* bytes); + + // concatenating segment with ext and x + QString SegmentName(const QString& ext, const int32_t x = -1); + // Creates a filename in buffer by concatenating segment with ext and x + void SegmentName(QString& buffer, int32_t bufferLen, const QString& ext, + const int32_t x = -1); + + /** + * @see IndexReader#getFieldNames(IndexReader.FieldOption fldOption) + */ + void getFieldNames(FieldOption fldOption, CL_NS(util)::StringArrayWithDeletor& retarray); + + static bool usesCompoundFile(SegmentInfo* si); + + /** Return a term frequency vector for the specified document and field. The + * vector returned contains term numbers and frequencies for all terms in + * the specified field of this document, if the field had storeTermVector + * flag set. If the flag was not set, the method returns null. + * @throws IOException + */ + TermFreqVector* getTermFreqVector(int32_t docNumber, const TCHAR* field = NULL); + + /** Return an array of term frequency vectors for the specified document. + * The array contains a vector for each vectorized field in the document. + * Each vector vector contains term numbers and frequencies for all terms + * in a given vectorized field. + * If no such fields existed, the method returns null. + * @throws IOException + */ + bool getTermFreqVectors(int32_t docNumber, Array& result); + +private: + //Open all norms files for all fields + void openNorms(CL_NS(store)::Directory* cfsDir); + //Closes all norms files + void closeNorms(); + + // a bitVector that manages which documents have been deleted + CL_NS(util)::BitSet* deletedDocs; + // an IndexInput to the frequency file + CL_NS(store)::IndexInput* freqStream; + // For reading the fieldInfos file + FieldInfos* fieldInfos; + // For reading the Term Dictionary .tis file + TermInfosReader* tis; + // an IndexInput to the prox file + CL_NS(store)::IndexInput* proxStream; + + static bool hasSeparateNorms(SegmentInfo* si); + static uint8_t* createFakeNorms(int32_t size); + + // allow various classes to access the internals of this. this allows us + // to have a more tight idea of the package + friend class IndexReader; + friend class IndexWriter; + friend class SegmentTermDocs; + friend class SegmentTermPositions; + friend class MultiReader; +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/index/SegmentInfos.cpp b/3rdparty/clucene/src/CLucene/index/SegmentInfos.cpp new file mode 100644 index 000000000..f62c4061a --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/SegmentInfos.cpp @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +*/ +#include "CLucene/StdHeader.h" +#include "SegmentInfos.h" + +#include "CLucene/store/Directory.h" +#include "CLucene/util/Misc.h" + +CL_NS_USE(store) +CL_NS_USE(util) +CL_NS_DEF(index) + +SegmentInfo::SegmentInfo(const QString& Name, const int32_t DocCount, + CL_NS(store)::Directory* Dir) + : docCount(DocCount) + , dir(Dir) +{ + //Func - Constructor. Initialises SegmentInfo. + //Pre - Name holds the unique name in the directory Dir + // DocCount holds the number of documents in the segment + // Dir holds the Directory where the segment resides + //Post - The instance has been created. name contains the duplicated string + // Name. docCount = DocCount and dir references Dir + name = Name; +} + +SegmentInfo::~SegmentInfo() +{ +} + +SegmentInfos::SegmentInfos(bool _deleteMembers) + : deleteMembers(_deleteMembers) +{ + //Func - Constructor + //Pre - deleteMembers indicates if the instance to be created must delete + // all SegmentInfo instances it manages when the instance is destroyed + // or not true -> must delete, false may not delete + //Post - An instance of SegmentInfos has been created. + + //initialize counter to 0 + counter = 0; + version = Misc::currentTimeMillis(); +} + +SegmentInfos::~SegmentInfos() +{ + //Func - Destructor + //Pre - true + //Post - The instance has been destroyed. Depending on the constructor used + // the SegmentInfo instances that this instance managed have been + // deleted or not. + + if (deleteMembers) { + segmentInfosType::iterator it; + for (it = infos.begin(); it != infos.end(); ++it) + _CLLDELETE(*it); + } + //Clear the list of SegmentInfo instances - make sure everything is deleted + infos.clear(); +} + +SegmentInfo* SegmentInfos::info(int32_t i) const +{ + //Func - Returns a reference to the i-th SegmentInfo in the list. + //Pre - i >= 0 + //Post - A reference to the i-th SegmentInfo instance has been returned + + CND_PRECONDITION(i >= 0, "i contains negative number"); + + //Get the i-th SegmentInfo instance + SegmentInfo *ret = infos.value(i, 0); + + //Condition check to see if the i-th SegmentInfo has been retrieved + CND_CONDITION(ret != NULL, "No SegmentInfo instance found"); + + return ret; +} + +void SegmentInfos::clearto(size_t _min) +{ + // Make sure we actually need to remove + if (infos.size() > _min) { + segmentInfosType::iterator itr; + segmentInfosType::iterator eitr = infos.end(); + segmentInfosType::iterator bitr = infos.begin() + _min; + + for(itr = bitr; itr != eitr; ++itr) + _CLLDELETE((*itr)); + infos.erase(bitr, eitr); + } +} + +void SegmentInfos::add(SegmentInfo* info) +{ + infos.push_back(info); +} + +int32_t SegmentInfos::size() const +{ + return infos.size(); +} + +void SegmentInfos::read(Directory* directory) +{ + //Func - Reads segments file that resides in directory. + //Pre - directory contains a valid reference + //Post - The segments file has been read and for each segment found + // a SegmentsInfo intance has been created and stored. + + //Open an IndexInput to the segments file and check if valid + IndexInput* input = directory->openInput(QLatin1String("segments")); + if (input) { + try { + int32_t format = input->readInt(); + // file contains explicit format info + if (format < 0) { + // check that it is a format we can understand + if (format < FORMAT) { + TCHAR err[30]; + _sntprintf(err, 30, _T("Unknown format version: %d"), format); + _CLTHROWT(CL_ERR_Runtime, err); + } + // read version + version = input->readLong(); + // read counter + counter = input->readInt(); + } else { + // file is in old format without explicit format info + counter = format; + } + + //Temporary variable for storing the name of the segment + char aname[CL_MAX_PATH] = { 0 }; + TCHAR tname[CL_MAX_PATH] = { 0 }; + + //read segmentInfos + for (int32_t i = input->readInt(); i > 0; --i) { + // read the name of the segment + input->readString(tname, CL_MAX_PATH); + STRCPY_TtoA(aname, tname, CL_MAX_PATH); + + //Instantiate a new SegmentInfo Instance + SegmentInfo* si = _CLNEW SegmentInfo(QLatin1String(aname), + input->readInt(), directory); + + //Condition check to see if si points to an instance + CND_CONDITION(si != NULL, "Memory allocation for si failed") ; + + //store SegmentInfo si + infos.push_back(si); + } + + if (format >= 0) { + // in old format the version number may be at the end of the file + if (input->getFilePointer() >= input->length()) { + // old file format without version number + version = Misc::currentTimeMillis(); + } else { + // read version + version = input->readLong(); + } + } + } _CLFINALLY ( + //destroy the inputStream input. The destructor of IndexInput will + //also close the Inputstream input + _CLDELETE(input); + ); + } +} + +void SegmentInfos::write(Directory* directory) +{ + //Func - Writes a new segments file based upon the SegmentInfo instances it manages + //Pre - directory is a valid reference to a Directory + //Post - The new segment has been written to disk + + //Open an IndexOutput to the segments file and check if valid + IndexOutput* output = directory->createOutput(QLatin1String("segments.new")); + if (output) { + try { + // write FORMAT + output->writeInt(FORMAT); + // every write changes the index + output->writeLong(++version); + // Write the counter + output->writeInt(counter); + + // Write the number of SegmentInfo Instances which is equal to the number + // of segments in directory as each SegmentInfo manages a single segment + output->writeInt(infos.size()); + + //temporary value for wide segment name + TCHAR tname[CL_MAX_PATH]; + + //Iterate through all the SegmentInfo instances + for (uint32_t i = 0; i < infos.size(); ++i) { + //Retrieve the SegmentInfo + SegmentInfo *si = infos.value(i, 0); + //Condition check to see if si has been retrieved + CND_CONDITION(si != NULL, "No SegmentInfo instance found"); + + //Write the name of the current segment + int32_t count = si->name.toWCharArray(tname); + tname[count] = '\0'; + output->writeString(tname, _tcslen(tname)); + + //Write the number of documents in the segment + output->writeInt(si->docCount); + } + } _CLFINALLY( + output->close(); + _CLDELETE(output); + ); + + // install new segment info + directory->renameFile(QLatin1String("segments.new"), + QLatin1String("segments")); + } +} + + +int64_t SegmentInfos::readCurrentVersion(Directory* directory) +{ + int32_t format = 0; + int64_t version = 0; + IndexInput* input = directory->openInput(QLatin1String("segments")); + try { + format = input->readInt(); + if (format < 0){ + if (format < FORMAT) { + TCHAR err[30]; + _sntprintf(err, 30, _T("Unknown format version: %d"), format); + _CLTHROWT(CL_ERR_Runtime, err); + } + // read version + version = input->readLong(); + } + } _CLFINALLY ( + input->close(); + _CLDELETE(input); + ); + + if (format < 0) + return version; + + // We cannot be sure about the format of the file. Therefore we have to + // read the whole file and cannot simply seek to the version entry. + SegmentInfos segmentInfos; + segmentInfos.read(directory); + return segmentInfos.getVersion(); +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/SegmentInfos.h b/3rdparty/clucene/src/CLucene/index/SegmentInfos.h new file mode 100644 index 000000000..ce7183820 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/SegmentInfos.h @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +*/ +#ifndef _lucene_index_SegmentInfos_ +#define _lucene_index_SegmentInfos_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include "CLucene/store/Directory.h" + +CL_NS_DEF(index) + +class SegmentInfo : LUCENE_BASE +{ +public: + SegmentInfo(const QString& Name, const int32_t DocCount, + CL_NS(store)::Directory* Dir); + ~SegmentInfo(); + + ///Gets the Directory where the segment resides + CL_NS(store)::Directory* getDir() const { return dir; } + + //Unique name in directory dir + QString name; + + //Number of docs in the segment + const int32_t docCount; + +private: + //Directory where the segment resides + CL_NS(store)::Directory* dir; +}; + +typedef QVector segmentInfosType; + +//SegmentInfos manages a list of SegmentInfo instances +//Each SegmentInfo contains information about a segment in a directory. +// +//The active segments in the index are stored in the segment info file. +//An index only has a single file in this format, and it is named "segments". +//This lists each segment by name, and also contains the size of each segment. +//The format of the file segments is defined as follows: +// +// SegCount +//Segments --> SegCount, +// +//SegCount, SegSize --> UInt32 +// +//SegName --> String +// +//SegName is the name of the segment, and is used as the file name prefix +//for all of the files that compose the segment's index. +// +//SegSize is the number of documents contained in the segment index. +// +//Note: +//At http://jakarta.apache.org/lucene/docs/fileformats.html the definition +//of all file formats can be found. Note that java lucene currently +//defines Segments as follows: +// +//Segments --> Format, Version, SegCount, SegCount +// +//Format, SegCount, SegSize --> UInt32 +// +//Format and Version have not been implemented yet +class SegmentInfos : LUCENE_BASE +{ +public: + SegmentInfos(bool deleteMembers = true); + ~SegmentInfos(); + + //delete and clears objects 'from' from to 'to' + void clearto(size_t to); + + //count of segment infos + int32_t size() const; + + //add a segment info + void add(SegmentInfo* info); + + //Returns a reference to the i-th SegmentInfo in the list. + SegmentInfo* info(int32_t i) const; + + // version number when this SegmentInfos was generated. + int64_t getVersion() const { return version; } + + static int64_t readCurrentVersion(CL_NS(store)::Directory* directory); + + //Reads segments file that resides in directory + void read(CL_NS(store)::Directory* directory); + + //Writes a new segments file based upon the SegmentInfo instances it manages + void write(CL_NS(store)::Directory* directory); + +private: + // The file format version, a negative number. + // Works since counter, the old 1st entry, is always >= 0 + LUCENE_STATIC_CONSTANT(int32_t, FORMAT = -1); + + // counts how often the index has been changed by adding or deleting docs. + // starting with the current time in milliseconds forces to create unique + // version numbers. + int64_t version; + + segmentInfosType infos; + + // used to name new segments + int32_t counter; + + // allow IndexWriter to use counter + friend class IndexWriter; + + bool deleteMembers; +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/index/SegmentMergeInfo.cpp b/3rdparty/clucene/src/CLucene/index/SegmentMergeInfo.cpp new file mode 100644 index 000000000..85ac784ad --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/SegmentMergeInfo.cpp @@ -0,0 +1,104 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "SegmentMergeInfo.h" + +#include "SegmentTermEnum.h" +#include "SegmentHeader.h" + +CL_NS_DEF(index) + +SegmentMergeInfo::SegmentMergeInfo(const int32_t b, TermEnum* te, IndexReader* r): + reader(r),termEnum(te),base(b), docMap(NULL) { +//Func - Constructor +//Pre - b >= 0 +// te contains a valid reference to a SegmentTermEnum instance +// r contains a valid reference to a SegmentReader instance +//Post - The instance has been created + + CND_PRECONDITION(b >= 0, "b is a negative number"); + + postings=NULL; + term = te->term(); +} + +SegmentMergeInfo::~SegmentMergeInfo(){ +//Func - Destructor +//Pre - true +//Post - The instance has been destroyed + + close(); +} + +int32_t* SegmentMergeInfo::getDocMap(){ + if ( docMap == NULL ){ + // build array which maps document numbers around deletions + if (reader->hasDeletions()) { + //Get the total number of documents managed by the reader including the deleted ones + int32_t maxDoc = reader->maxDoc(); + //Create a map for all documents + docMap = _CL_NEWARRAY(int32_t,maxDoc); + int32_t j = 0; + //Iterate through all the document numbers + for (int32_t i = 0; i < maxDoc; i++) { + //Check if document i is marked deleted + if (reader->isDeleted(i)){ + //Document i has not been marked deleted so assign -1 + docMap[i] = -1; + }else{ + docMap[i] = j++; + } + } + } + } + return docMap; +} + +TermPositions* SegmentMergeInfo::getPositions() { + if (postings == NULL) { + postings = reader->termPositions(); + } + return postings; +} + + +bool SegmentMergeInfo::next() { +//Func - Moves the current term of the enumeration termEnum to the next and term +// points to this new current term +//Pre - true +//Post - Returns true if the term has been moved to the next otherwise false + if (termEnum->next()) { + _CLDECDELETE(term); + term = termEnum->term(); + return true; + } else { + _CLDECDELETE(term); //TODO: test HighFreqTerms errors with this + term = NULL; + return false; + } +} + +void SegmentMergeInfo::close() { +//Func - Closes the the resources +//Pre - true +//Post - The resources have been closed + + //First make sure posting has been closed + if ( postings != NULL ){ + postings->close(); + _CLVDELETE(postings); //todo: not a clucene object... should be + } + + if ( termEnum != NULL ){ + termEnum->close(); + _CLDELETE(termEnum); + } + _CLDECDELETE(term); + _CLDELETE_ARRAY(docMap); +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/SegmentMergeInfo.h b/3rdparty/clucene/src/CLucene/index/SegmentMergeInfo.h new file mode 100644 index 000000000..7ffd46ade --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/SegmentMergeInfo.h @@ -0,0 +1,47 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_index_SegmentMergeInfo_ +#define _lucene_index_SegmentMergeInfo_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "SegmentTermEnum.h" +#include "SegmentHeader.h" + +CL_NS_DEF(index) +class SegmentMergeInfo:LUCENE_BASE { + int32_t* docMap; // maps around deleted docs + TermPositions* postings; +public: + TermEnum* termEnum; + Term* term; + int32_t base; + IndexReader* reader; + + //Constructor + SegmentMergeInfo(const int32_t b, TermEnum* te, IndexReader* r); + + //Destructor + ~SegmentMergeInfo(); + + //Moves the current term of the enumeration termEnum to the next and term + //points to this new current term + bool next(); + + //Closes the the resources + void close(); + + // maps around deleted docs + int32_t* getDocMap(); + + TermPositions* getPositions(); +}; +CL_NS_END +#endif + diff --git a/3rdparty/clucene/src/CLucene/index/SegmentMergeQueue.cpp b/3rdparty/clucene/src/CLucene/index/SegmentMergeQueue.cpp new file mode 100644 index 000000000..879781287 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/SegmentMergeQueue.cpp @@ -0,0 +1,74 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "SegmentMergeQueue.h" + +#include "SegmentMergeInfo.h" +CL_NS_DEF(index) + + + SegmentMergeQueue::SegmentMergeQueue(const int32_t size) { + //Func - Constructor + // Creates a queue of length size + //Pre - size >= 0 + //Post - The queue has been created of length size + + //BVK: bug. changed condition from size > 0 to size >= 0 + //if size is 0, as it is when retrieving a TermEnum + //from an empty index this should this should not fail. + CND_PRECONDITION(size >= 0, "size is too small"); + + //Call the initialize method of its superclass. The boolean value passed here + //indicates that the superclass PriorityQueue takes the responsibility to have its elements deleted + //The destructor of SegmentMergInfo will make sure that each intstance it will be closed properly + //before it is deleted + initialize(size,true); + } + + SegmentMergeQueue::~SegmentMergeQueue(){ + //Func - Destructor + // Does nothing as its parent class will clean up everything + //Pre - true + //Post - true + close(); + } + + void SegmentMergeQueue::close() { + //Func - Closes and destroyes all SegmentMergeInfo Instances in the queue + //Pre - true + //post - All SegmentMergeInfo Instances in the queue have been closed and deleted + // The queue is now empty but can still be used + + //call the clear method of the parent class PriorityQueue + clear(); + } + + bool SegmentMergeQueue::lessThan(SegmentMergeInfo* stiA, SegmentMergeInfo* stiB) { + //Func - Overloaded method that implements the lessThan operator for the parent class + // This method is used by the parent class Priority queue to reorder its internal + // data structures. This implementation check if stiA is less than the current term of stiB. + //Pre - stiA != NULL + // stiB != NULL + //Post - true is returned if stiA < stiB otherwise false + + CND_PRECONDITION(stiA != NULL, "stiA is NULL"); + CND_PRECONDITION(stiB != NULL, "stiB is NULL"); + + //Compare the two terms + int32_t comparison = stiA->term->compareTo(stiB->term); + //Check if they match + if (comparison == 0){ //todo: can we do an optimized compare here? compare using equals, then compare properly? + //If the match check if the base of stiA is smaller than the base of stiB + //Note that different bases means that the terms of stiA an stiB ly in different segments + return stiA->base < stiB->base; + }else{ + //Terms didn't match so return the difference in positions + return comparison < 0; + } + } + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/SegmentMergeQueue.h b/3rdparty/clucene/src/CLucene/index/SegmentMergeQueue.h new file mode 100644 index 000000000..faa690252 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/SegmentMergeQueue.h @@ -0,0 +1,38 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_index_SegmentMergeQueue_ +#define _lucene_index_SegmentMergeQueue_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/util/PriorityQueue.h" +#include "SegmentMergeInfo.h" + +CL_NS_DEF(index) + class SegmentMergeQueue :public CL_NS(util)::PriorityQueue > { + public: + //Constructor + //Creates a queue of length size + SegmentMergeQueue(const int32_t size); + + //Destructor + //Does nothing as its parent class will clean up everything + ~SegmentMergeQueue(); + + //Closes and destroyes all SegmentMergeInfo Instances in the queue + void close(); + protected: + //Overloaded method that implements the lessThan operator for the parent class + //This method is used by the parent class Priority queue to reorder its internal + //data structures. This implementation check if stiA is less than the current term of stiB. + bool lessThan(SegmentMergeInfo* stiA, SegmentMergeInfo* stiB); + + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/index/SegmentMerger.cpp b/3rdparty/clucene/src/CLucene/index/SegmentMerger.cpp new file mode 100644 index 000000000..40814da0c --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/SegmentMerger.cpp @@ -0,0 +1,723 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#include "CLucene/StdHeader.h" +#include "SegmentMerger.h" + +CL_NS_USE(util) +CL_NS_USE(document) +CL_NS_USE(store) +CL_NS_DEF(index) + +// File extensions of old-style index files +int COMPOUND_EXTENSIONS_LENGTH = 7; +const char* COMPOUND_EXTENSIONS = "fnm\0" "frq\0" "prx\0" "fdx\0" "fdt\0" "tii\0" "tis\0"; + +int VECTOR_EXTENSIONS_LENGTH = 3; +const char* VECTOR_EXTENSIONS = "tvx\0" "tvd\0" "tvf\0"; + +SegmentMerger::SegmentMerger(IndexWriter* writer, const QString& name) +{ + //Func - Constructor + //Pre - dir holds a valid reference to a Directory + // name != NULL + //Post - Instance has been created + + CND_PRECONDITION(!name.isEmpty(), "name is NULL"); + + freqOutput = NULL; + proxOutput = NULL; + termInfosWriter = NULL; + queue = NULL; + fieldInfos = NULL; + useCompoundFile = writer->getUseCompoundFile(); + skipBuffer = _CLNEW CL_NS(store)::RAMIndexOutput(); + + segment = name; + directory = writer->getDirectory(); + termIndexInterval = writer->getTermIndexInterval(); + + lastSkipDoc=0; + lastSkipFreqPointer=0; + lastSkipProxPointer=0; + skipInterval=0; +} + +SegmentMerger::~SegmentMerger() +{ + //Func - Destructor + //Pre - true + //Post - The instance has been destroyed + + //Clear the readers set + readers.clear(); + + //Delete field Infos + _CLDELETE(fieldInfos); + //Close and destroy the IndexOutput to the Frequency File + if (freqOutput != NULL) { + freqOutput->close(); + _CLDELETE(freqOutput); + } + //Close and destroy the IndexOutput to the Prox File + if (proxOutput != NULL) { + proxOutput->close(); + _CLDELETE(proxOutput); + } + //Close and destroy the termInfosWriter + if (termInfosWriter != NULL) { + termInfosWriter->close(); + _CLDELETE(termInfosWriter); + } + //Close and destroy the queue + if (queue != NULL) { + queue->close(); + _CLDELETE(queue); + } + //close and destory the skipBuffer + if (skipBuffer != NULL) { + skipBuffer->close(); + _CLDELETE(skipBuffer); + } +} + +void SegmentMerger::add(IndexReader* reader) +{ + //Func - Adds a IndexReader to the set of readers + //Pre - reader contains a valid reference to a IndexReader + //Post - The SegementReader reader has been added to the set of readers + + readers.push_back(reader); +} + +IndexReader* SegmentMerger::segmentReader(const int32_t i) +{ + //Func - Returns a reference to the i-th IndexReader + //Pre - 0 <= i < readers.size() + //Post - A reference to the i-th IndexReader has been returned + + CND_PRECONDITION(i >= 0, "i is a negative number"); + CND_PRECONDITION((size_t)i < readers.size(), + "i is bigger than the number of IndexReader instances"); + + //Retrieve the i-th IndexReader + IndexReader* ret = readers[i]; + CND_CONDITION(ret != NULL, "No IndexReader found"); + + return ret; +} + +int32_t SegmentMerger::merge() +{ + int32_t value = mergeFields(); + mergeTerms(); + mergeNorms(); + + if (fieldInfos->hasVectors()) + mergeVectors(); + + return value; +} + +void SegmentMerger::closeReaders() +{ + for (uint32_t i = 0; i < readers.size(); i++) { + // close readers + IndexReader* reader = readers[i]; + reader->close(); + } +} + +void SegmentMerger::createCompoundFile(const QString& filename, QStringList& files) +{ + CompoundFileWriter* cfsWriter = _CLNEW CompoundFileWriter(directory, filename); + + { //msvc6 scope fix + // Basic files + for (int32_t i = 0; i < COMPOUND_EXTENSIONS_LENGTH; i++) { + files.push_back(Misc::qjoin(segment, QLatin1String("."), + QLatin1String(COMPOUND_EXTENSIONS+(i*4)))); + } + } + + { //msvc6 scope fix + // Field norm files + for (int32_t i = 0; i < fieldInfos->size(); i++) { + FieldInfo* fi = fieldInfos->fieldInfo(i); + if (fi->isIndexed && !fi->omitNorms) { + TCHAR tbuf[10]; + char abuf[10]; + _i64tot(i, tbuf, 10); + STRCPY_TtoA(abuf, tbuf, 10); + + files.push_back(Misc::qjoin(segment, QLatin1String(".f"), + QLatin1String(abuf))); + } + } + } + + // Vector files + if (fieldInfos->hasVectors()) { + for (int32_t i = 0; i < VECTOR_EXTENSIONS_LENGTH; i++) { + files.push_back(Misc::qjoin(segment, QLatin1String("."), + QLatin1String(VECTOR_EXTENSIONS+(i*4)))); + } + } + + { //msvc6 scope fix + // Now merge all added files + for (size_t i=0;iaddFile(files[i]); + } + } + + // Perform the merge + cfsWriter->close(); + _CLDELETE(cfsWriter); +} + +void SegmentMerger::addIndexed(IndexReader* reader, FieldInfos* fieldInfos, + StringArrayWithDeletor& names, bool storeTermVectors, + bool storePositionWithTermVector, bool storeOffsetWithTermVector) +{ + StringArrayWithDeletor::const_iterator itr = names.begin(); + while (itr != names.end()) { + fieldInfos->add(*itr, true, + storeTermVectors, storePositionWithTermVector, + storeOffsetWithTermVector, !reader->hasNorms(*itr)); + ++itr; + } +} + +int32_t SegmentMerger::mergeFields() +{ + //Func - Merge the fields of all segments + //Pre - true + //Post - The field infos and field values of all segments have been merged. + + //Create a new FieldInfos + fieldInfos = _CLNEW FieldInfos(); // merge field names + + //Condition check to see if fieldInfos points to a valid instance + CND_CONDITION(fieldInfos != NULL, "Memory allocation for fieldInfos failed"); + + IndexReader* reader = NULL; + + int32_t docCount = 0; + + //Iterate through all readers + for (uint32_t i = 0; i < readers.size(); i++) { + //get the i-th reader + reader = readers[i]; + //Condition check to see if reader points to a valid instance + CND_CONDITION(reader != NULL,"No IndexReader found"); + + StringArrayWithDeletor tmp; + + tmp.clear(); + reader->getFieldNames(IndexReader::TERMVECTOR_WITH_POSITION_OFFSET, tmp); + addIndexed(reader, fieldInfos, tmp, true, true, true); + + tmp.clear(); + reader->getFieldNames(IndexReader::TERMVECTOR_WITH_POSITION, tmp); + addIndexed(reader, fieldInfos, tmp, true, true, false); + + tmp.clear(); + reader->getFieldNames(IndexReader::TERMVECTOR_WITH_OFFSET, tmp); + addIndexed(reader, fieldInfos, tmp, true, false, true); + + tmp.clear(); + reader->getFieldNames(IndexReader::TERMVECTOR, tmp); + addIndexed(reader, fieldInfos, tmp, true, false, false); + + tmp.clear(); + reader->getFieldNames(IndexReader::INDEXED, tmp); + addIndexed(reader, fieldInfos, tmp, false, false, false); + + tmp.clear(); + reader->getFieldNames(IndexReader::UNINDEXED, tmp); + if (tmp.size() > 0) { + TCHAR** arr = _CL_NEWARRAY(TCHAR*,tmp.size()+1); + tmp.toArray(arr); + fieldInfos->add((const TCHAR**)arr, false); + _CLDELETE_ARRAY(arr); + //no need to delete the contents, since tmp is responsible for it + } + } + + //Create the filename of the new FieldInfos file + QString buf = Misc::segmentname(segment, QLatin1String(".fnm")); + //Write the new FieldInfos file to the directory + fieldInfos->write(directory, buf); + + // merge field values + // Instantiate Fieldswriter which will write in directory for the segment + // name segment using the new merged fieldInfos + FieldsWriter* fieldsWriter = _CLNEW FieldsWriter(directory, segment, fieldInfos); + + //Condition check to see if fieldsWriter points to a valid instance + CND_CONDITION(fieldsWriter != NULL, "Memory allocation for fieldsWriter failed"); + + try { + IndexReader* reader = NULL; + int32_t maxDoc = 0; + //Iterate through all readers + for (uint32_t i = 0; i < readers.size(); i++) { + // get the i-th reader + reader = readers[i]; + + + // Condition check to see if reader points to a valid instance + CND_CONDITION(reader != NULL, "No IndexReader found"); + + // Get the total number documents including the documents that have + // been marked deleted + int32_t maxDoc = reader->maxDoc(); + + //document buffer + Document doc; + + //Iterate through all the documents managed by the current reader + for (int32_t j = 0; j < maxDoc; j++) { + //Check if the j-th document has been deleted, if so skip it + if (!reader->isDeleted(j)) { + //Get the document + if (reader->document(j, &doc)) { + //Add the document to the new FieldsWriter + fieldsWriter->addDocument(&doc); + docCount++; + //doc is cleard for re-use + doc.clear(); + } + } + } + } + } _CLFINALLY ( + //Close the fieldsWriter + fieldsWriter->close(); + //And have it deleted as it not used any more + _CLDELETE(fieldsWriter); + ); + + return docCount; +} + +void SegmentMerger::mergeVectors() +{ + TermVectorsWriter* termVectorsWriter = + _CLNEW TermVectorsWriter(directory, segment, fieldInfos); + + try { + for (uint32_t r = 0; r < readers.size(); r++) { + IndexReader* reader = readers[r]; + int32_t maxDoc = reader->maxDoc(); + for (int32_t docNum = 0; docNum < maxDoc; docNum++) { + // skip deleted docs + if (reader->isDeleted(docNum)) + continue; + + Array tmp; + if (reader->getTermFreqVectors(docNum, tmp)) + termVectorsWriter->addAllDocVectors(tmp); + tmp.deleteAll(); + } + } + } _CLFINALLY ( + _CLDELETE(termVectorsWriter); + ); +} + + +void SegmentMerger::mergeTerms() +{ + //Func - Merge the terms of all segments + //Pre - fieldInfos != NULL + //Post - The terms of all segments have been merged + + CND_PRECONDITION(fieldInfos != NULL, "fieldInfos is NULL"); + + try{ + //create a filename for the new Frequency File for segment + QString buf = Misc::segmentname(segment, QLatin1String(".frq")); + //Open an IndexOutput to the new Frequency File + freqOutput = directory->createOutput(buf); + + //create a filename for the new Prox File for segment + buf = Misc::segmentname(segment, QLatin1String(".prx")); + //Open an IndexOutput to the new Prox File + proxOutput = directory->createOutput(buf); + + //Instantiate a new termInfosWriter which will write in directory + //for the segment name segment using the new merged fieldInfos + termInfosWriter = _CLNEW TermInfosWriter(directory, segment, fieldInfos, + termIndexInterval); + + //Condition check to see if termInfosWriter points to a valid instance + CND_CONDITION(termInfosWriter != NULL, + "Memory allocation for termInfosWriter failed"); + + skipInterval = termInfosWriter->skipInterval; + queue = _CLNEW SegmentMergeQueue(readers.size()); + + //And merge the Term Infos + mergeTermInfos(); + } _CLFINALLY ( + //Close and destroy the IndexOutput to the Frequency File + if (freqOutput != NULL) { + freqOutput->close(); _CLDELETE(freqOutput); + } + + //Close and destroy the IndexOutput to the Prox File + if (proxOutput != NULL) + { + proxOutput->close(); + _CLDELETE(proxOutput); + } + + //Close and destroy the termInfosWriter + if (termInfosWriter != NULL) { + termInfosWriter->close(); + _CLDELETE(termInfosWriter); + } + + //Close and destroy the queue + if (queue != NULL) { + queue->close(); + _CLDELETE(queue); + } + ); +} + +void SegmentMerger::mergeTermInfos() +{ + //Func - Merges all TermInfos into a single segment + //Pre - true + //Post - All TermInfos have been merged into a single segment + + //Condition check to see if queue points to a valid instance + CND_CONDITION(queue != NULL, "Memory allocation for queue failed"); + + //base is the id of the first document in a segment + int32_t base = 0; + + IndexReader* reader = NULL; + SegmentMergeInfo* smi = NULL; + + //iterate through all the readers + for (uint32_t i = 0; i < readers.size(); i++) { + //Get the i-th reader + reader = readers[i]; + + //Condition check to see if reader points to a valid instance + CND_CONDITION(reader != NULL, "No IndexReader found"); + + //Get the term enumeration of the reader + TermEnum* termEnum = reader->terms(); + //Instantiate a new SegmentMerginfo for the current reader and enumeration + smi = _CLNEW SegmentMergeInfo(base, termEnum, reader); + + //Condition check to see if smi points to a valid instance + CND_CONDITION(smi != NULL, "Memory allocation for smi failed") ; + + //Increase the base by the number of documents that have not been marked deleted + //so base will contain a new value for the first document of the next iteration + base += reader->numDocs(); + //Get the next current term + if (smi->next()) { + //Store the SegmentMergeInfo smi with the initialized SegmentTermEnum TermEnum + //into the queue + queue->put(smi); + } else { + //Apparently the end of the TermEnum of the SegmentTerm has been reached so + //close the SegmentMergeInfo smi + smi->close(); + //And destroy the instance and set smi to NULL (It will be used later in this method) + _CLDELETE(smi); + } + } + + //Instantiate an array of SegmentMergeInfo instances called match + SegmentMergeInfo** match = _CL_NEWARRAY(SegmentMergeInfo*,readers.size()+1); + + //Condition check to see if match points to a valid instance + CND_CONDITION(match != NULL, "Memory allocation for match failed") ; + + SegmentMergeInfo* top = NULL; + + //As long as there are SegmentMergeInfo instances stored in the queue + while (queue->size() > 0) { + int32_t matchSize = 0; + + // pop matching terms + + //Pop the first SegmentMergeInfo from the queue + match[matchSize++] = queue->pop(); + //Get the Term of match[0] + Term* term = match[0]->term; + + //Condition check to see if term points to a valid instance + CND_CONDITION(term != NULL,"term is NULL") ; + + //Get the current top of the queue + top = queue->top(); + + //For each SegmentMergInfo still in the queue + //Check if term matches the term of the SegmentMergeInfo instances in the queue + while (top != NULL && term->equals(top->term)) { + //A match has been found so add the matching SegmentMergeInfo to the match array + match[matchSize++] = queue->pop(); + //Get the next SegmentMergeInfo + top = queue->top(); + } + match[matchSize]=NULL; + + //add new TermInfo + mergeTermInfo(match); //matchSize + + //Restore the SegmentTermInfo instances in the match array back into the queue + while (matchSize > 0) { + smi = match[--matchSize]; + + //Condition check to see if smi points to a valid instance + CND_CONDITION(smi != NULL, "smi is NULL"); + + //Move to the next term in the enumeration of SegmentMergeInfo smi + if (smi->next()) { + //There still are some terms so restore smi in the queue + queue->put(smi); + + } else { + //Done with a segment + //No terms anymore so close this SegmentMergeInfo instance + smi->close(); + _CLDELETE(smi); + } + } + } + + _CLDELETE_ARRAY(match); +} + +void SegmentMerger::mergeTermInfo(SegmentMergeInfo** smis) +{ + //Func - Merge the TermInfo of a term found in one or more segments. + //Pre - smis != NULL and it contains segments that are positioned at the same term. + // n is equal to the number of SegmentMergeInfo instances in smis + // freqOutput != NULL + // proxOutput != NULL + //Post - The TermInfo of a term has been merged + + CND_PRECONDITION(smis != NULL, "smis is NULL"); + CND_PRECONDITION(freqOutput != NULL, "freqOutput is NULL"); + CND_PRECONDITION(proxOutput != NULL, "proxOutput is NULL"); + + //Get the file pointer of the IndexOutput to the Frequency File + int64_t freqPointer = freqOutput->getFilePointer(); + //Get the file pointer of the IndexOutput to the Prox File + int64_t proxPointer = proxOutput->getFilePointer(); + + //Process postings from multiple segments all positioned on the same term. + int32_t df = appendPostings(smis); + + int64_t skipPointer = writeSkip(); + + //df contains the number of documents across all segments where this term was found + if (df > 0) { + //add an entry to the dictionary with pointers to prox and freq files + termInfo.set(df, freqPointer, proxPointer, (int32_t)(skipPointer - freqPointer)); + //Precondition check for to be sure that the reference to + //smis[0]->term will be valid + CND_PRECONDITION(smis[0]->term != NULL, "smis[0]->term is NULL"); + //Write a new TermInfo + termInfosWriter->add(smis[0]->term, &termInfo); + } +} + + +int32_t SegmentMerger::appendPostings(SegmentMergeInfo** smis) +{ + //Func - Process postings from multiple segments all positioned on the + // same term. Writes out merged entries into freqOutput and + // the proxOutput streams. + //Pre - smis != NULL and it contains segments that are positioned at the same term. + // n is equal to the number of SegmentMergeInfo instances in smis + // freqOutput != NULL + // proxOutput != NULL + //Post - Returns number of documents across all segments where this term was found + + CND_PRECONDITION(smis != NULL, "smis is NULL"); + CND_PRECONDITION(freqOutput != NULL, "freqOutput is NULL"); + CND_PRECONDITION(proxOutput != NULL, "proxOutput is NULL"); + + int32_t lastDoc = 0; + int32_t df = 0; //Document Counter + + resetSkip(); + SegmentMergeInfo* smi = NULL; + + //Iterate through all SegmentMergeInfo instances in smis + int32_t i = 0; + while ((smi=smis[i]) != NULL) { + //Get the i-th SegmentMergeInfo + + //Condition check to see if smi points to a valid instance + CND_PRECONDITION(smi != NULL, " is NULL"); + + //Get the term positions + TermPositions* postings = smi->getPositions(); + //Get the base of this segment + int32_t base = smi->base; + //Get the docMap so we can see which documents have been deleted + int32_t* docMap = smi->getDocMap(); + //Seek the termpost + postings->seek(smi->termEnum); + while (postings->next()) { + int32_t doc = postings->doc(); + //Check if there are deletions + if (docMap != NULL) + doc = docMap[doc]; // map around deletions + doc += base; // convert to merged space + + //Condition check to see doc is eaqual to or bigger than lastDoc + CND_CONDITION(doc >= lastDoc,"docs out of order"); + + //Increase the total frequency over all segments + df++; + + if ((df % skipInterval) == 0) { + bufferSkip(lastDoc); + } + + //Calculate a new docCode + //use low bit to flag freq=1 + int32_t docCode = (doc - lastDoc) << 1; + lastDoc = doc; + + //Get the frequency of the Term + int32_t freq = postings->freq(); + if (freq == 1) { + //write doc & freq=1 + freqOutput->writeVInt(docCode | 1); + } else { + //write doc + freqOutput->writeVInt(docCode); + //write frequency in doc + freqOutput->writeVInt(freq); + } + + int32_t lastPosition = 0; + // write position deltas + for (int32_t j = 0; j < freq; j++) { + //Get the next position + int32_t position = postings->nextPosition(); + //Write the difference between position and the last position + proxOutput->writeVInt(position - lastPosition); + lastPosition = position; + } + } + + i++; + } + + //Return total number of documents across all segments where term was found + return df; +} + +void SegmentMerger::resetSkip() +{ + skipBuffer->reset(); + lastSkipDoc = 0; + lastSkipFreqPointer = freqOutput->getFilePointer(); + lastSkipProxPointer = proxOutput->getFilePointer(); +} + +void SegmentMerger::bufferSkip(int32_t doc) +{ + int64_t freqPointer = freqOutput->getFilePointer(); + int64_t proxPointer = proxOutput->getFilePointer(); + + skipBuffer->writeVInt(doc - lastSkipDoc); + skipBuffer->writeVInt((int32_t) (freqPointer - lastSkipFreqPointer)); + skipBuffer->writeVInt((int32_t) (proxPointer - lastSkipProxPointer)); + + lastSkipDoc = doc; + lastSkipFreqPointer = freqPointer; + lastSkipProxPointer = proxPointer; +} + +int64_t SegmentMerger::writeSkip() +{ + int64_t skipPointer = freqOutput->getFilePointer(); + skipBuffer->writeTo(freqOutput); + return skipPointer; +} + +// Func - Merges the norms for all fields +// Pre - fieldInfos != NULL +// Post - The norms for all fields have been merged +void SegmentMerger::mergeNorms() +{ + CND_PRECONDITION(fieldInfos != NULL, "fieldInfos is NULL"); + + //iterate through all the Field Infos instances + for (int32_t i = 0; i < fieldInfos->size(); i++) { + //Get the i-th FieldInfo + FieldInfo* fi = fieldInfos->fieldInfo(i); + //Is this Field indexed? + if (fi->isIndexed && !fi->omitNorms) { + //Create and Instantiate an IndexOutput to that norm file + QString buf = Misc::segmentname(segment, QLatin1String(".f"), i); + IndexOutput* output = directory->createOutput(buf); + + //Condition check to see if output points to a valid instance + CND_CONDITION(output != NULL, "No Outputstream retrieved"); + + uint8_t* input = NULL; + try { + for (uint32_t j = 0; j < readers.size(); ++j) { + // get the next index reader + condition check + IndexReader* reader = readers[j]; + CND_CONDITION(reader != NULL, "No reader found"); + + // Get the total number of documents including the documents + // that have been marked deleted + int32_t maxDoc = reader->maxDoc(); + if (maxDoc > 0) { + // if there are docs, allocate buffer to read it's norms + uint8_t* data = (uint8_t*)realloc(input, maxDoc * + sizeof(uint8_t)); + if (data) { + input = data; + memset(input, 0, maxDoc * sizeof(uint8_t)); + // Get an IndexInput to the norm file for this + // field in this segment + reader->norms(fi->name, input); + + //Iterate through all the documents + for(int32_t k = 0; k < maxDoc; k++) { + //Check if document k is deleted + if (!reader->isDeleted(k)) { + //write the new norm + output->writeByte(input[k]); + } + } + } + } + } + } _CLFINALLY ( + if (output != NULL) { + output->close(); + _CLDELETE(output); + } + free(input); + ); + } + } +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/SegmentMerger.h b/3rdparty/clucene/src/CLucene/index/SegmentMerger.h new file mode 100644 index 000000000..230843b00 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/SegmentMerger.h @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#ifndef _lucene_index_SegmentMerger_ +#define _lucene_index_SegmentMerger_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include "CLucene/store/Directory.h" +#include "CLucene/store/RAMDirectory.h" +#include "CLucene/util/VoidList.h" +#include "SegmentMergeInfo.h" +#include "SegmentMergeQueue.h" +#include "IndexWriter.h" +#include "FieldInfos.h" +#include "FieldsWriter.h" +#include "TermInfosWriter.h" + +CL_NS_DEF(index) + +/** +* The SegmentMerger class combines two or more Segments, represented by an IndexReader ({@link #add}, +* into a single Segment. After adding the appropriate readers, call the merge method to combine the +* segments. +*

+* If the compoundFile flag is set, then the segments will be merged into a compound file. +* +* +* @see #merge +* @see #add +*/ +class SegmentMerger : LUCENE_BASE +{ + bool useCompoundFile; + + CL_NS(store)::RAMIndexOutput* skipBuffer; + int32_t lastSkipDoc; + int64_t lastSkipFreqPointer; + int64_t lastSkipProxPointer; + + void resetSkip(); + void bufferSkip(int32_t doc); + int64_t writeSkip(); + + //Directory of the segment + CL_NS(store)::Directory* directory; + //name of the new segment + QString segment; + //Set of IndexReaders + CL_NS(util)::CLVector > readers; + //Field Infos for t he FieldInfo instances of all fields + FieldInfos* fieldInfos; + + //The queue that holds SegmentMergeInfo instances + SegmentMergeQueue* queue; + //IndexOutput to the new Frequency File + CL_NS(store)::IndexOutput* freqOutput; + //IndexOutput to the new Prox File + CL_NS(store)::IndexOutput* proxOutput; + //Writes Terminfos that have been merged + TermInfosWriter* termInfosWriter; + TermInfo termInfo; //(new) minimize consing + + int32_t termIndexInterval; + int32_t skipInterval; + +public: + /** + * + * @param dir The Directory to merge the other segments into + * @param name The name of the new segment + * @param compoundFile true if the new segment should use a compoundFile + */ + SegmentMerger( IndexWriter* writer, const QString& name ); + + //Destructor + ~SegmentMerger(); + + /** + * Add an IndexReader to the collection of readers that are to be merged + * @param reader + */ + void add(IndexReader* reader); + + /** + * + * @param i The index of the reader to return + * @return The ith reader to be merged + */ + IndexReader* segmentReader(const int32_t i); + + /** + * Merges the readers specified by the {@link #add} method into the + * directory passed to the constructor + * @return The number of documents that were merged + * @throws IOException + */ + int32_t merge(); + /** + * close all IndexReaders that have been added. + * Should not be called before merge(). + * @throws IOException + */ + void closeReaders(); +private: + void addIndexed(IndexReader* reader, FieldInfos* fieldInfos, + CL_NS(util)::StringArrayWithDeletor& names, + bool storeTermVectors, bool storePositionWithTermVector, + bool storeOffsetWithTermVector); + + /** + * Merge the fields of all segments + * @return The number of documents in all of the readers + * @throws IOException + */ + int32_t mergeFields(); + + /** + * Merge the TermVectors from each of the segments into the new one. + * @throws IOException + */ + void mergeVectors(); + + /** Merge the terms of all segments */ + void mergeTerms(); + + /** Merges all TermInfos into a single segment */ + void mergeTermInfos(); + + /** Merge one term found in one or more segments. The array smis + * contains segments that are positioned at the same term. N + * is the number of cells in the array actually occupied. + * + * @param smis array of segments + * @param n number of cells in the array actually occupied + */ + void mergeTermInfo( SegmentMergeInfo** smis); + + /** Process postings from multiple segments all positioned on the + * same term. Writes out merged entries into freqOutput and + * the proxOutput streams. + * + * @param smis array of segments + * @param n number of cells in the array actually occupied + * @return number of documents across all segments where this term was found + */ + int32_t appendPostings(SegmentMergeInfo** smis); + + //Merges the norms for all fields + void mergeNorms(); + + void createCompoundFile(const QString& filename, QStringList& files); + friend class IndexWriter; //allow IndexWriter to use createCompoundFile +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/index/SegmentReader.cpp b/3rdparty/clucene/src/CLucene/index/SegmentReader.cpp new file mode 100644 index 000000000..ba061714b --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/SegmentReader.cpp @@ -0,0 +1,816 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +*/ +#include "CLucene/StdHeader.h" +#include "SegmentHeader.h" + +#include "FieldInfos.h" +#include "FieldsReader.h" +#include "IndexReader.h" +#include "TermInfosReader.h" +#include "Terms.h" +#include "CLucene/search/Similarity.h" + +CL_NS_USE(util) +CL_NS_USE(store) +CL_NS_USE(document) +CL_NS_USE(search) +CL_NS_DEF(index) + +SegmentReader::Norm::Norm(IndexInput* instrm, int32_t n, SegmentReader* r, + const QString& seg) + : number(n) + , reader(r) + , segment(seg) + , in(instrm) + , bytes(NULL) + , dirty(false) +{ + //Func - Constructor + //Pre - instrm is a valid reference to an IndexInput + //Post - A Norm instance has been created with an empty bytes array + bytes = NULL; + dirty = false; +} + +SegmentReader::Norm::~Norm() +{ + //Func - Destructor + //Pre - true + //Post - The IndexInput in has been deleted (and closed by its destructor) + // and the array too. + + //Close and destroy the inputstream in-> The inputstream will be closed + // by its destructor. Note that the IndexInput 'in' actually is a pointer!!!!! + _CLDELETE(in); + + //Delete the bytes array + _CLDELETE_ARRAY(bytes); + +} + +void SegmentReader::Norm::reWrite() +{ + QString buf(segment + QLatin1String(".tmp")); + + // NOTE: norms are re-written in regular directory, not cfs + IndexOutput* out = reader->getDirectory()->createOutput(buf); + try { + out->writeBytes(bytes, reader->maxDoc()); + } _CLFINALLY ( + out->close(); + _CLDELETE(out) + ); + + QString fileName(segment); + if (reader->cfsReader == NULL) + fileName.append(QLatin1String(".f%1")).arg(number); + else // use a different file name if we have compound format + fileName.append(QLatin1String(".s%1")).arg(number); + + reader->getDirectory()->renameFile(buf, fileName); + this->dirty = false; +} + +SegmentReader::SegmentReader(SegmentInfo* si) + : IndexReader(si->getDir()) + , _norms(false, false) +{ + initialize(si); +} + +SegmentReader::SegmentReader(SegmentInfos* sis, SegmentInfo* si) + : IndexReader(si->getDir(), sis, false) + , _norms(false, false) +{ + initialize(si); +} + +void SegmentReader::initialize(SegmentInfo* si) +{ + //Pre - si-> is a valid reference to SegmentInfo instance + // identified by si-> + //Post - All files of the segment have been read + + deletedDocs = NULL; + ones = NULL; + //There are no documents yet marked as deleted + deletedDocsDirty = false; + + normsDirty=false; + undeleteAll=false; + + //Duplicate the name of the segment from SegmentInfo to segment + segment = si->name; + // make sure that all index files have been read or are kept open + // so that if an index update removes them we'll still have them + freqStream = NULL; + proxStream = NULL; + + //instantiate a buffer large enough to hold a directory path + QString buf; + + // Use compound file directory for some files, if it exists + Directory* cfsDir = getDirectory(); + SegmentName(buf, CL_MAX_PATH, QLatin1String(".cfs")); + if (cfsDir->fileExists(buf)) { + cfsReader = _CLNEW CompoundFileReader(cfsDir, buf); + cfsDir = cfsReader; + }else + cfsReader = NULL; + + // Create the name of the field info file with suffix .fnm in buf + SegmentName(buf, CL_MAX_PATH, QLatin1String(".fnm")); + fieldInfos = _CLNEW FieldInfos(cfsDir, buf ); + + // Condition check to see if fieldInfos points to a valid instance + CND_CONDITION(fieldInfos != NULL, + "No memory could be allocated for fieldInfos"); + + // Create the name of the frequence file with suffix .frq in buf + SegmentName(buf ,CL_MAX_PATH, QLatin1String(".frq")); + + // Open an IndexInput freqStream to the frequency file + freqStream = cfsDir->openInput( buf ); + + // Condition check to see if freqStream points to a valid instance and was + // able to open the frequency file + CND_CONDITION(freqStream != NULL, + "IndexInput freqStream could not open the frequency file"); + + // Create the name of the prox file with suffix .prx in buf + SegmentName(buf, CL_MAX_PATH, QLatin1String(".prx")); + + // Open an IndexInput proxStream to the prox file + proxStream = cfsDir->openInput( buf ); + + // Condition check to see if proxStream points to a valid instance and was + // able to open the prox file + CND_CONDITION(proxStream != NULL, + "IndexInput proxStream could not open proximity file"); + + // Instantiate a FieldsReader for reading the Field Info File + fieldsReader = _CLNEW FieldsReader(cfsDir, segment, fieldInfos); + + // Condition check to see if fieldsReader points to a valid instance + CND_CONDITION(fieldsReader != NULL, + "No memory could be allocated for fieldsReader"); + + //Instantiate a TermInfosReader for reading the Term Dictionary .tis file + tis = _CLNEW TermInfosReader(cfsDir, segment, fieldInfos); + + //Condition check to see if tis points to a valid instance + CND_CONDITION(tis != NULL,"No memory could be allocated for tis"); + + // Check if the segment has deletion according to the SegmentInfo instance + // si-> NOTE: the bitvector is stored using the regular directory, not cfs + if (hasDeletions(si)) { + //Create a deletion file with suffix .del + SegmentName(buf, CL_MAX_PATH, QLatin1String(".del")); + // Instantiate a BitVector that manages which documents have been deleted + deletedDocs = _CLNEW BitSet(getDirectory(), buf); + } + + // Open the norm file. There's a norm file for each indexed field with a + // byte for each document. The .f[0-9]* file contains, for each document, + // a byte that encodes a value that is multiplied into the score for hits + // on that field + openNorms(cfsDir); + + termVectorsReaderOrig = NULL; + if (fieldInfos->hasVectors()) // open term vector files only as needed + termVectorsReaderOrig = _CLNEW TermVectorsReader(cfsDir, segment, fieldInfos); +} + +SegmentReader::~SegmentReader() +{ + //Func - Destructor. + //Pre - doClose has been invoked! + //Post - the instance has been destroyed + + doClose(); //this means that index reader doesn't need to be closed manually + + _CLDELETE(fieldInfos); + _CLDELETE(fieldsReader); + _CLDELETE(tis); + _CLDELETE(freqStream); + _CLDELETE(proxStream); + _CLDELETE(deletedDocs); + _CLDELETE_ARRAY(ones); + _CLDELETE(termVectorsReaderOrig); + _CLDECDELETE(cfsReader); +} + +void SegmentReader::doCommit() +{ + QString bufdel(segment + QLatin1String(".del")); + + if (deletedDocsDirty) { // re-write deleted + QString buftmp(segment + QLatin1String(".tmp")); + deletedDocs->write(getDirectory(), buftmp); + getDirectory()->renameFile(buftmp, bufdel); + } + + if(undeleteAll && getDirectory()->fileExists(bufdel)) + getDirectory()->deleteFile(bufdel, true); + + if (normsDirty) { // re-write norms + NormsType::iterator itr = _norms.begin(); + while (itr != _norms.end()) { + Norm* norm = itr->second; + if (norm->dirty) { + norm->reWrite(); + } + ++itr; + } + } + deletedDocsDirty = false; + normsDirty = false; + undeleteAll = false; +} + +void SegmentReader::doClose() +{ + //Func - Closes all streams to the files of a single segment + //Pre - fieldsReader != NULL + // tis != NULL + //Post - All streams to files have been closed + + CND_PRECONDITION(fieldsReader != NULL, "fieldsReader is NULL"); + CND_PRECONDITION(tis != NULL, "tis is NULL"); + + //Close the fieldsReader + fieldsReader->close(); + //Close the TermInfosReader + tis->close(); + + //Close the frequency stream + if (freqStream != NULL){ + freqStream->close(); + } + //Close the prox stream + if (proxStream != NULL){ + proxStream->close(); + } + + //Close the norm file + closeNorms(); + + if (termVectorsReaderOrig != NULL) + termVectorsReaderOrig->close(); + + if (cfsReader != NULL) + cfsReader->close(); +} + +bool SegmentReader::hasDeletions() const +{ + return deletedDocs != NULL; +} + +//static +bool SegmentReader::usesCompoundFile(SegmentInfo* si) +{ + return si->getDir()->fileExists(si->name + QLatin1String(".cfs")); +} + +//static +bool SegmentReader::hasSeparateNorms(SegmentInfo* si) +{ + QString pattern(si->name); + pattern.append(QLatin1String(".s")); + size_t patternLength = pattern.length(); + + QStringList names = si->getDir()->list(); + foreach (const QString& name, names) { + int length = name.length(); + if (length > patternLength && name.left(patternLength) == pattern) { + if (name.at(patternLength) >= QLatin1Char('0') + && name.at(patternLength) <= QLatin1Char('9')) { + return true; + } + } + } + return false; +} + +bool SegmentReader::hasDeletions(const SegmentInfo* si) +{ + //Func - Static method + // Checks if a segment managed by SegmentInfo si-> has deletions + //Pre - si-> holds a valid reference to an SegmentInfo instance + //Post - if the segement contains deleteions true is returned otherwise flas + + //Check if the deletion file exists and return the result + QString f; + Misc::segmentname(f, CL_MAX_PATH, si->name, QLatin1String(".del"), -1); + return si->getDir()->fileExists(f); +} + +//synchronized +void SegmentReader::doDelete(const int32_t docNum) +{ + //Func - Marks document docNum as deleted + //Pre - docNum >=0 and DocNum < maxDoc() + // docNum contains the number of the document that must be + // marked deleted + //Post - The document identified by docNum has been marked deleted + + SCOPED_LOCK_MUTEX(THIS_LOCK) + + CND_PRECONDITION(docNum >= 0, "docNum is a negative number"); + CND_PRECONDITION(docNum < maxDoc(), + "docNum is bigger than the total number of documents"); + + //Check if deletedDocs exists + if (deletedDocs == NULL) { + deletedDocs = _CLNEW BitSet(maxDoc()); + + //Condition check to see if deletedDocs points to a valid instance + CND_CONDITION(deletedDocs != NULL, + "No memory could be allocated for deletedDocs"); + } + //Flag that there are documents marked deleted + deletedDocsDirty = true; + undeleteAll = false; + //Mark document identified by docNum as deleted + deletedDocs->set(docNum); + +} + +void SegmentReader::doUndeleteAll() +{ + _CLDELETE(deletedDocs); + deletedDocsDirty = false; + undeleteAll = true; +} + +void SegmentReader::files(QStringList& retarray) +{ + //Func - Returns all file names managed by this SegmentReader + //Pre - segment != NULL + //Post - All filenames managed by this SegmentRead have been returned + + CND_PRECONDITION(segment != NULL, "segment is NULL"); + + QString temp; + #define _ADD_SEGMENT(ext) \ + temp = SegmentName(ext); \ + if (getDirectory()->fileExists(temp)) \ + retarray.push_back(temp); + + //Add the name of the Field Info file + _ADD_SEGMENT(QLatin1String(".cfs")); + _ADD_SEGMENT(QLatin1String(".fnm")); + _ADD_SEGMENT(QLatin1String(".fdx")); + _ADD_SEGMENT(QLatin1String(".fdt")); + _ADD_SEGMENT(QLatin1String(".tii")); + _ADD_SEGMENT(QLatin1String(".tis")); + _ADD_SEGMENT(QLatin1String(".frq")); + _ADD_SEGMENT(QLatin1String(".prx")); + _ADD_SEGMENT(QLatin1String(".del")); + _ADD_SEGMENT(QLatin1String(".tvx")); + _ADD_SEGMENT(QLatin1String(".tvd")); + _ADD_SEGMENT(QLatin1String(".tvf")); + _ADD_SEGMENT(QLatin1String(".tvp")); + + //iterate through the field infos + for (int32_t i = 0; i < fieldInfos->size(); ++i) { + //Get the field info for the i-th field + FieldInfo* fi = fieldInfos->fieldInfo(i); + //Check if the field has been indexed + if (fi->isIndexed && !fi->omitNorms) { + QString name; + if (cfsReader == NULL) + name = SegmentName(QLatin1String(".f"), i); + else + name = SegmentName(QLatin1String(".s"), i); + + //The field has been indexed so add its norm file + if (getDirectory()->fileExists(name)) + retarray.push_back(name); + } + } +} + +TermEnum* SegmentReader::terms() const +{ + //Func - Returns an enumeration of all the Terms and TermInfos in the set. + //Pre - tis != NULL + //Post - An enumeration of all the Terms and TermInfos in the set has been returned + + CND_PRECONDITION(tis != NULL, "tis is NULL"); + + return tis->terms(); +} + +TermEnum* SegmentReader::terms(const Term* t) const +{ + //Func - Returns an enumeration of terms starting at or after the named term t + //Pre - t != NULL + // tis != NULL + //Post - An enumeration of terms starting at or after the named term t + + CND_PRECONDITION(t != NULL, "t is NULL"); + CND_PRECONDITION(tis != NULL, "tis is NULL"); + + return tis->terms(t); +} + +bool SegmentReader::document(int32_t n, Document* doc) +{ + //Func - Returns a document identified by n + //Pre - n >=0 and identifies the document n + //Post - if the document has been deleted then an exception has been thrown + // otherwise a reference to the found document has been returned + + SCOPED_LOCK_MUTEX(THIS_LOCK) + + CND_PRECONDITION(n >= 0, "n is a negative number"); + + //Check if the n-th document has been marked deleted + if (isDeleted(n)) + _CLTHROWA(CL_ERR_InvalidState, "attempt to access a deleted document" ); + + //Retrieve the n-th document + return fieldsReader->doc(n, doc); +} + +bool SegmentReader::isDeleted(const int32_t n) +{ + //Func - Checks if the n-th document has been marked deleted + //Pre - n >=0 and identifies the document n + //Post - true has been returned if document n has been deleted otherwise fralse + + SCOPED_LOCK_MUTEX(THIS_LOCK) + + CND_PRECONDITION(n >= 0, "n is a negative number"); + + //Is document n deleted + return (deletedDocs != NULL && deletedDocs->get(n)); +} + +TermDocs* SegmentReader::termDocs() const +{ + //Func - Returns an unpositioned TermDocs enumerator. + //Pre - true + //Post - An unpositioned TermDocs enumerator has been returned + + return _CLNEW SegmentTermDocs(this); +} + +TermPositions* SegmentReader::termPositions() const +{ + //Func - Returns an unpositioned TermPositions enumerator. + //Pre - true + //Post - An unpositioned TermPositions enumerator has been returned + + return _CLNEW SegmentTermPositions(this); +} + +int32_t SegmentReader::docFreq(const Term* t) const +{ + //Func - Returns the number of documents which contain the term t + //Pre - t holds a valid reference to a Term + //Post - The number of documents which contain term t has been returned + + //Get the TermInfo ti for Term t in the set + TermInfo* ti = tis->get(t); + //Check if an TermInfo has been returned + if (ti) { + //Get the frequency of the term + int32_t ret = ti->docFreq; + //TermInfo ti is not needed anymore so delete it + _CLDELETE( ti ); + //return the number of documents which containt term t + return ret; + } + + //No TermInfo returned so return 0 + return 0; +} + +int32_t SegmentReader::numDocs() +{ + //Func - Returns the actual number of documents in the segment + //Pre - true + //Post - The actual number of documents in the segments + + //Get the number of all the documents in the segment including the ones that have + //been marked deleted + int32_t n = maxDoc(); + + //Check if there any deleted docs + if (deletedDocs != NULL) + //Substract the number of deleted docs from the number returned by maxDoc + n -= deletedDocs->count(); + + //return the actual number of documents in the segment + return n; +} + +int32_t SegmentReader::maxDoc() const +{ + //Func - Returns the number of all the documents in the segment including + // the ones that have been marked deleted + //Pre - true + //Post - The total number of documents in the segment has been returned + + return fieldsReader->size(); +} + +void SegmentReader::getFieldNames(FieldOption fldOption, + StringArrayWithDeletor& retarray) +{ + size_t len = fieldInfos->size(); + for (size_t i = 0; i < len; i++) { + bool v = false; + FieldInfo* fi = fieldInfos->fieldInfo(i); + if (fldOption & IndexReader::ALL) { + v = true; + } else { + if (!fi->isIndexed && (fldOption & IndexReader::UNINDEXED)) { + v = true; + } + + if (fi->isIndexed && (fldOption & IndexReader::INDEXED)) { + v = true; + } + + if (fi->isIndexed && fi->storeTermVector == false + && (fldOption & IndexReader::INDEXED_NO_TERMVECTOR)) { + v = true; + } + + if ((fldOption & IndexReader::TERMVECTOR) + && fi->storeTermVector == true + && fi->storePositionWithTermVector == false + && fi->storeOffsetWithTermVector == false) { + v = true; + } + + if (fi->isIndexed && fi->storeTermVector + && (fldOption & IndexReader::INDEXED_WITH_TERMVECTOR)) { + v = true; + } + + if (fi->storePositionWithTermVector + && fi->storeOffsetWithTermVector == false + && (fldOption & IndexReader::TERMVECTOR_WITH_POSITION)) { + v = true; + } + + if (fi->storeOffsetWithTermVector + && fi->storePositionWithTermVector == false + && (fldOption & IndexReader::TERMVECTOR_WITH_OFFSET)) { + v = true; + } + + if ((fi->storeOffsetWithTermVector && fi->storePositionWithTermVector) + && (fldOption & IndexReader::TERMVECTOR_WITH_POSITION_OFFSET)) { + v = true; + } + } + + if (v) + retarray.push_back(STRDUP_TtoT(fi->name)); + } +} + +bool SegmentReader::hasNorms(const TCHAR* field) const +{ + return _norms.find(field) != _norms.end(); +} + + +void SegmentReader::norms(const TCHAR* field, uint8_t* bytes) +{ + //Func - Reads the Norms for field from disk starting at offset in the inputstream + //Pre - field != NULL + // bytes != NULL is an array of bytes which is to be used to read the norms into. + // it is advisable to have bytes initalized by zeroes! + //Post - The if an inputstream to the norm file could be retrieved the bytes have been read + // You are never sure whether or not the norms have been read into bytes properly!!!!!!!!!!!!!!!!! + + CND_PRECONDITION(field != NULL, "field is NULL"); + CND_PRECONDITION(bytes != NULL, "field is NULL"); + + SCOPED_LOCK_MUTEX(THIS_LOCK) + + Norm* norm = _norms.get(field); + if ( norm == NULL ){ + memcpy(bytes, fakeNorms(), maxDoc()); + return; + } + + if (norm->bytes != NULL) { // can copy from cache + memcpy(bytes, norm->bytes, maxDoc()); + return; + } + + IndexInput* _normStream = norm->in->clone(); + CND_PRECONDITION(_normStream != NULL, "normStream==NULL") + + // read from disk + try { + _normStream->seek(0); + _normStream->readBytes(bytes, maxDoc()); + } _CLFINALLY ( + //Have the normstream closed + _normStream->close(); + //Destroy the normstream + _CLDELETE( _normStream ); + ); +} + +uint8_t* SegmentReader::createFakeNorms(int32_t size) +{ + uint8_t* ones = _CL_NEWARRAY(uint8_t,size); + memset(ones, DefaultSimilarity::encodeNorm(1.0f), size); + return ones; +} + +uint8_t* SegmentReader::fakeNorms() +{ + if (ones == NULL) + ones = createFakeNorms(maxDoc()); + return ones; +} + +// can return null if norms aren't stored +uint8_t* SegmentReader::getNorms(const TCHAR* field) +{ + SCOPED_LOCK_MUTEX(THIS_LOCK) + Norm* norm = _norms.get(field); + if (norm == NULL) + return NULL; // not indexed, or norms not stored + + if (norm->bytes == NULL) { // value not yet read + uint8_t* bytes = _CL_NEWARRAY(uint8_t, maxDoc()); + norms(field, bytes); + norm->bytes = bytes; // cache it + } + return norm->bytes; +} + +uint8_t* SegmentReader::norms(const TCHAR* field) +{ + //Func - Returns the bytes array that holds the norms of a named field + //Pre - field != NULL and contains the name of the field for which the norms + // must be retrieved + //Post - If there was norm for the named field then a bytes array has been allocated + // and returned containing the norms for that field. If the named field is unknown NULL is returned. + + CND_PRECONDITION(field != NULL, "field is NULL"); + + SCOPED_LOCK_MUTEX(THIS_LOCK) + + uint8_t* bytes = getNorms(field); + if (bytes == NULL) + bytes = fakeNorms(); + return bytes; +} + +void SegmentReader::doSetNorm(int32_t doc, const TCHAR* field, uint8_t value) +{ + Norm* norm = _norms.get(field); + if (norm == NULL) // not an indexed field + return; + + norm->dirty = true; // mark it dirty + normsDirty = true; + + uint8_t* bits = norms(field); + bits[doc] = value; // set the value +} + +QString SegmentReader::SegmentName(const QString& ext, const int32_t x) +{ + //Func - Returns an allocated buffer in which it creates a filename by + // concatenating segment with ext and x + //Pre ext != NULL and holds the extension + // x contains a number + //Post - A buffer has been instantiated an when x = -1 buffer contains the concatenation of + // segment and ext otherwise buffer contains the contentation of segment, ext and x + + CND_PRECONDITION(!ext.isEmpty(), "ext is NULL"); + + QString buf; + SegmentName(buf, CL_MAX_PATH, ext, x); + return buf; +} + +void SegmentReader::SegmentName(QString& buffer, int32_t bufferLen, + const QString& ext, const int32_t x) +{ + //Func - Creates a filename in buffer by concatenating segment with ext and x + //Pre - buffer != NULL + // ext != NULL + // x contains a number + //Post - When x = -1 buffer contains the concatenation of segment and ext otherwise + // buffer contains the contentation of segment, ext and x + + CND_PRECONDITION(!segment.isEmpty(), "Segment is NULL"); + + Misc::segmentname(buffer, bufferLen, segment, ext, x); +} + +void SegmentReader::openNorms(Directory* cfsDir) +{ + //Func - Open all norms files for all fields + // Creates for each field a norm Instance with an open inputstream to + // a corresponding norm file ready to be read + //Pre - true + //Post - For each field a norm instance has been created with an open inputstream to + // a corresponding norm file ready to be read + + //Iterate through all the fields + for (int32_t i = 0; i < fieldInfos->size(); i++) { + //Get the FieldInfo for the i-th field + FieldInfo* fi = fieldInfos->fieldInfo(i); + //Check if the field is indexed + if (fi->isIndexed && !fi->omitNorms ) { + //Allocate a buffer + QString fileName; + + // look first if there are separate norms in compound format + SegmentName(fileName, CL_MAX_PATH, QLatin1String(".s"), fi->number); + Directory* d = getDirectory(); + if(!d->fileExists(fileName)){ + SegmentName(fileName, CL_MAX_PATH, QLatin1String(".f"), fi->number); + d = cfsDir; + } + + _norms.put(fi->name, _CLNEW Norm(d->openInput(fileName), + fi->number, this, segment)); + } + } +} + +void SegmentReader::closeNorms() +{ + //Func - Close all the norms stored in norms + //Pre - true + //Post - All the norms have been destroyed + + SCOPED_LOCK_MUTEX(_norms.THIS_LOCK) + + //Create an interator initialized at the beginning of norms + NormsType::iterator itr = _norms.begin(); + //Iterate through all the norms + while (itr != _norms.end()) { + // Get, delete the norm + _CLDELETE(itr->second); + // Move the interator to the next norm in the norms collection. + // Note ++ is an overloaded operator + ++itr; + } + _norms.clear(); //bvk: they're deleted, so clear them so that they are not re-used +} + +TermVectorsReader* SegmentReader::getTermVectorsReader() +{ + TermVectorsReader* tvReader = termVectorsLocal.get(); + if (tvReader == NULL) { + tvReader = termVectorsReaderOrig->clone(); + termVectorsLocal.set(tvReader); + } + return tvReader; +} + +TermFreqVector* SegmentReader::getTermFreqVector(int32_t docNumber, + const TCHAR* field) +{ + if (field) { + FieldInfo* fi = fieldInfos->fieldInfo(field); + // Check if this field is invalid or has no stored term vector + if (fi == NULL || !fi->storeTermVector || termVectorsReaderOrig == NULL) + return NULL; + } + + TermVectorsReader* termVectorsReader = getTermVectorsReader(); + if (termVectorsReader == NULL) + return NULL; + + return termVectorsReader->get(docNumber, field); +} + +bool SegmentReader::getTermFreqVectors(int32_t docNumber, + Array& result) +{ + if (termVectorsReaderOrig == NULL) + return false; + + TermVectorsReader* termVectorsReader = getTermVectorsReader(); + if (termVectorsReader == NULL) + return false; + + return termVectorsReader->get(docNumber, result); +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/SegmentTermDocs.cpp b/3rdparty/clucene/src/CLucene/index/SegmentTermDocs.cpp new file mode 100644 index 000000000..50951e9ba --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/SegmentTermDocs.cpp @@ -0,0 +1,216 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "SegmentHeader.h" + +#include "CLucene/store/IndexInput.h" +#include "Term.h" + +CL_NS_DEF(index) + + SegmentTermDocs::SegmentTermDocs(const SegmentReader* _parent){ + //Func - Constructor + //Pre - Paren != NULL + //Post - The instance has been created + + CND_PRECONDITION(_parent != NULL,"Parent is NULL"); + + parent = _parent; + deletedDocs = parent->deletedDocs; + + _doc = 0; + _freq = 0; + count = 0; + df = 0; + + skipInterval=0; + numSkips=0; + skipCount=0; + skipStream=NULL; + skipDoc=0; + freqPointer=0; + proxPointer=0; + skipPointer=0; + haveSkipped=false; + + freqStream = parent->freqStream->clone(); + skipInterval = parent->tis->getSkipInterval(); + } + + SegmentTermDocs::~SegmentTermDocs() { + //Func - Destructor + //Pre - true + //Post - The instance has been destroyed + + close(); + } + + TermPositions* SegmentTermDocs::__asTermPositions(){ + return NULL; + } + + void SegmentTermDocs::seek(Term* term) { + TermInfo* ti = parent->tis->get(term); + seek(ti); + _CLDELETE(ti); + } + + void SegmentTermDocs::seek(TermEnum* termEnum){ + TermInfo* ti=NULL; + + // use comparison of fieldinfos to verify that termEnum belongs to the same segment as this SegmentTermDocs + if ( termEnum->getObjectName() == SegmentTermEnum::getClassName() ){ + SegmentTermEnum* te = (SegmentTermEnum*)termEnum; + te->fieldInfos = parent->fieldInfos; + ti = te->getTermInfo(); + }else{ + ti = parent->tis->get(termEnum->term(false)); + } + + seek(ti); + _CLDELETE(ti); + } + void SegmentTermDocs::seek(const TermInfo* ti) { + count = 0; + if (ti == NULL) { + df = 0; + } else { + df = ti->docFreq; + _doc = 0; + skipDoc = 0; + skipCount = 0; + numSkips = df / skipInterval; + freqPointer = ti->freqPointer; + proxPointer = ti->proxPointer; + skipPointer = freqPointer + ti->skipOffset; + freqStream->seek(freqPointer); + haveSkipped = false; + } + } + + void SegmentTermDocs::close() { + + //Check if freqStream still exists + if (freqStream != NULL){ + freqStream->close(); //todo: items like these can probably be delete, because deleting the object also closes it...do everywhere + _CLDELETE( freqStream ); + } + if (skipStream != NULL){ + skipStream->close(); + _CLDELETE( skipStream ); + } + } + + int32_t SegmentTermDocs::doc()const { + return _doc; + } + int32_t SegmentTermDocs::freq()const { + return _freq; + } + + +bool SegmentTermDocs::next() +{ + while (true) { + if (count == df) + return false; + + uint32_t docCode = freqStream->readVInt(); + _doc += docCode >> 1; //unsigned shift + if ((docCode & 1) != 0) // if low bit is set + _freq = 1; // _freq is one + else + _freq = freqStream->readVInt(); // else read _freq + count++; + + if (deletedDocs == NULL || (_doc >= 0 && !deletedDocs->get(_doc))) + break; + skippingDoc(); + } + return true; +} + + +int32_t SegmentTermDocs::read(int32_t* docs, int32_t* freqs, int32_t length) +{ + int32_t i = 0; + // TODO: one optimization would be to get the pointer buffer for ram or mmap + // dirs and iterate over them instead of using readByte() intensive functions. + while (i < length && count < df) { + uint32_t docCode = freqStream->readVInt(); + _doc += docCode >> 1; + if ((docCode & 1) != 0) // if low bit is set + _freq = 1; // _freq is one + else + _freq = freqStream->readVInt(); // else read _freq + count++; + + if (deletedDocs == NULL || (_doc >= 0 && !deletedDocs->get(_doc))) { + docs[i] = _doc; + freqs[i] = _freq; + i++; + } + } + return i; +} + + bool SegmentTermDocs::skipTo(const int32_t target){ + if (df >= skipInterval) { // optimized case + if (skipStream == NULL) + skipStream = freqStream->clone(); // lazily clone + + if (!haveSkipped) { // lazily seek skip stream + skipStream->seek(skipPointer); + haveSkipped = true; + } + + // scan skip data + int32_t lastSkipDoc = skipDoc; + int64_t lastFreqPointer = freqStream->getFilePointer(); + int64_t lastProxPointer = -1; + int32_t numSkipped = -1 - (count % skipInterval); + + while (target > skipDoc) { + lastSkipDoc = skipDoc; + lastFreqPointer = freqPointer; + lastProxPointer = proxPointer; + + if (skipDoc != 0 && skipDoc >= _doc) + numSkipped += skipInterval; + + if(skipCount >= numSkips) + break; + + skipDoc += skipStream->readVInt(); + freqPointer += skipStream->readVInt(); + proxPointer += skipStream->readVInt(); + + skipCount++; + } + + // if we found something to skip, then skip it + if (lastFreqPointer > freqStream->getFilePointer()) { + freqStream->seek(lastFreqPointer); + skipProx(lastProxPointer); + + _doc = lastSkipDoc; + count += numSkipped; + } + + } + + // done skipping, now just scan + + do { + if (!next()) + return false; + } while (target > _doc); + return true; + } + + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/SegmentTermEnum.cpp b/3rdparty/clucene/src/CLucene/index/SegmentTermEnum.cpp new file mode 100644 index 000000000..20e286fd1 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/SegmentTermEnum.cpp @@ -0,0 +1,389 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "SegmentTermEnum.h" + +#include "Terms.h" +#include "FieldInfos.h" +#include "Term.h" +#include "TermInfo.h" +#include "TermInfosWriter.h" + +CL_NS_USE(store) +CL_NS_DEF(index) + + SegmentTermEnum::SegmentTermEnum(IndexInput* i, FieldInfos* fis, const bool isi): + fieldInfos(fis){ + //Func - Constructor + //Pre - i holds a reference to an instance of IndexInput + // fis holds a reference to an instance of FieldInfos + // isi + //Post - An instance of SegmentTermEnum has been created + input = i; + position = -1; + //Instantiate a Term with empty field, empty text and which is interned (see term.h what interned means) + _term = _CLNEW Term; + isIndex = isi; + termInfo = _CLNEW TermInfo(); + indexPointer = 0; + buffer = NULL; + bufferLength = 0; + prev = NULL; + formatM1SkipInterval = 0; + + //Set isClone to false as the instance is not clone of another instance + isClone = false; + + + int32_t firstInt = input->readInt(); + if (firstInt >= 0) { + // original-format file, without explicit format version number + format = 0; + size = firstInt; + + // back-compatible settings + indexInterval = 128; + skipInterval = LUCENE_INT32_MAX_SHOULDBE; // switch off skipTo optimization + + } else { + // we have a format version number + format = firstInt; + + // check that it is a format we can understand + if (format < TermInfosWriter::FORMAT){ + TCHAR err[30]; + _sntprintf(err,30,_T("Unknown format version: %d"), format); + _CLTHROWT(CL_ERR_Runtime,err); + } + + size = input->readLong(); // read the size + + if(format == -1){ + if (!isIndex) { + indexInterval = input->readInt(); + formatM1SkipInterval = input->readInt(); + } + // switch off skipTo optimization for file format prior to 1.4rc2 in order to avoid a bug in + // skipTo implementation of these versions + skipInterval = LUCENE_INT32_MAX_SHOULDBE; + }else{ + indexInterval = input->readInt(); + skipInterval = input->readInt(); + } + } + } + + SegmentTermEnum::SegmentTermEnum(const SegmentTermEnum& clone): + fieldInfos(clone.fieldInfos) + { + //Func - Constructor + // The instance is created by cloning all properties of clone + //Pre - clone holds a valid reference to SegmentTermEnum + //Post - An instance of SegmentTermEnum with the same properties as clone + + input = clone.input->clone(); + //Copy the postion from the clone + position = clone.position; + + if ( clone._term != NULL ){ + _term = _CLNEW Term; + _term->set(clone._term,clone._term->text()); + }else + _term = NULL; + isIndex = clone.isIndex; + termInfo = _CLNEW TermInfo(clone.termInfo); + indexPointer = clone.indexPointer; + buffer = clone.buffer==NULL?NULL:(TCHAR*)malloc(sizeof(TCHAR) * (clone.bufferLength+1)); + bufferLength = clone.bufferLength; + prev = clone.prev==NULL?NULL:_CLNEW Term(clone.prev->field(),clone.prev->text(),false); + size = clone.size; + + format = clone.format; + indexInterval= clone.indexInterval; + skipInterval = clone.skipInterval; + formatM1SkipInterval = clone.formatM1SkipInterval; + //Set isClone to true as this instance is a clone of another instance + isClone = true; + + //Copy the contents of buffer of clone to the buffer of this instance + if ( clone.buffer != NULL ) + memcpy(buffer,clone.buffer,bufferLength * sizeof(TCHAR)); + } + + SegmentTermEnum::~SegmentTermEnum(){ + //Func - Destructor + //Pre - true + //Post - The instance has been destroyed. If this instance was a clone + // then the inputstream is closed and deleted too. + + //todo: revisit this... close() should clean up most of everything. + + //Finalize prev + _CLDECDELETE(prev ); + //Finalize term + _CLDECDELETE( _term ); + + + //Delete the buffer if necessary + free(buffer); + //Delete termInfo if necessary + _CLDELETE(termInfo); + + //Check if this instance is a clone + if ( isClone ){ + //Close the inputstream + input->close(); + //delete the inputstream + _CLDELETE(input); + } + } + + bool SegmentTermEnum::next(){ + //Func - Moves the current of the set to the next in the set + //Pre - true + //Post - If the end has been reached NULL is returned otherwise the term has + // become the next Term in the enumeration + + //Increase position by and and check if the end has been reached + if (position++ >= size-1) { + //delete term + _CLDECDELETE(_term); + return false; + } + + //delete the previous enumerated term + Term* tmp=NULL; + if ( prev != NULL ){ + int32_t usage = prev->__cl_refcount; + if ( usage > 1 ){ + _CLDECDELETE(prev); //todo: tune other places try and delete its term + }else + tmp = prev; //we are going to re-use this term + } + //prev becomes the current enumerated term + prev = _term; + //term becomes the next term read from inputStream input + _term = readTerm(tmp); + + //Read docFreq, the number of documents which contain the term. + termInfo->docFreq = input->readVInt(); + //Read freqPointer, a pointer into the TermFreqs file (.frq) + termInfo->freqPointer += input->readVLong(); + + //Read proxPointer, a pointer into the TermPosition file (.prx). + termInfo->proxPointer += input->readVLong(); + + if(format == -1){ + // just read skipOffset in order to increment file pointer; + // value is never used since skipTo is switched off + if (!isIndex) { + if (termInfo->docFreq > formatM1SkipInterval) { + termInfo->skipOffset = input->readVInt(); + } + } + }else{ + if (termInfo->docFreq >= skipInterval) + termInfo->skipOffset = input->readVInt(); + } + + //Check if the enumeration is an index + if (isIndex) + //read index pointer + indexPointer += input->readVLong(); + + return true; + } + + Term* SegmentTermEnum::term() { + //Func - Returns the current term. + //Pre - pointer is true or false and indicates if the reference counter + // of term must be increased or not + // next() must have been called once! + //Post - pointer = true -> term has been returned with an increased reference counter + // pointer = false -> term has been returned + + return _CL_POINTER(_term); + } + Term* SegmentTermEnum::term(bool pointer) { + if ( pointer ) + return _CL_POINTER(_term); + else + return _term; + } + + void SegmentTermEnum::scanTo(const Term *term){ + //Func - Scan for Term without allocating new Terms + //Pre - term != NULL + //Post - The iterator term has been moved to the position where Term is expected to be + // in the enumeration + while ( term->compareTo(this->_term) > 0 && next()) + { + } + } + + void SegmentTermEnum::close() { + //Func - Closes the enumeration to further activity, freeing resources. + //Pre - true + //Post - The inputStream input has been closed + + input->close(); + } + + int32_t SegmentTermEnum::docFreq() const { + //Func - Returns the document frequency of the current term in the set + //Pre - termInfo != NULL + // next() must have been called once + //Post - The document frequency of the current enumerated term has been returned + + return termInfo->docFreq; + } + + void SegmentTermEnum::seek(const int64_t pointer, const int32_t p, Term* t, TermInfo* ti) { + //Func - Repositions term and termInfo within the enumeration + //Pre - pointer >= 0 + // p >= 0 and contains the new position within the enumeration + // t is a valid reference to a Term and is the new current term in the enumeration + // ti is a valid reference to a TermInfo and is corresponding TermInfo form the new + // current Term + //Post - term and terminfo have been repositioned within the enumeration + + //Reset the IndexInput input to pointer + input->seek(pointer); + //Assign the new position + position = p; + + //finalize the current term + if ( _term == NULL || _term->__cl_refcount > 1 ){ + _CLDECDELETE(_term); + //Get a pointer from t and increase the reference counter of t + _term = _CLNEW Term; //cannot use reference, because TermInfosReader uses non ref-counted array + } + _term->set(t,t->text()); + + //finalize prev + _CLDECDELETE(prev); + + //Change the current termInfo so it matches the new current term + termInfo->set(ti); + + //Have the buffer grown if needed + if ( bufferLength <= _term->textLength() ) + growBuffer(_term->textLength(), true ); // copy term text into buffer + else + _tcsncpy(buffer,_term->text(),bufferLength); //just copy the buffer + } + + TermInfo* SegmentTermEnum::getTermInfo()const { + //Func - Returns a clone of the current termInfo + //Pre - termInfo != NULL + // next() must have been called once + //Post - A clone of the current termInfo has been returned + + return _CLNEW TermInfo(*termInfo); //clone + } + + void SegmentTermEnum::getTermInfo(TermInfo* ti)const { + //Func - Retrieves a clone of termInfo through the reference ti + //Pre - ti contains a valid reference to TermInfo + // termInfo != NULL + // next() must have been called once + //Post - ti contains a clone of termInfo + + ti->set(termInfo); + } + + int64_t SegmentTermEnum::freqPointer()const { + //Func - Returns the freqpointer of the current termInfo + //Pre - termInfo != NULL + // next() must have been called once + //Post - The freqpointer of the current termInfo has been returned + + return termInfo->freqPointer; + } + + int64_t SegmentTermEnum::proxPointer()const { + //Func - Returns the proxPointer of the current termInfo + //Pre - termInfo != NULL + // next() must have been called once + //Post - the proxPointer of the current termInfo has been returned + + return termInfo->proxPointer; + } + + SegmentTermEnum* SegmentTermEnum::clone() const { + //Func - Returns a clone of this instance + //Pre - true + //Post - An clone of this instance has been returned + + return _CLNEW SegmentTermEnum(*this); + } + + Term* SegmentTermEnum::readTerm(Term* reuse) { + //Func - Reads the next term in the enumeration + //Pre - true + //Post - The next Term in the enumeration has been read and returned + + //Read the start position from the inputStream input + int32_t start = input->readVInt(); + //Read the length of term in the inputStream input + int32_t length = input->readVInt(); + + //Calculated the total lenght of bytes that buffer must be to contain the current + //chars in buffer and the new ones yet to be read + uint32_t totalLength = start + length; + + if (static_cast(bufferLength) < totalLength+1) + growBuffer(totalLength, false); + + //Read a length number of characters into the buffer from position start in the inputStream input + input->readChars(buffer, start, length); + //Null terminate the string + buffer[totalLength] = 0; + + //Return a new Term + int32_t field = input->readVInt(); + const TCHAR* fieldname = fieldInfos->fieldName(field); + if ( reuse == NULL ) + reuse = _CLNEW Term; + + reuse->set(fieldname, buffer, false); + return reuse; + } + + void SegmentTermEnum::growBuffer(const uint32_t length, bool force_copy) { + //Func - Instantiate a buffer of length length+1 + //Pre - length > 0 + //Post - pre(buffer) has been deleted with its contents. A new buffer + // has been allocated of length length+1 and the text of term has been copied + // to buffer + //todo: we could guess that we will need to re-grow this + //buffer a few times...so start off with a reasonable grow + //value... + if ( bufferLength > length ) + return; + + //Store the new bufferLength + if ( length - bufferLength < LUCENE_SEGMENTTERMENUM_GROWSIZE ) + bufferLength = length+LUCENE_SEGMENTTERMENUM_GROWSIZE; + else + bufferLength = length+1; + + bool copy = buffer==NULL; + + //Instantiate the new buffer + 1 is needed for terminator '\0' + if ( buffer == NULL ) + buffer = (TCHAR*)malloc(sizeof(TCHAR) * (bufferLength+1)); + else + buffer = (TCHAR*)realloc(buffer, sizeof(TCHAR) * (bufferLength+1)); + + if ( copy || force_copy){ + //Copy the text of term into buffer + _tcsncpy(buffer,_term->text(),bufferLength); + } + } + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/SegmentTermEnum.h b/3rdparty/clucene/src/CLucene/index/SegmentTermEnum.h new file mode 100644 index 000000000..0d50103f3 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/SegmentTermEnum.h @@ -0,0 +1,138 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_index_SegmentTermEnum_ +#define _lucene_index_SegmentTermEnum_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "Terms.h" +#include "FieldInfos.h" +#include "TermInfo.h" + +CL_NS_DEF(index) + +/** + * SegmentTermEnum is an enumeration of all Terms and TermInfos + */ +class SegmentTermEnum:public TermEnum{ +private: + Term* _term; ///points to the current Term in the enumeration + TermInfo* termInfo; ///points to the TermInfo matching the current Term in the enumeration + + bool isIndex; ///Indicates if the Segment is a an index + bool isClone; ///Indicates if SegmentTermEnum is an orignal instance or + ///a clone of another SegmentTermEnum + + TCHAR* buffer; ///The buffer that contains the data read from the Term Infos File + uint32_t bufferLength; ///Length of the buffer + + int32_t format; + int32_t formatM1SkipInterval; + + CL_NS(store)::IndexInput* input; ///The IndexInput that reads from the Term Infos File + FieldInfos* fieldInfos; ///contains the Field Infos for the segment + int64_t size; ///The size of the enumeration + int64_t position; ///The position of the current (term) in the enumeration + int64_t indexPointer; + Term* prev; ///The previous current + int32_t indexInterval; + int32_t skipInterval; + + friend class TermInfosReader; + friend class SegmentTermDocs; +protected: + + /** + * Constructor. + * The instance is created by cloning all properties of clone + */ + SegmentTermEnum( const SegmentTermEnum& clone); + +public: + ///Constructor + SegmentTermEnum(CL_NS(store)::IndexInput* i, FieldInfos* fis, const bool isi ); + + ///Destructor + ~SegmentTermEnum(); + + /** + * Moves the current of the set to the next in the set + */ + bool next(); + + /** + * Returns a pointer to the current term. + */ + Term* term(); + /** + * Returns the current term. + */ + Term* term(bool pointer); + + /** + * Scan for Term term without allocating new Terms + */ + void scanTo(const Term *term); + + /** + * Closes the enumeration to further activity, freeing resources. + */ + void close(); + + /** + * Returns the document frequency of the current term in the set + */ + int32_t docFreq() const; + + /** + * Repositions term and termInfo within the enumeration + */ + void seek(const int64_t pointer, const int32_t p, Term* t, TermInfo* ti); + + /** + * Returns a clone of the current termInfo + */ + TermInfo* getTermInfo()const; + + /** + * Retrieves a clone of termInfo through the reference ti + */ + void getTermInfo(TermInfo* ti)const; + + /** + * Returns the freqPointer from the current TermInfo in the enumeration. + */ + int64_t freqPointer() const; + + /** + * Returns the proxPointer from the current TermInfo in the enumeration. + */ + int64_t proxPointer() const; + + /** + * Returns a clone of this instance + */ + SegmentTermEnum* clone() const; + + const char* getObjectName(){ return SegmentTermEnum::getClassName(); } + static const char* getClassName(){ return "SegmentTermEnum"; } + +private: + /** + * Reads the next term in the enumeration + */ + Term* readTerm(Term* reuse); + /** + * Instantiate a buffer of length length+1 + */ + void growBuffer(const uint32_t length, bool force_copy); + +}; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/index/SegmentTermPositions.cpp b/3rdparty/clucene/src/CLucene/index/SegmentTermPositions.cpp new file mode 100644 index 000000000..e481838e9 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/SegmentTermPositions.cpp @@ -0,0 +1,101 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "SegmentHeader.h" + +#include "Terms.h" + +CL_NS_USE(util) +CL_NS_DEF(index) + +SegmentTermPositions::SegmentTermPositions(const SegmentReader* _parent): + SegmentTermDocs(_parent){ +//Func - Constructor +//Pre - Parent != NULL +//Post - The instance has been created + + CND_PRECONDITION(_parent != NULL, "Parent is NULL"); + + proxStream = _parent->proxStream->clone(); + + CND_CONDITION(proxStream != NULL,"proxStream is NULL"); + + position = 0; + proxCount = 0; +} + +SegmentTermPositions::~SegmentTermPositions() { +//Func - Destructor +//Pre - true +//Post - The intance has been closed + close(); +} + +TermDocs* SegmentTermPositions::__asTermDocs(){ + return (TermDocs*) this; +} +TermPositions* SegmentTermPositions::__asTermPositions(){ + return (TermPositions*) this; +} + +void SegmentTermPositions::seek(const TermInfo* ti) { + SegmentTermDocs::seek(ti); + if (ti != NULL) + proxStream->seek(ti->proxPointer); + proxCount = 0; +} + +void SegmentTermPositions::close() { +//Func - Frees the resources +//Pre - true +//Post - The resources have been freed + + SegmentTermDocs::close(); + //Check if proxStream still exists + if(proxStream){ + proxStream->close(); + _CLDELETE( proxStream ); + } +} + +int32_t SegmentTermPositions::nextPosition() { + /* DSR:CL_BUG: Should raise exception if proxCount == 0 at the + ** beginning of this method, as in + ** if (--proxCount == 0) throw ...; + ** The JavaDocs for TermPositions.nextPosition declare this constraint, + ** but CLucene doesn't enforce it. */ + proxCount--; + return position += proxStream->readVInt(); +} + +bool SegmentTermPositions::next() { + for (int32_t f = proxCount; f > 0; f--) // skip unread positions + proxStream->readVInt(); + + if (SegmentTermDocs::next()) { // run super + proxCount = _freq; // note frequency + position = 0; // reset position + return true; + } + return false; +} + +int32_t SegmentTermPositions::read(int32_t* docs, int32_t* freqs, int32_t length) { + _CLTHROWA(CL_ERR_InvalidState,"TermPositions does not support processing multiple documents in one call. Use TermDocs instead."); +} + +void SegmentTermPositions::skippingDoc() { + for (int32_t f = _freq; f > 0; f--) // skip all positions + proxStream->readVInt(); +} + +void SegmentTermPositions::skipProx(int64_t proxPointer){ + proxStream->seek(proxPointer); + proxCount = 0; +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/SegmentTermVector.cpp b/3rdparty/clucene/src/CLucene/index/SegmentTermVector.cpp new file mode 100644 index 000000000..5e9ac3c3b --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/SegmentTermVector.cpp @@ -0,0 +1,188 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "TermVector.h" +#include "CLucene/util/StringBuffer.h" + +CL_NS_USE(util) +CL_NS_DEF(index) + +Array SegmentTermPositionVector::EMPTY_TERM_POS; + +SegmentTermVector::SegmentTermVector(const TCHAR* field, TCHAR** terms, Array* termFreqs) { + this->field = STRDUP_TtoT(field); + this->terms = terms; + this->termsLen = -1; //lazily get the size of the terms + this->termFreqs = termFreqs; +} + +SegmentTermVector::~SegmentTermVector(){ + _CLDELETE_CARRAY(field); + _CLDELETE_CARRAY_ALL(terms); + + _CLDELETE_ARRAY(termFreqs->values); + _CLDELETE(termFreqs); +} +TermPositionVector* SegmentTermVector::__asTermPositionVector(){ + return NULL; +} + +const TCHAR* SegmentTermVector::getField() { +return field; +} + +TCHAR* SegmentTermVector::toString() const{ +StringBuffer sb; +sb.appendChar('{'); +sb.append(field); +sb.append(_T(": ")); + +int32_t i=0; +while ( terms && terms[i] != NULL ){ + if (i>0) + sb.append(_T(", ")); + sb.append(terms[i]); + sb.appendChar('/'); + + sb.appendInt((*termFreqs)[i]); +} +sb.appendChar('}'); +return sb.toString(); +} + +int32_t SegmentTermVector::size() { +if ( terms == NULL ) + return 0; + +if ( termsLen == -1 ){ + termsLen=0; + while ( terms[termsLen] != 0 ) + termsLen++; +} +return termsLen; +} + +const TCHAR** SegmentTermVector::getTerms() { + return (const TCHAR**)terms; +} + +const Array* SegmentTermVector::getTermFrequencies() { + return termFreqs; +} + +int32_t SegmentTermVector::binarySearch(TCHAR** a, const int32_t arraylen, const TCHAR* key) const +{ + int32_t low = 0; + int32_t hi = arraylen - 1; + int32_t mid = 0; + while (low <= hi) + { + mid = (low + hi) >> 1; + + int32_t c = _tcscmp(a[mid],key); + if (c==0) + return mid; + else if (c > 0) + hi = mid - 1; + else // This gets the insertion point right on the last loop. + low = ++mid; + } + return -mid - 1; +} + +int32_t SegmentTermVector::indexOf(const TCHAR* termText) { + if(terms == NULL) + return -1; + int32_t res = binarySearch(terms, size(), termText); + return res >= 0 ? res : -1; +} + +void SegmentTermVector::indexesOf(const TCHAR** termNumbers, const int32_t start, const int32_t len, Array& ret) { + // TODO: there must be a more efficient way of doing this. + // At least, we could advance the lower bound of the terms array + // as we find valid indexes. Also, it might be possible to leverage + // this even more by starting in the middle of the termNumbers array + // and thus dividing the terms array maybe in half with each found index. + ret.length = len; + ret.values = _CL_NEWARRAY(int32_t,len); + for (int32_t i=0; i* termFreqs, Array< Array >* positions, Array< Array >* offsets): + SegmentTermVector(field,terms,termFreqs) +{ + this->offsets = offsets; + this->positions = positions; +} + +SegmentTermPositionVector::~SegmentTermPositionVector(){ + if ( offsets ){ + for (size_t i=0;ilength;i++){ + if ( offsets->values != NULL ){ + Array& offs = offsets->values[i]; + for ( size_t j=0;jvalues); + _CLDELETE(offsets); + } + if ( positions ){ + for (size_t i=0;ilength;i++){ + if ( positions->values != NULL ){ + Array& pos = positions->values[i]; + for ( size_t j=0;jvalues); + _CLDELETE(positions); + } +} + +TermPositionVector* SegmentTermPositionVector::__asTermPositionVector(){ + return this; +} +/** +* Returns an array of TermVectorOffsetInfo in which the term is found. +* +* @param index The position in the array to get the offsets from +* @return An array of TermVectorOffsetInfo objects or the empty list +* @see org.apache.lucene.analysis.Token +*/ +Array* SegmentTermPositionVector::getOffsets(int32_t index) { + if(offsets == NULL) + return NULL; + if (index >=0 && index < offsets->length) + return &offsets->values[index]; + else + return &TermVectorOffsetInfo::EMPTY_OFFSET_INFO; +} + +/** +* Returns an array of positions in which the term is found. +* Terms are identified by the index at which its number appears in the +* term String array obtained from the indexOf method. +*/ +Array* SegmentTermPositionVector::getTermPositions(int32_t index) { + if(positions == NULL) + return NULL; + + if (index >=0 && index < positions->length) + return &positions->values[index]; + else + return &EMPTY_TERM_POS; +} +CL_NS_END + diff --git a/3rdparty/clucene/src/CLucene/index/Term.cpp b/3rdparty/clucene/src/CLucene/index/Term.cpp new file mode 100644 index 000000000..5ff7bb264 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/Term.cpp @@ -0,0 +1,182 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +* +* Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +------------------------------------------------------------------------------*/ + +#include "CLucene/StdHeader.h" +#include "Term.h" +#include "CLucene/util/StringIntern.h" + +CL_NS_USE(util) +CL_NS_DEF(index) + +Term::Term() +{ + init(); +} + +Term::Term(const TCHAR* fld, const TCHAR* txt, bool internField) +{ + init(); + set(fld, txt, internField); +} + +Term::Term(const Term* fieldTerm, const TCHAR* txt) +{ + init(); + set(fieldTerm, txt); +} + +Term::Term(const TCHAR* fld, const TCHAR* txt) +{ + init(); + set(fld, txt); +} + +Term::~Term() +{ + if (internF) + CLStringIntern::unintern(_field); + _field = NULL; + +#ifndef LUCENE_TERM_TEXT_LENGTH + if (_text != LUCENE_BLANK_STRING) + _CLDELETE_CARRAY(_text); +#endif +} + +const TCHAR* Term::field() const +{ + return _field; +} + +const TCHAR* Term::text() const +{ + return _text; +} + +void Term::set(const Term* term, const TCHAR* txt) +{ + set(term->field(), txt, false); +} + +void Term::set(const TCHAR* fld, const TCHAR* txt,bool internField) +{ + CND_PRECONDITION(fld != NULL, "fld contains NULL"); + CND_PRECONDITION(txt != NULL, "txt contains NULL"); + + //save field for unintern later + const TCHAR* oldField = _field; + cachedHashCode = 0; + textLen = _tcslen(txt); + + //Delete text if it is the owner +#ifdef LUCENE_TERM_TEXT_LENGTH + if (textLen > LUCENE_TERM_TEXT_LENGTH) + textLen = LUCENE_TERM_TEXT_LENGTH; + + _tcsncpy(_text,txt,textLen+1); + _text[textLen]=0; +#else + //if the term text buffer is bigger than what we have + if (_text && textLen > textLenBuf) { + if (_text != LUCENE_BLANK_STRING) { + _CLDELETE_ARRAY(_text); + } else { + _text = NULL; + } + textLenBuf = 0; + } + + if (_text == LUCENE_BLANK_STRING) { + _text = LUCENE_BLANK_STRING; + } else if (_text == NULL) { + if (txt[0] == 0) { + //if the string is blank and we aren't re-using the buffer... + _text = LUCENE_BLANK_STRING; + } else { + //duplicate the text + _text = stringDuplicate(txt); + textLenBuf = textLen; + } + } else { + //re-use the buffer + _tcscpy(_text,txt); + } +#endif + + //Set Term Field + if (internField) { + _field = CLStringIntern::intern(fld CL_FILELINE); + } else { + _field = fld; + } + + //unintern old field after interning new one, + if (internF) + CLStringIntern::unintern(oldField); + internF = internField; + + CND_PRECONDITION(_tcscmp(fld, _field) == 0, "field not equal"); +} + +bool Term::equals(const Term* other) const +{ + if (cachedHashCode != 0 && other->cachedHashCode != 0 + && other->cachedHashCode != cachedHashCode) + return false; + + if (_field == other->_field) { + if (textLen == other->textLen) + return (_tcscmp(_text, other->_text) == 0); + return false; + } + + return false; +} + +size_t Term::hashCode() +{ + if (cachedHashCode == 0) + cachedHashCode = Misc::thashCode(_field) + Misc::thashCode(_text, textLen); + + return cachedHashCode; +} + +int32_t Term::compareTo(const Term* other) const +{ + //Check ret to see if text needs to be compared + if (_field == other->_field) + return _tcscmp(_text, other->_text); + + int32_t ret = _tcscmp(_field, other->_field); + if (ret == 0) + ret = _tcscmp(_text, other->_text); + return ret; +} + +TCHAR* Term::toString() const +{ + return CL_NS(util)::Misc::join(_field, _T(":"), _text); +} + +void Term::init() +{ + textLen = 0; + internF = false; + cachedHashCode = 0; + _field = LUCENE_BLANK_STRING; + +#ifdef LUCENE_TERM_TEXT_LENGTH + _text[0] = 0; +#else + _text = LUCENE_BLANK_STRING; + textLenBuf = 0; +#endif +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/Term.h b/3rdparty/clucene/src/CLucene/index/Term.h new file mode 100644 index 000000000..68eefd194 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/Term.h @@ -0,0 +1,146 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +* +* Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +------------------------------------------------------------------------------*/ +#ifndef _lucene_index_Term_ +#define _lucene_index_Term_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/util/Misc.h" +#include "CLucene/util/StringIntern.h" + +CL_NS_DEF(index) + +/* +A Term represents a word from text. This is the unit of search. It is +composed of two elements, the text of the word, as a string, and the name of +the field that the text occured in, an interned string. + +Note that terms may represent more than words from text fields, but also +things like dates, email addresses, urls, etc. + +IMPORTANT NOTE: +Term inherits from the template class LUCENE_REFBASE which tries to do +some garbage collection by counting the references an instance has. As a result +of this construction you MUST use _CLDECDELETE(obj) when you want to delete an +of Term! + +ABOUT intrn + +intrn indicates if field and text are interned or not. Interning of Strings +is the process of converting duplicated strings to shared ones. + +*/ +class Term : LUCENE_REFBASE +{ +private: + const TCHAR* _field; + bool internF; // Indicates if Term Field is interned(and therefore must be uninternd). + size_t cachedHashCode; + size_t textLen; // a cache of text len, this allows for a preliminary comparison of text lengths + +#ifdef LUCENE_TERM_TEXT_LENGTH + TCHAR _text[LUCENE_TERM_TEXT_LENGTH + 1]; +#else + TCHAR* _text; + size_t textLenBuf; //a cache of text len, this allows for a preliminary comparison of text lengths +#endif + + void init(); +public: + + //uses the specified fieldTerm's field. this saves on intern'ing time. + Term(const Term* fieldTerm, const TCHAR* txt); + + ///Constructs a blank term + Term(); + + // TODO: need to be private, a few other things need to be changed first... + Term(const TCHAR* fld, const TCHAR* txt, bool internField); + + /** + * Constructor. Constructs a Term with the given field and text. Field and + * text are not copied Field and text are deleted in destructor only if + * intern is false. + */ + Term(const TCHAR* fld, const TCHAR* txt); + + ///Destructor. + ~Term(); + + ///Returns the field of this term, an interned string. The field indicates + ///the part of a document which this term came from. + const TCHAR* field() const; /// + TCHAR* toString() const; + + size_t hashCode(); + + class Equals:public CL_NS_STD(binary_function) + { + public: + bool operator()( const Term* val1, const Term* val2 ) const + { + return val1->equals(val2); + } + }; + + class Compare:LUCENE_BASE, public CL_NS(util)::Compare::_base // + { + public: + bool operator()(Term* t1, Term* t2) const + { + return (t1->compareTo(t2) < 0); + } + + size_t operator()(Term* t) const + { + return t->hashCode(); + } + }; +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/index/TermInfo.cpp b/3rdparty/clucene/src/CLucene/index/TermInfo.cpp new file mode 100644 index 000000000..ac1107317 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/TermInfo.cpp @@ -0,0 +1,53 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +* +* Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +------------------------------------------------------------------------------*/ + +#include "CLucene/StdHeader.h" +#include "TermInfo.h" + +CL_NS_DEF(index) + +TermInfo::TermInfo() +{ + set(0, 0, 0, 0); +} + +TermInfo::~TermInfo() +{ +} + +TermInfo::TermInfo(int32_t df, int64_t fp, int64_t pp) +{ + set(df, fp, pp, 0); +} + +TermInfo::TermInfo(const TermInfo* ti) +{ + if (ti) + set(ti); +} + +void TermInfo::set(const TermInfo* ti) +{ + if (ti) + set(ti->docFreq, ti->freqPointer, ti->proxPointer, ti->skipOffset); +} + +void TermInfo::set(int32_t df, int64_t fp, int64_t pp, int32_t so) +{ + CND_PRECONDITION(df >= 0, "df contains negative number"); + CND_PRECONDITION(fp >= 0, "fp contains negative number"); + CND_PRECONDITION(pp >= 0, "pp contains negative number"); + + docFreq = df; + freqPointer = fp; + proxPointer = pp; + skipOffset = so; +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/TermInfo.h b/3rdparty/clucene/src/CLucene/index/TermInfo.h new file mode 100644 index 000000000..57b7a9a76 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/TermInfo.h @@ -0,0 +1,61 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +* +* Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +------------------------------------------------------------------------------*/ +#ifndef _lucene_index_TermInfo +#define _lucene_index_TermInfo + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +CL_NS_DEF(index) + +// A TermInfo is the record of information stored for a term. +class TermInfo : LUCENE_BASE +{ +public: + // The number of documents which contain the term. + int32_t docFreq; + + //A pointer into the TermFreqs file (.frq) + //The .frq file contains the lists of documents which contain each term, + //along with the frequency of the term in that document. + int64_t freqPointer; + + //A pointer into the TermPosition file (.prx). + //The .prx file contains the lists of positions that each term + //occurs at within documents. + int64_t proxPointer; + + int32_t skipOffset; + + //Constructor + TermInfo(); + + //Constructor + TermInfo(int32_t df, int64_t fp, int64_t pp); + + //Constructor + //Initialises this instance by copying the values of another TermInfo ti + TermInfo(const TermInfo* ti); + + //Destructor + ~TermInfo(); + + //Sets a new document frequency, a new freqPointer and a new proxPointer + void set(int32_t docFreq, int64_t freqPointer, int64_t proxPointer, + int32_t skipOffset); + + //Sets a new document frequency, a new freqPointer and a new proxPointer + //by copying these values from another instance of TermInfo + void set(const TermInfo* ti); +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/index/TermInfosReader.cpp b/3rdparty/clucene/src/CLucene/index/TermInfosReader.cpp new file mode 100644 index 000000000..8f9e43dec --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/TermInfosReader.cpp @@ -0,0 +1,443 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#include "CLucene/StdHeader.h" +#include "TermInfosReader.h" + +#include "CLucene/store/Directory.h" +#include "CLucene/util/Misc.h" +#include "FieldInfos.h" +#include "Term.h" +#include "Terms.h" +#include "TermInfo.h" +#include "TermInfosWriter.h" + +CL_NS_USE(store) +CL_NS_USE(util) +CL_NS_DEF(index) + +TermInfosReader::TermInfosReader(Directory* dir, const QString& seg, + FieldInfos* fis) + : directory(dir) + , fieldInfos (fis) +{ + //Func - Constructor. + // Reads the TermInfos file (.tis) and eventually the Term Info Index file (.tii) + //Pre - dir is a reference to a valid Directory + // Fis contains a valid reference to an FieldInfos instance + // seg != NULL and contains the name of the segment + //Post - An instance has been created and the index named seg has been read. (Remember + // a segment is nothing more then an independently readable index) + + CND_PRECONDITION(!seg.isEmpty(), "seg is NULL"); + + //Initialize the name of the segment + segment = seg; + //There are no indexTerms yet + indexTerms = NULL; + //So there are no indexInfos + indexInfos = NULL; + //So there are no indexPointers + indexPointers = NULL; + //Create a filname fo a Term Info File + QString tisFile = Misc::segmentname(segment, QLatin1String(".tis")); + QString tiiFile = Misc::segmentname(segment, QLatin1String(".tii")); + + //Create an SegmentTermEnum for storing all the terms read of the segment + origEnum = _CLNEW SegmentTermEnum( directory->openInput( tisFile ), fieldInfos, false); + indexEnum = _CLNEW SegmentTermEnum( directory->openInput( tiiFile ), fieldInfos, true); + + //Check if enumerator points to a valid instance + CND_CONDITION(origEnum != NULL, "No memory could be allocated for orig enumerator"); + CND_CONDITION(indexEnum != NULL, "No memory could be allocated for index enumerator"); + + //Get the size of the enumeration and store it in size + _size = origEnum->size; +} + +TermInfosReader::~TermInfosReader() +{ + //Func - Destructor + //Pre - true + //Post - The instance has been destroyed + + //Close the TermInfosReader to be absolutly sure that enumerator has been closed + //and the arrays indexTerms, indexPointers and indexInfos and their elements + //have been destroyed + close(); +} + +void TermInfosReader::close() +{ + //Func - Close the enumeration of TermInfos + //Pre - true + //Post - The _enumeration has been closed and the arrays + + //Check if indexTerms and indexInfos exist + if (indexTerms && indexInfos){ + //Iterate through arrays indexTerms and indexPointer to + //destroy their elements +#ifdef _DEBUG + for (int32_t i = 0; i < indexTermsLength; ++i) { + if (indexTerms[i].__cl_refcount != 1) { + CND_PRECONDITION(indexTerms[i].__cl_refcount == 1, + "TermInfosReader term was references more than internally"); + } + // _CLDECDELETE(indexTerms[i]); + //_CLDELETE(indexInfos[i]); + } +#endif + //Delete the arrays + _CLDELETE_ARRAY(indexTerms); + _CLDELETE_ARRAY(indexInfos); + } + + //Delete the arrays + _CLDELETE_ARRAY(indexPointers); + + if (origEnum != NULL) { + origEnum->close(); + + //Get a pointer to IndexInput used by the enumeration but + //instantiated in the constructor by directory.open( tisFile ) + IndexInput *is = origEnum->input; + + //Delete the enumuration enumerator + _CLDELETE(origEnum); + + //Delete the IndexInput + _CLDELETE(is); + } + + if (indexEnum != NULL){ + indexEnum->close(); + + //Get a pointer to IndexInput used by the enumeration but + //instantiated in the constructor by directory.open( tiiFile ) + IndexInput *is = indexEnum->input; + + //Delete the enumuration enumerator + _CLDELETE(indexEnum); + + //Delete the IndexInput + _CLDELETE(is); + } +} + +int64_t TermInfosReader::size() const +{ + //Func - Return the size of the enumeration of TermInfos + //Pre - true + //Post - size has been returened + + return _size; +} + +Term* TermInfosReader::get(const int32_t position) +{ + //Func - Returns the nth term in the set + //Pre - position > = 0 + //Post - The n-th term in the set has been returned + + //Check if the size is 0 because then there are no terms + if (_size == 0) + return NULL; + + SegmentTermEnum* enumerator = getEnum(); + + if (enumerator != NULL //an enumeration exists + && enumerator->term(false) != NULL // term is at or past current + && position >= enumerator->position + && position < (enumerator->position + enumerator->indexInterval)) { + return scanEnum(position); // can avoid seek + } + + //random-access: must seek + seekEnum(position / enumerator->indexInterval); + + //Get the Term at position + return scanEnum(position); +} + +// TODO: currently there is no way of cleaning up a thread, if the thread ends. +// we are stuck with the terminfosreader of that thread. Hopefully this won't +// be too big a problem... solutions anyone? +SegmentTermEnum* TermInfosReader::getEnum() +{ + SegmentTermEnum* termEnum = enumerators.get(); + if (termEnum == NULL) { + termEnum = terms(); + enumerators.set(termEnum); + } + return termEnum; +} + +TermInfo* TermInfosReader::get(const Term* term) +{ + //Func - Returns a TermInfo for a term + //Pre - term holds a valid reference to term + //Post - if term can be found its TermInfo has been returned otherwise NULL + + //If the size of the enumeration is 0 then no Terms have been read + if (_size == 0) + return NULL; + + ensureIndexIsRead(); + + // optimize sequential access: first try scanning cached enum w/o seeking + SegmentTermEnum* enumerator = getEnum(); + + // optimize sequential access: first try scanning cached enumerator w/o seeking + // if the current term of the enumeration enumerator is not at the end + if (enumerator->term(false) != NULL + // AND there exists a previous current called prev and term is + // positioned after this prev + && ((enumerator->prev != NULL && term->compareTo(enumerator->prev) > 0) + // OR term is positioned at the same position as the current of + // enumerator or at a higher position + || term->compareTo(enumerator->term(false)) >= 0)) { + //Calculate the offset for the position + int32_t _enumOffset = (int32_t) + (enumerator->position / enumerator->indexInterval) + 1; + + // but before end of block the length of indexTerms (the number of + // terms in enumerator) equals _enum_offset + if (indexTermsLength == _enumOffset + // OR term is positioned in front of term found at _enumOffset in + // indexTerms + || term->compareTo(&indexTerms[_enumOffset]) < 0) { + //no need to seek, retrieve the TermInfo for term + return scanEnum(term); + } + } + + //Reposition current term in the enumeration + seekEnum(getIndexOffset(term)); + //Return the TermInfo for term + return scanEnum(term); +} + +int64_t TermInfosReader::getPosition(const Term* term) +{ + //Func - Returns the position of a Term in the set + //Pre - term holds a valid reference to a Term + // enumerator != NULL + //Post - If term was found then its position is returned otherwise -1 + + //if the enumeration is empty then return -1 + if (_size == 0) + return -1; + + ensureIndexIsRead(); + + //Retrieve the indexOffset for term + int32_t indexOffset = getIndexOffset(term); + seekEnum(indexOffset); + + SegmentTermEnum* enumerator = getEnum(); + + while(term->compareTo(enumerator->term(false)) > 0 && enumerator->next()) {} + + if (term->equals(enumerator->term(false))) + return enumerator->position; + + return -1; +} + +SegmentTermEnum* TermInfosReader::terms(const Term* term) +{ + //Func - Returns an enumeration of terms starting at or after the named term. + // If term is null then enumerator is set to the beginning + //Pre - term holds a valid reference to a Term + // enumerator != NULL + //Post - An enumeration of terms starting at or after the named term has been returned + + SegmentTermEnum* enumerator = NULL; + if (term != NULL) { + //Seek enumerator to term; delete the new TermInfo that's returned. + TermInfo* ti = get(term); + _CLDELETE(ti); + enumerator = getEnum(); + } else { + enumerator = origEnum; + } + //Clone the entire enumeration + SegmentTermEnum* cln = enumerator->clone(); + + //Check if cln points to a valid instance + CND_CONDITION(cln != NULL, "cln is NULL"); + + return cln; +} + +void TermInfosReader::ensureIndexIsRead() +{ + //Func - Reads the term info index file or .tti file. + // This file contains every IndexInterval-th entry from the .tis file, + // along with its location in the "tis" file. This is designed to be + // read entirely into memory and used to provide random access to the + // "tis" file. + //Pre - indexTerms = NULL + // indexInfos = NULL + // indexPointers = NULL + //Post - The term info index file has been read into memory + + SCOPED_LOCK_MUTEX(THIS_LOCK) + + if ( indexTerms != NULL ) + return; + + try { + indexTermsLength = (size_t)indexEnum->size; + + // Instantiate an block of Term's,so that each one doesn't have to be new'd + indexTerms = _CL_NEWARRAY(Term,indexTermsLength); + + // Check if is indexTerms is a valid array + CND_CONDITION(indexTerms != NULL, + "No memory could be allocated for indexTerms"); + + // Instantiate an big block of TermInfo's, so that each one doesn't + // have to be new'd + indexInfos = _CL_NEWARRAY(TermInfo,indexTermsLength); + + // Check if is indexInfos is a valid array + CND_CONDITION(indexInfos != NULL, + "No memory could be allocated for indexInfos"); + + // Instantiate an array indexPointers that contains pointers to the + // term info index file + indexPointers = _CL_NEWARRAY(int64_t,indexTermsLength); + + // Check if is indexPointers is a valid array + CND_CONDITION(indexPointers != NULL, + "No memory could be allocated for indexPointers"); + + //Iterate through the terms of indexEnum + for (int32_t i = 0; indexEnum->next(); ++i) { + indexTerms[i].set(indexEnum->term(false), indexEnum->term(false)->text()); + indexEnum->getTermInfo(&indexInfos[i]); + indexPointers[i] = indexEnum->indexPointer; + } + } _CLFINALLY ( + indexEnum->close(); + // Close and delete the IndexInput is. The close is done by the destructor. + _CLDELETE( indexEnum->input ); + _CLDELETE( indexEnum ); + ); +} + +int32_t TermInfosReader::getIndexOffset(const Term* term) +{ + //Func - Returns the offset of the greatest index entry which is less than + // or equal to term. + //Pre - term holds a reference to a valid term + // indexTerms != NULL + //Post - The new offset has been returned + + //Check if is indexTerms is a valid array + CND_PRECONDITION(indexTerms != NULL, "indexTerms is NULL"); + + int32_t lo = 0; + int32_t hi = indexTermsLength - 1; + int32_t mid; + int32_t delta; + + while (hi >= lo) { + //Start in the middle betwee hi and lo + mid = (lo + hi) >> 1; + + //Check if is indexTerms[mid] is a valid instance of Term + CND_PRECONDITION(&indexTerms[mid] != NULL, "indexTerms[mid] is NULL"); + CND_PRECONDITION(mid < indexTermsLength, "mid >= indexTermsLength"); + + //Determine if term is before mid or after mid + delta = term->compareTo(&indexTerms[mid]); + if (delta < 0) { + //Calculate the new hi + hi = mid - 1; + } else if (delta > 0) { + //Calculate the new lo + lo = mid + 1; + } else { + //term has been found so return its position + return mid; + } + } + // the new starting offset + return hi; +} + +void TermInfosReader::seekEnum(const int32_t indexOffset) +{ + //Func - Reposition the current Term and TermInfo to indexOffset + //Pre - indexOffset >= 0 + // indexTerms != NULL + // indexInfos != NULL + // indexPointers != NULL + //Post - The current Term and Terminfo have been repositioned to indexOffset + + CND_PRECONDITION(indexOffset >= 0, "indexOffset contains a negative number"); + CND_PRECONDITION(indexTerms != NULL, "indexTerms is NULL"); + CND_PRECONDITION(indexInfos != NULL, "indexInfos is NULL"); + CND_PRECONDITION(indexPointers != NULL, "indexPointers is NULL"); + + SegmentTermEnum* enumerator = getEnum(); + enumerator->seek(indexPointers[indexOffset], + (indexOffset * enumerator->indexInterval) - 1, + &indexTerms[indexOffset], &indexInfos[indexOffset]); +} + +TermInfo* TermInfosReader::scanEnum(const Term* term) +{ + //Func - Scans the Enumeration of terms for term and returns the + // corresponding TermInfo instance if found. The search is started + // from the current term. + //Pre - term contains a valid reference to a Term + // enumerator != NULL + //Post - if term has been found the corresponding TermInfo has been returned + // otherwise NULL has been returned + + SegmentTermEnum* enumerator = getEnum(); + enumerator->scanTo(term); + + //Check if the at the position the Term term can be found + if (enumerator->term(false) != NULL && term->equals(enumerator->term(false))) { + //Return the TermInfo instance about term + return enumerator->getTermInfo(); + } + + //term was not found so no TermInfo can be returned + return NULL; +} + +Term* TermInfosReader::scanEnum(const int32_t position) +{ + //Func - Scans the enumeration to the requested position and returns the + // Term located at that position + //Pre - position > = 0 + // enumerator != NULL + //Post - The Term at the requested position has been returned + + SegmentTermEnum* enumerator = getEnum(); + + // As long the position of the enumeration enumerator is smaller than the + // requested one + while(enumerator->position < position) { + //Move the current of enumerator to the next + if (!enumerator->next()) { + //If there is no next it means that the requested position was to big + return NULL; + } + } + + //Return the Term a the requested position + return enumerator->term(); +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/TermInfosReader.h b/3rdparty/clucene/src/CLucene/index/TermInfosReader.h new file mode 100644 index 000000000..ed202e750 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/TermInfosReader.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#ifndef _lucene_index_TermInfosReader_ +#define _lucene_index_TermInfosReader_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include + +#include "CLucene/store/Directory.h" +#include "CLucene/util/ThreadLocal.h" +#include "SegmentTermEnum.h" + +CL_NS_DEF(index) + +class FieldInfos; +class Term; +class TermInfo; +class TermInfos; +class TermInfosWriter; + +// PORT STATUS: 365707 (jlucene 1.9) +// This stores a monotonically increasing set of pairs in a +// Directory. Pairs are accessed either by Term or by ordinal position the set. +class TermInfosReader : LUCENE_BASE +{ +private: + CL_NS(store)::Directory* directory; + QString segment; + FieldInfos* fieldInfos; + + CL_NS(util)::ThreadLocal > enumerators; + + SegmentTermEnum* getEnum(); + SegmentTermEnum* origEnum; + SegmentTermEnum* indexEnum; + int64_t _size; + + Term* indexTerms; + int32_t indexTermsLength; + TermInfo* indexInfos; + int64_t* indexPointers; + + DEFINE_MUTEX(THIS_LOCK) + +public: + // Reads the TermInfos file(.tis) and eventually the Term Info Index(.tii) + TermInfosReader(CL_NS(store)::Directory* dir, const QString& segment, + FieldInfos* fis); + ~TermInfosReader(); + + //Close the enumeration of TermInfos + void close(); + + //Return the size of the enumeration of TermInfos + int64_t size() const; + + int32_t getSkipInterval() { + return origEnum->skipInterval; } + + // Returns an enumeration of terms starting at or after the named term. + // If no term is specified, an enumeration of all the Terms + // and TermInfos in the set is returned. + SegmentTermEnum* terms(const Term* term = NULL); + + // Returns the TermInfo for a Term in the set + // synchronized + TermInfo* get(const Term* term); + +private: + // Reads the term info index file or .tti file. + void ensureIndexIsRead(); + + // Returns the offset of the greatest index entry which is less than term. + int32_t getIndexOffset(const Term* term); + + // Reposition the current Term and TermInfo to indexOffset + void seekEnum(const int32_t indexOffset); + + // Scans the Enumeration of terms for term and returns the corresponding + // TermInfo instance if found. The search is started from the current term. + TermInfo* scanEnum(const Term* term); + + // Scans the enumeration to the requested position and returns the Term + // located at that position + Term* scanEnum(const int32_t position); + + // Returns the position of a Term in the set. synchronized + int64_t getPosition(const Term* term); + + // Returns the nth term in the set. synchronized + Term* get(const int32_t position); +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/index/TermInfosWriter.cpp b/3rdparty/clucene/src/CLucene/index/TermInfosWriter.cpp new file mode 100644 index 000000000..c5b5340c3 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/TermInfosWriter.cpp @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#include "CLucene/StdHeader.h" +#include "TermInfosWriter.h" + +#include "CLucene/store/Directory.h" +#include "CLucene/util/Misc.h" +#include "FieldInfos.h" +#include "Term.h" +#include "TermInfo.h" +#include "IndexWriter.h" + +CL_NS_USE(util) +CL_NS_USE(store) +CL_NS_DEF(index) + +TermInfosWriter::TermInfosWriter(Directory* directory, const QString& segment, + FieldInfos* fis, int32_t interval) + : fieldInfos(fis) +{ + //Func - Constructor + //Pre - directory contains a valid reference to a Directory + // segment != NULL + // fis contains a valid reference to a reference FieldInfos + //Post - The instance has been created + + CND_PRECONDITION(!segment.isEmpty(), "segment is NULL"); + //Initialize instance + initialise(directory, segment, interval, false); + + other = _CLNEW TermInfosWriter(directory, segment, fieldInfos, interval, true); + + CND_CONDITION(other != NULL, "other is NULL"); + + other->other = this; +} + +TermInfosWriter::TermInfosWriter(Directory* directory, const QString& segment, + FieldInfos* fis, int32_t interval, bool isIndex) + : fieldInfos(fis) +{ + //Func - Constructor + //Pre - directory contains a valid reference to a Directory + // segment != NULL + // fis contains a valid reference to a reference FieldInfos + // isIndex is true or false + //Post - The instance has been created + + CND_PRECONDITION(!segment.isEmpty(), "segment is NULL"); + initialise(directory, segment, interval, isIndex); +} + +void TermInfosWriter::initialise(Directory* directory, const QString& segment, + int32_t interval, bool IsIndex) +{ + //Func - Helps constructors to initialize Instance + //Pre - directory contains a valid reference to a Directory + // segment != NULL + // fis contains a valid reference to a reference FieldInfos + //Post - The instance has been initialized + + lastTerm = _CLNEW Term; + + CND_CONDITION(lastTerm != NULL, "Could not allocate memory for lastTerm"); + + lastTi = _CLNEW TermInfo(); + + CND_CONDITION(lastTi != NULL, "Could not allocate memory for lastTi"); + + lastIndexPointer = 0; + size = 0; + isIndex = IsIndex; + indexInterval = interval; + skipInterval = LUCENE_DEFAULT_TERMDOCS_SKIP_INTERVAL; + + QString buf = Misc::segmentname(segment, QLatin1String(isIndex ? ".tii" : ".tis")); + output = directory->createOutput(buf); + + output->writeInt(FORMAT); // write format + output->writeLong(0); // leave space for size + output->writeInt(indexInterval);// write indexInterval + output->writeInt(skipInterval); // write skipInterval + + //Set other to NULL by Default + other = NULL; +} + +TermInfosWriter::~TermInfosWriter() +{ + //Func - Destructor + //Pre - true + //Post - de instance has been destroyed + + close(); +} + +void TermInfosWriter::add(Term* term, const TermInfo* ti) +{ + //Func - Writes a Term and TermInfo to the outputstream + //Pre - Term must be lexicographically greater than all previous Terms added. + // Pointers of TermInfo ti (freqPointer and proxPointer) must be + // positive and greater than all previous. + + CND_PRECONDITION(isIndex || (!isIndex && term->compareTo(lastTerm) > 0),"term out of order"); + CND_PRECONDITION(ti->freqPointer >= lastTi->freqPointer,"freqPointer out of order"); + CND_PRECONDITION(ti->proxPointer >= lastTi->proxPointer,"proxPointer out of order"); + + if (!isIndex && size % indexInterval == 0) { + //add an index term + other->add(lastTerm, lastTi); + } + + //write term + writeTerm(term); + // write doc freq + output->writeVInt(ti->docFreq); + //write pointers + output->writeVLong(ti->freqPointer - lastTi->freqPointer); + output->writeVLong(ti->proxPointer - lastTi->proxPointer); + if (ti->docFreq >= skipInterval) { + output->writeVInt(ti->skipOffset); + } + + if (isIndex){ + output->writeVLong(other->output->getFilePointer() - lastIndexPointer); + lastIndexPointer = other->output->getFilePointer(); // write pointer + } + + lastTi->set(ti); + size++; +} + +void TermInfosWriter::close() { + //Func - Closes the TermInfosWriter + //Pre - true + //Post - The TermInfosWriter has been closed + + if (output){ + //write size at start + output->seek(4); // write size after format + output->writeLong(size); + output->close(); + _CLDELETE(output); + + if (!isIndex){ + if(other){ + other->close(); + _CLDELETE( other ); + } + } + _CLDECDELETE(lastTerm); + + _CLDELETE(lastTi); + } +} + +void TermInfosWriter::writeTerm(Term* term) +{ + int32_t start = Misc::stringDifference(lastTerm->text(),lastTerm->textLength(), + term->text(),term->textLength()); + int32_t length = term->textLength() - start; + + output->writeVInt(start); // write shared prefix length + output->writeVInt(length); // write delta length + output->writeChars(term->text(), start, length); // write delta chars + + int32_t fieldnum = fieldInfos->fieldNumber(term->field()); + CND_PRECONDITION(fieldnum>=-1&&fieldnumsize(),"Fieldnum is out of range"); + output->writeVInt(fieldnum); // write field num + + if ( lastTerm->__cl_refcount == 1 ){ + lastTerm->set(term,term->text()); + }else{ + _CLDECDELETE(lastTerm); + lastTerm = _CL_POINTER(term); + } +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/TermInfosWriter.h b/3rdparty/clucene/src/CLucene/index/TermInfosWriter.h new file mode 100644 index 000000000..7e3c68699 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/TermInfosWriter.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#ifndef _lucene_index_TermInfosWriter_ +#define _lucene_index_TermInfosWriter_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include + +#include "CLucene/store/Directory.h" +#include "FieldInfos.h" +#include "TermInfo.h" +#include "Term.h" + +CL_NS_DEF(index) + + +// This stores a monotonically increasing set of pairs in a +// Directory. A TermInfos can be written once, in order. +class TermInfosWriter : LUCENE_BASE +{ +private: + FieldInfos* fieldInfos; + CL_NS(store)::IndexOutput* output; + Term* lastTerm; + TermInfo* lastTi; + int64_t size; + int64_t lastIndexPointer; + bool isIndex; + TermInfosWriter* other; + + //inititalize + TermInfosWriter(CL_NS(store)::Directory* directory, + const QString& segment, FieldInfos* fis, int32_t interval, bool isIndex); +public: + /** The file format version, a negative number. */ + LUCENE_STATIC_CONSTANT(int32_t,FORMAT=-2); + + /** + * Expert: The fraction of terms in the "dictionary" which should be stored + * in RAM. Smaller values use more memory, but make searching slightly + * faster, while larger values use less memory and make searching slightly + * slower. Searching is typically not dominated by dictionary lookup, so + * tweaking this is rarely useful. + */ + int32_t indexInterval;// = 128 + + /** + * Expert: The fraction of {@link TermDocs} entries stored in skip tables, + * used to accellerate {@link TermDocs#SkipTo(int32_t)}. Larger values result in + * smaller indexes, greater acceleration, but fewer accelerable cases, while + * smaller values result in bigger indexes, less acceleration and more + * accelerable cases. More detailed experiments would be useful here. + */ + int32_t skipInterval;// = 16 + + TermInfosWriter(CL_NS(store)::Directory* directory, + const QString& segment, FieldInfos* fis, int32_t interval); + + ~TermInfosWriter(); + + /** + * Adds a new pair to the set. + * Term must be lexicographically greater than all previous Terms added. + * TermInfo pointers must be positive and greater than all previous. + */ + void add(Term* term, const TermInfo* ti); + + /** Called to complete TermInfos creation. */ + void close(); + +private: + /** Helps constructors to initialize instances */ + void initialise(CL_NS(store)::Directory* directory, + const QString& segment, int32_t interval, bool IsIndex); + void writeTerm(Term* term); +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/index/TermVector.h b/3rdparty/clucene/src/CLucene/index/TermVector.h new file mode 100644 index 000000000..8601fbf53 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/TermVector.h @@ -0,0 +1,418 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#ifndef _lucene_index_termvector_h +#define _lucene_index_termvector_h + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include + +#include "CLucene/store/Directory.h" +#include "CLucene/store/IndexOutput.h" +#include "FieldInfos.h" + +CL_NS_DEF(index) + +struct TermVectorOffsetInfo; +class TermPositionVector; + +// Provides access to stored term vector of a document field. +class TermFreqVector : LUCENE_BASE +{ +public: + virtual ~TermFreqVector() {} + + // @return The field this vector is associated with. + virtual const TCHAR* getField() = 0; + + // @return The number of terms in the term vector. + virtual int32_t size() = 0; + + // @return An Array of term texts in ascending order. + virtual const TCHAR** getTerms() = 0; + + + /* Array of term frequencies. Locations of the array correspond one to one + * to the terms in the array obtained from getTerms + * method. Each location in the array contains the number of times this + * term occurs in the document or the document field. + * + * The size of the returned array is size() + * @memory Returning a pointer to internal data. Do not delete. + */ + virtual const Array* getTermFrequencies() = 0; + + + /* Return an index in the term numbers array returned from + * getTerms at which the term with the specified + * term appears. If this term does not appear in the array, + * return -1. + */ + virtual int32_t indexOf(const TCHAR* term) = 0; + + + /* Just like indexOf(int32_t) but searches for a number of terms + * at the same time. Returns an array that has the same size as the number + * of terms searched for, each slot containing the result of searching for + * that term number. + * + * @param terms array containing terms to look for + * @param start index in the array where the list of terms starts + * @param len the number of terms in the list + */ + virtual void indexesOf(const TCHAR** terms, const int32_t start, + const int32_t len, Array& ret) = 0; + + // Solve the diamond inheritence problem by providing a reinterpret function. + // No dynamic casting is required and no RTTI data is needed to do this + virtual TermPositionVector* __asTermPositionVector() = 0; +}; + + +/** +* Writer works by opening a document and then opening the fields within the document and then +* writing out the vectors for each field. +* +* Rough usage: +* + +for each document +{ +writer.openDocument(); +for each field on the document +{ +writer.openField(field); +for all of the terms +{ +writer.addTerm(...) +} +writer.closeField +} +writer.closeDocument() +} + +*/ +class TermVectorsWriter : LUCENE_BASE +{ +private: + class TVField : LUCENE_BASE + { + public: + int32_t number; + int64_t tvfPointer; + int32_t length; // number of distinct term positions + bool storePositions; + bool storeOffsets; + + TVField(int32_t number, bool storePos, bool storeOff) + : tvfPointer(0) + , length(0) + { + this->number = number; + this->storePositions = storePos; + this->storeOffsets = storeOff; + } + ~TVField() {} + }; + + class TVTerm : LUCENE_BASE + { + const TCHAR* termText; + int32_t termTextLen; //textlen cache + + public: + TVTerm(); + ~TVTerm(); + + int32_t freq; + Array* positions; + Array* offsets; + + const TCHAR* getTermText() const; + size_t getTermTextLen(); + void setTermText(const TCHAR* val); + }; + + CL_NS(store)::IndexOutput* tvx, *tvd, *tvf; + CL_NS(util)::CLVector > fields; + CL_NS(util)::CLVector > terms; + FieldInfos* fieldInfos; + + TVField* currentField; + int64_t currentDocPointer; + + void addTermInternal(const TCHAR* termText, const int32_t freq, + Array* positions, Array* offsets); + + void writeField(); + void writeDoc(); + + void openField(int32_t fieldNumber, bool storePositionWithTermVector, + bool storeOffsetWithTermVector); + +public: + LUCENE_STATIC_CONSTANT(int32_t, FORMAT_VERSION = 2); + + // The size in bytes that the FORMAT_VERSION will take up at the beginning + // of each file + LUCENE_STATIC_CONSTANT(int32_t, FORMAT_SIZE = 4); + + LUCENE_STATIC_CONSTANT(uint8_t, STORE_POSITIONS_WITH_TERMVECTOR = 0x1); + LUCENE_STATIC_CONSTANT(uint8_t, STORE_OFFSET_WITH_TERMVECTOR = 0x2); + + static const QLatin1String LUCENE_TVX_EXTENSION; + static const QLatin1String LUCENE_TVD_EXTENSION; + static const QLatin1String LUCENE_TVF_EXTENSION; + + TermVectorsWriter(CL_NS(store)::Directory* directory, const QString& segment, + FieldInfos* fieldInfos); + + ~TermVectorsWriter(); + void openDocument(); + void closeDocument(); + + /** Close all streams. */ + void close(); + bool isDocumentOpen() const; + + /** Start processing a field. This can be followed by a number of calls to + * addTerm, and a final call to closeField to indicate the end of + * processing of this field. If a field was previously open, it is + * closed automatically. + */ + void openField(const TCHAR* field); + + /** Finished processing current field. This should be followed by a call to + * openField before future calls to addTerm. + */ + void closeField(); + + /** Return true if a field is currently open. */ + bool isFieldOpen() const; + + /** + * Add a complete document specified by all its term vectors. If document has no + * term vectors, add value for tvx. + * + * @param vectors + * @throws IOException + */ + void addAllDocVectors(Array& vectors); + + /** Add term to the field's term vector. Field must already be open. + * Terms should be added in + * increasing order of terms, one call per unique termNum. ProxPointer + * is a pointer into the TermPosition file (prx). Freq is the number of + * times this term appears in this field, in this document. + * @throws IllegalStateException if document or field is not open + */ + void addTerm(const TCHAR* termText, int32_t freq, + Array* positions = NULL, Array* offsets = NULL); +}; + +class SegmentTermVector : public virtual TermFreqVector +{ +private: + const TCHAR* field; + TCHAR** terms; + int32_t termsLen; //cache + Array* termFreqs; + + int32_t binarySearch(TCHAR** a, const int32_t arraylen, const TCHAR* key) const; +public: + //note: termFreqs must be the same length as terms + SegmentTermVector(const TCHAR* field, TCHAR** terms, Array* termFreqs); + virtual ~SegmentTermVector(); + + /** + * + * @return The number of the field this vector is associated with + */ + const TCHAR* getField(); + TCHAR* toString() const; + int32_t size(); + const TCHAR** getTerms(); + const Array* getTermFrequencies(); + int32_t indexOf(const TCHAR* termText); + void indexesOf(const TCHAR** termNumbers, const int32_t start, const int32_t len, Array& ret); + + virtual TermPositionVector* __asTermPositionVector(); +}; + +class TermVectorsReader : LUCENE_BASE +{ +private: + FieldInfos* fieldInfos; + + CL_NS(store)::IndexInput* tvx; + CL_NS(store)::IndexInput* tvd; + CL_NS(store)::IndexInput* tvf; + int64_t _size; + + int32_t tvdFormat; + int32_t tvfFormat; + + + int32_t checkValidFormat(CL_NS(store)::IndexInput* in); + + void readTermVectors(const TCHAR** fields, const int64_t* tvfPointers, + const int32_t len, Array& _return); + + /** + * + * @param field The field to read in + * @param tvfPointer The pointer within the tvf file where we should start reading + * @return The TermVector located at that position + * @throws IOException + */ + SegmentTermVector* readTermVector(const TCHAR* field, const int64_t tvfPointer); + + int64_t size(); + + + DEFINE_MUTEX(THIS_LOCK) + TermVectorsReader(const TermVectorsReader& copy); +public: + TermVectorsReader(CL_NS(store)::Directory* d, const QString& segment, + FieldInfos* fieldInfos); + ~TermVectorsReader(); + + void close(); + TermVectorsReader* clone() const; + + /** + * Retrieve the term vector for the given document and field + * @param docNum The document number to retrieve the vector for + * @param field The field within the document to retrieve + * @return The TermFreqVector for the document and field or null if there is no termVector for this field. + * @throws IOException if there is an error reading the term vector files + */ + TermFreqVector* get(const int32_t docNum, const TCHAR* field); + + + /** + * Return all term vectors stored for this document or null if the could not be read in. + * + * @param docNum The document number to retrieve the vector for + * @return All term frequency vectors + * @throws IOException if there is an error reading the term vector files + */ + bool get(int32_t docNum, Array& result); +}; + + +struct TermVectorOffsetInfo +{ + int startOffset; + int endOffset; + +public: + static Array EMPTY_OFFSET_INFO; + TermVectorOffsetInfo(); + ~TermVectorOffsetInfo(); + TermVectorOffsetInfo(int32_t startOffset, int32_t endOffset); + int32_t getEndOffset() const; + void setEndOffset(int32_t endOffset); + int32_t getStartOffset() const; + void setStartOffset(int32_t startOffset); + bool equals(TermVectorOffsetInfo* o); + size_t hashCode() const; +}; + + +/* Extends TermFreqVector to provide additional information about + * positions in which each of the terms is found. A TermPositionVector not + * necessarily contains both positions and offsets, but at least one of these + * arrays exists. +*/ +class TermPositionVector : public virtual TermFreqVector +{ +public: + + /** Returns an array of positions in which the term is found. + * Terms are identified by the index at which its number appears in the + * term String array obtained from the indexOf method. + * May return null if positions have not been stored. + */ + virtual Array* getTermPositions(int32_t index) = 0; + + /** + * Returns an array of TermVectorOffsetInfo in which the term is found. + * May return null if offsets have not been stored. + * + * @see org.apache.lucene.analysis.Token + * + * @param index The position in the array to get the offsets from + * @return An array of TermVectorOffsetInfo objects or the empty list + */ + virtual Array* getOffsets(int32_t index) = 0; + + virtual ~TermPositionVector(){ + } +}; + + +class SegmentTermPositionVector: public SegmentTermVector, public TermPositionVector +{ +protected: + Array< Array >* positions; + Array< Array >* offsets; + static Array EMPTY_TERM_POS; +public: + SegmentTermPositionVector(const TCHAR* field, TCHAR** terms, + Array* termFreqs, Array< Array >* positions, + Array< Array >* offsets); + ~SegmentTermPositionVector(); + + /** + * Returns an array of TermVectorOffsetInfo in which the term is found. + * + * @param index The position in the array to get the offsets from + * @return An array of TermVectorOffsetInfo objects or the empty list + * @see org.apache.lucene.analysis.Token + */ + Array* getOffsets(int32_t index); + + /** + * Returns an array of positions in which the term is found. + * Terms are identified by the index at which its number appears in the + * term String array obtained from the indexOf method. + */ + Array* getTermPositions(int32_t index); + + const TCHAR* getField() { + return SegmentTermVector::getField(); } + + TCHAR* toString() const { + return SegmentTermVector::toString(); } + + int32_t size() { + return SegmentTermVector::size(); } + + const TCHAR** getTerms() { + return SegmentTermVector::getTerms(); } + + const Array* getTermFrequencies() { + return SegmentTermVector::getTermFrequencies(); } + + int32_t indexOf(const TCHAR* termText) { + return SegmentTermVector::indexOf(termText); } + + void indexesOf(const TCHAR** termNumbers, const int32_t start, + const int32_t len, Array& ret) { + SegmentTermVector::indexesOf(termNumbers, start, len, ret); } + + virtual TermPositionVector* __asTermPositionVector(); +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/index/TermVectorReader.cpp b/3rdparty/clucene/src/CLucene/index/TermVectorReader.cpp new file mode 100644 index 000000000..53d909b29 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/TermVectorReader.cpp @@ -0,0 +1,393 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#include "CLucene/StdHeader.h" +#include "TermVector.h" +#include "CLucene/util/StringBuffer.h" + +CL_NS_USE(util) +CL_NS_DEF(index) + +TermVectorsReader::TermVectorsReader(CL_NS(store)::Directory* d, + const QString& segment, FieldInfos* fieldInfos) +{ + if (d->fileExists(segment + TermVectorsWriter::LUCENE_TVX_EXTENSION)) { + tvx = d->openInput(segment + TermVectorsWriter::LUCENE_TVX_EXTENSION); + checkValidFormat(tvx); + + tvd = d->openInput(segment + TermVectorsWriter::LUCENE_TVD_EXTENSION); + tvdFormat = checkValidFormat(tvd); + + tvf = d->openInput(segment + TermVectorsWriter::LUCENE_TVF_EXTENSION); + tvfFormat = checkValidFormat(tvf); + + _size = tvx->length() / 8; + }else{ + tvx = NULL; + tvd = NULL; + tvf = NULL; + _size = 0; + } + + this->fieldInfos = fieldInfos; +} + +TermVectorsReader::TermVectorsReader(const TermVectorsReader& copy) +{ + tvx = copy.tvx->clone(); + tvd = copy.tvd->clone(); + tvf = copy.tvf->clone(); + + tvdFormat = copy.tvdFormat; + tvfFormat = copy.tvfFormat; + _size = copy._size; + fieldInfos = copy.fieldInfos; +} +TermVectorsReader* TermVectorsReader::clone() const{ + if (tvx == NULL || tvd == NULL || tvf == NULL) + return NULL; + return _CLNEW TermVectorsReader(*this); +} + +TermVectorsReader::~TermVectorsReader(){ + close(); +} + +void TermVectorsReader::close(){ + // why don't we trap the exception and at least make sure that + // all streams that we can close are closed? + CLuceneError keep(0,"",false); + bool thrown = false; + + if (tvx != NULL){ + try{ + tvx->close(); + }catch(CLuceneError& err){ + if ( err.number() == CL_ERR_IO ){ + keep = err; + thrown = true; + }else + throw err; + } + _CLDELETE(tvx);//delete even if error thrown + } + if (tvd != NULL){ + try{ + tvd->close(); + }catch(CLuceneError& err){ + if ( err.number() == CL_ERR_IO ){ + keep = err; + thrown = true; + }else + throw err; + } + _CLDELETE(tvd); + } + if (tvf != NULL){ + try{ + tvf->close(); + }catch(CLuceneError& err){ + if ( err.number() == CL_ERR_IO ){ + keep = err; + thrown = true; + }else + throw err; + } + _CLDELETE(tvf); + } + + if ( thrown ) + throw keep; +} + +TermFreqVector* TermVectorsReader::get(const int32_t docNum, const TCHAR* field){ + // Check if no term vectors are available for this segment at all + int32_t fieldNumber = fieldInfos->fieldNumber(field); + TermFreqVector* result = NULL; + if (tvx != NULL) { + //We need to account for the FORMAT_SIZE at when seeking in the tvx + //We don't need to do this in other seeks because we already have the + // file pointer + //that was written in another file + tvx->seek((docNum * 8L) + TermVectorsWriter::FORMAT_SIZE); + int64_t position = tvx->readLong(); + + tvd->seek(position); + int32_t fieldCount = tvd->readVInt(); + // There are only a few fields per document. We opt for a full scan + // rather then requiring that they be ordered. We need to read through + // all of the fields anyway to get to the tvf pointers. + int32_t number = 0; + int32_t found = -1; + for (int32_t i = 0; i < fieldCount; ++i) { + if(tvdFormat == TermVectorsWriter::FORMAT_VERSION) + number = tvd->readVInt(); + else + number += tvd->readVInt(); + if (number == fieldNumber) + found = i; + } + + // This field, although valid in the segment, was not found in this + // document + if (found != -1) { + // Compute position in the tvf file + position = 0; + for (int32_t i = 0; i <= found; ++i) + position += tvd->readVLong(); + result = readTermVector(field, position); + } + } + return result; +} + + +bool TermVectorsReader::get(int32_t docNum, Array& result){ + // Check if no term vectors are available for this segment at all + if (tvx != NULL) { + //We need to offset by + tvx->seek((docNum * 8L) + TermVectorsWriter::FORMAT_SIZE); + int64_t position = tvx->readLong(); + + tvd->seek(position); + int32_t fieldCount = tvd->readVInt(); + + // No fields are vectorized for this document + if (fieldCount != 0) { + int32_t number = 0; + const TCHAR** fields = _CL_NEWARRAY(const TCHAR*,fieldCount+1); + + { //msvc6 scope fix + for (int32_t i = 0; i < fieldCount; ++i) { + if(tvdFormat == TermVectorsWriter::FORMAT_VERSION) + number = tvd->readVInt(); + else + number += tvd->readVInt(); + fields[i] = fieldInfos->fieldName(number); + } + } + fields[fieldCount]=NULL; + + // Compute position in the tvf file + position = 0; + int64_t* tvfPointers = _CL_NEWARRAY(int64_t,fieldCount); + { //msvc6 scope fix + for (int32_t i = 0; i < fieldCount; ++i) { + position += tvd->readVLong(); + tvfPointers[i] = position; + } + } + + readTermVectors(fields, tvfPointers, fieldCount, result); + _CLDELETE_ARRAY(tvfPointers); + _CLDELETE_ARRAY(fields); + } + return true; + } + return false; +} + + +int32_t TermVectorsReader::checkValidFormat(CL_NS(store)::IndexInput* in) +{ + int32_t format = in->readInt(); + if (format > TermVectorsWriter::FORMAT_VERSION) + { + CL_NS(util)::StringBuffer err; + err.append(_T("Incompatible format version: ")); + err.appendInt(format); + err.append(_T(" expected ")); + err.appendInt(TermVectorsWriter::FORMAT_VERSION); + err.append(_T(" or less")); + _CLTHROWT(CL_ERR_Runtime,err.getBuffer()); + } + return format; +} + +void TermVectorsReader::readTermVectors(const TCHAR** fields, + const int64_t* tvfPointers, const int32_t len, Array& result) +{ + result.length = len; + result.values = _CL_NEWARRAY(TermFreqVector*,len); + for (int32_t i = 0; i < len; ++i) { + result.values[i] = readTermVector(fields[i], tvfPointers[i]); + } +} + +SegmentTermVector* TermVectorsReader::readTermVector(const TCHAR* field, + const int64_t tvfPointer) +{ + // Now read the data from specified position. We don't need to offset by + // the FORMAT here since the pointer already includes the offset + tvf->seek(tvfPointer); + + int32_t numTerms = tvf->readVInt(); + // If no terms - return a constant empty termvector. However, this should never occur! + if (numTerms == 0) + return _CLNEW SegmentTermVector(field, NULL, NULL); + + bool storePositions; + bool storeOffsets; + + if(tvfFormat == TermVectorsWriter::FORMAT_VERSION){ + uint8_t bits = tvf->readByte(); + storePositions = (bits & TermVectorsWriter::STORE_POSITIONS_WITH_TERMVECTOR) != 0; + storeOffsets = (bits & TermVectorsWriter::STORE_OFFSET_WITH_TERMVECTOR) != 0; + } + else{ + tvf->readVInt(); + storePositions = false; + storeOffsets = false; + } + + TCHAR** terms = _CL_NEWARRAY(TCHAR*,numTerms+1); + Array* termFreqs = _CLNEW Array(numTerms); + + // we may not need these, but declare them + Array< Array >* positions = NULL; + Array< Array >* offsets = NULL; + if(storePositions){ + Array* tmp = _CL_NEWARRAY(Array,numTerms); + positions = _CLNEW Array< Array >(tmp, numTerms); + } + if(storeOffsets){ + Array* tmp = _CL_NEWARRAY(Array,numTerms); + offsets = _CLNEW Array< Array >(tmp, numTerms); + } + + int32_t start = 0; + int32_t deltaLength = 0; + int32_t totalLength = 0; + int32_t bufferLen=10; // init the buffer with a length of 10 character + TCHAR* buffer = (TCHAR*)malloc(bufferLen * sizeof(TCHAR)); + + for (int32_t i = 0; i < numTerms; ++i) { + start = tvf->readVInt(); + deltaLength = tvf->readVInt(); + totalLength = start + deltaLength; + if (bufferLen < totalLength) // increase buffer + { + buffer=(TCHAR*)realloc(buffer,totalLength * sizeof(TCHAR)); + bufferLen = totalLength; + } + + //read the term + tvf->readChars(buffer, start, deltaLength); + terms[i] = _CL_NEWARRAY(TCHAR,totalLength+1); + _tcsncpy(terms[i],buffer,totalLength); + terms[i][totalLength] = '\0'; //null terminate term + + //read the frequency + int32_t freq = tvf->readVInt(); + termFreqs->values[i] = freq; + + if (storePositions) { //read in the positions + Array& pos = positions->values[i]; + pos.length = freq; + pos.values = _CL_NEWARRAY(int32_t,freq); + + int32_t prevPosition = 0; + for (int32_t j = 0; j < freq; ++j) + { + pos.values[j] = prevPosition + tvf->readVInt(); + prevPosition = pos.values[j]; + } + } + + if (storeOffsets) { + Array& offs = offsets->values[i]; + offs.length = freq; + offs.values = _CL_NEWARRAY(TermVectorOffsetInfo,freq); + + int32_t prevOffset = 0; + for (int32_t j = 0; j < freq; ++j) { + int32_t startOffset = prevOffset + tvf->readVInt(); + int32_t endOffset = startOffset + tvf->readVInt(); + offs.values[j].setStartOffset(startOffset); + offs.values[j].setEndOffset(endOffset); + prevOffset = endOffset; + } + } + } + free(buffer); + terms[numTerms]=NULL; //null terminate terms array + + SegmentTermVector* tv = NULL; + if (storePositions || storeOffsets){ + return _CLNEW SegmentTermPositionVector(field, terms, termFreqs, positions, offsets); + }else { + return _CLNEW SegmentTermVector(field, terms, termFreqs); + } +} + +int64_t TermVectorsReader::size() +{ + return _size; +} + + + + +Array TermVectorOffsetInfo::EMPTY_OFFSET_INFO; + +TermVectorOffsetInfo::TermVectorOffsetInfo() +{ + startOffset = 0; + endOffset=0; +} + +TermVectorOffsetInfo::~TermVectorOffsetInfo() +{ +} + +TermVectorOffsetInfo::TermVectorOffsetInfo(int32_t startOffset, int32_t endOffset) +{ + this->endOffset = endOffset; + this->startOffset = startOffset; +} + +int32_t TermVectorOffsetInfo::getEndOffset() const +{ + return endOffset; +} + +void TermVectorOffsetInfo::setEndOffset(int32_t endOffset) +{ + this->endOffset = endOffset; +} + +int32_t TermVectorOffsetInfo::getStartOffset() const +{ + return startOffset; +} + +void TermVectorOffsetInfo::setStartOffset(int32_t startOffset) +{ + this->startOffset = startOffset; +} + +bool TermVectorOffsetInfo::equals(TermVectorOffsetInfo* termVectorOffsetInfo) +{ + if (this == termVectorOffsetInfo) + return true; + + if (endOffset != termVectorOffsetInfo->endOffset) return false; + if (startOffset != termVectorOffsetInfo->startOffset) return false; + + return true; +} + +size_t TermVectorOffsetInfo::hashCode() const +{ + size_t result; + result = startOffset; + result = 29 * result + endOffset; + return result; +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/TermVectorWriter.cpp b/3rdparty/clucene/src/CLucene/index/TermVectorWriter.cpp new file mode 100644 index 000000000..276b1bbd0 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/TermVectorWriter.cpp @@ -0,0 +1,349 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#include "CLucene/StdHeader.h" +#include "TermVector.h" +#include "CLucene/util/Misc.h" + +CL_NS_USE(util) +CL_NS_DEF(index) + +const QLatin1String TermVectorsWriter::LUCENE_TVX_EXTENSION(".tvx"); +const QLatin1String TermVectorsWriter::LUCENE_TVD_EXTENSION(".tvd"); +const QLatin1String TermVectorsWriter::LUCENE_TVF_EXTENSION(".tvf"); + +TermVectorsWriter::TermVectorsWriter(CL_NS(store)::Directory* directory, + const QString& segment,FieldInfos* fieldInfos) +{ + // Open files for TermVector storage + tvx = directory->createOutput(segment + LUCENE_TVX_EXTENSION); + tvx->writeInt(FORMAT_VERSION); + + tvd = directory->createOutput(segment + LUCENE_TVD_EXTENSION); + tvd->writeInt(FORMAT_VERSION); + + tvf = directory->createOutput(segment + LUCENE_TVF_EXTENSION); + tvf->writeInt(FORMAT_VERSION); + + this->fieldInfos = fieldInfos; + + currentField = NULL; + currentDocPointer = -1; +} + +TermVectorsWriter::~TermVectorsWriter() +{ + if (tvx != NULL) { + tvx->close(); + _CLDELETE(tvx); + } + + if (tvd != NULL) { + tvd->close(); + _CLDELETE(tvd); + } + + if (tvf != NULL){ + tvf->close(); + _CLDELETE(tvf); + } +} + +void TermVectorsWriter::openDocument() +{ + closeDocument(); + currentDocPointer = tvd->getFilePointer(); +} + +void TermVectorsWriter::closeDocument() +{ + if (isDocumentOpen()) { + closeField(); + writeDoc(); + fields.clear(); + currentDocPointer = -1; + } +} + +bool TermVectorsWriter::isDocumentOpen() const +{ + return currentDocPointer != -1; +} + + +void TermVectorsWriter::openField(int32_t fieldNumber, + bool storePositionWithTermVector, bool storeOffsetWithTermVector) +{ + if (!isDocumentOpen()) + _CLTHROWA(CL_ERR_InvalidState,"Cannot open field when no document is open."); + + closeField(); + currentField = _CLNEW TVField(fieldNumber, storePositionWithTermVector, + storeOffsetWithTermVector); +} + +void TermVectorsWriter::openField(const TCHAR* field) +{ + FieldInfo* fieldInfo = fieldInfos->fieldInfo(field); + openField(fieldInfo->number, fieldInfo->storePositionWithTermVector, + fieldInfo->storeOffsetWithTermVector); +} + +void TermVectorsWriter::closeField() +{ + if (isFieldOpen()) { + /* DEBUG */ + //System.out.println("closeField()"); + /* DEBUG */ + + // save field and terms + writeField(); + fields.push_back(currentField); + terms.clear(); + currentField = NULL; + } +} + +bool TermVectorsWriter::isFieldOpen() const +{ + return currentField != NULL; +} + +void TermVectorsWriter::addTerm(const TCHAR* termText, int32_t freq, + Array* positions, Array* offsets) +{ + if (!isDocumentOpen()) + _CLTHROWA(CL_ERR_InvalidState, "Cannot add terms when document is not open"); + + if (!isFieldOpen()) + _CLTHROWA(CL_ERR_InvalidState, "Cannot add terms when field is not open"); + + addTermInternal(termText, freq, positions, offsets); +} + +void TermVectorsWriter::addTermInternal(const TCHAR* termText, int32_t freq, + Array* positions, Array* offsets) +{ + TVTerm* term = _CLNEW TVTerm(); + term->setTermText(termText); + term->freq = freq; + term->positions = positions; + term->offsets = offsets; + terms.push_back(term); +} + +void TermVectorsWriter::addAllDocVectors(Array& vectors) +{ + openDocument(); + + for (int32_t i = 0; i < vectors.length; ++i) { + bool storePositionWithTermVector = false; + bool storeOffsetWithTermVector = false; + + if ( vectors[i]->__asTermPositionVector() != NULL ) { + TermPositionVector* tpVector = vectors[i]->__asTermPositionVector(); + + if (tpVector->size() > 0 && tpVector->getTermPositions(0) != NULL) + storePositionWithTermVector = true; + if (tpVector->size() > 0 && tpVector->getOffsets(0) != NULL) + storeOffsetWithTermVector = true; + + FieldInfo* fieldInfo = fieldInfos->fieldInfo(tpVector->getField()); + openField(fieldInfo->number, storePositionWithTermVector, storeOffsetWithTermVector); + + for (int32_t j = 0; j < tpVector->size(); ++j) + addTermInternal(tpVector->getTerms()[j], + (*tpVector->getTermFrequencies())[j], + tpVector->getTermPositions(j), + tpVector->getOffsets(j)); + + closeField(); + + } else { + TermFreqVector* tfVector = vectors[i]; + + FieldInfo* fieldInfo = fieldInfos->fieldInfo(tfVector->getField()); + openField(fieldInfo->number, storePositionWithTermVector, storeOffsetWithTermVector); + + for (int32_t j = 0; j < tfVector->size(); ++j) + addTermInternal(tfVector->getTerms()[j], + (*tfVector->getTermFrequencies())[j], NULL, NULL); + + closeField(); + } + } + + closeDocument(); +} + + +void TermVectorsWriter::close() +{ + try { + closeDocument(); + + // make an effort to close all streams we can but remember and re-throw + // the first exception encountered in this process +#define _DOTVWCLOSE(x) \ + if (x != NULL) { \ + try { \ + x->close(); \ + _CLDELETE(x) \ + } catch (CLuceneError& e) { \ + if ( e.number() != CL_ERR_IO ) \ + throw e; \ + if (ikeep == 0) \ + ikeep = e.number(); \ + if (keep[0] == 0) \ + strcpy(keep,e.what()); \ + } catch (...) { \ + if (keep[0] == 0) \ + strcpy(keep, "Unknown error while closing " #x);\ + } \ + } + } _CLFINALLY ( \ + char keep[200]; + int32_t ikeep = 0; + keep[0] = 0; + _DOTVWCLOSE(tvx); + _DOTVWCLOSE(tvd); + _DOTVWCLOSE(tvf); + if (keep[0] != 0) + _CLTHROWA(ikeep, keep); + ); +} + +void TermVectorsWriter::writeField() +{ + // remember where this field is written + currentField->tvfPointer = tvf->getFilePointer(); + //System.out.println("Field Pointer: " + currentField.tvfPointer); + int32_t size = terms.size(); + + tvf->writeVInt(size); + + bool storePositions = currentField->storePositions; + bool storeOffsets = currentField->storeOffsets; + uint8_t bits = 0x0; + if (storePositions) + bits |= STORE_POSITIONS_WITH_TERMVECTOR; + if (storeOffsets) + bits |= STORE_OFFSET_WITH_TERMVECTOR; + tvf->writeByte(bits); + + const TCHAR* lastTermText = LUCENE_BLANK_STRING; + int32_t lastTermTextLen = 0; + + for (int32_t i = 0; i < size; ++i) { + TVTerm* term = terms[i]; + int32_t start = CL_NS(util)::Misc::stringDifference(lastTermText, + lastTermTextLen, term->getTermText(),term->getTermTextLen()); + int32_t length = term->getTermTextLen() - start; + tvf->writeVInt(start); // write shared prefix length + tvf->writeVInt(length); // write delta length + tvf->writeChars(term->getTermText(), start, length); // write delta chars + tvf->writeVInt(term->freq); + + lastTermText = term->getTermText(); + lastTermTextLen = term->getTermTextLen(); + + if (storePositions) { + if(term->positions == NULL) + _CLTHROWA(CL_ERR_IllegalState, "Trying to write positions that are NULL!"); + + // use delta encoding for positions + int32_t position = 0; + for (int32_t j = 0; j < term->freq; ++j){ + tvf->writeVInt((*term->positions)[j] - position); + position = (*term->positions)[j]; + } + } + + if (storeOffsets) { + if(term->offsets == NULL) + _CLTHROWA(CL_ERR_IllegalState, "Trying to write offsets that are NULL!"); + + // use delta encoding for offsets + int32_t position = 0; + for (int32_t j = 0; j < term->freq; ++j) { + tvf->writeVInt((*term->offsets)[j].getStartOffset() - position); + //Save the diff between the two. + tvf->writeVInt((*term->offsets)[j].getEndOffset() - + (*term->offsets)[j].getStartOffset()); + position = (*term->offsets)[j].getEndOffset(); + } + } + } +} + +void TermVectorsWriter::writeDoc() +{ + if (isFieldOpen()) { + _CLTHROWA(CL_ERR_InvalidState, + "Field is still open while writing document"); + } + + // write document index record + tvx->writeLong(currentDocPointer); + + // write document data record + int32_t size = fields.size(); + + // write the number of fields + tvd->writeVInt(size); + + // write field numbers + for (int32_t j = 0; j < size; ++j) { + tvd->writeVInt(fields[j]->number); + } + + // write field pointers + int64_t lastFieldPointer = 0; + for (int32_t i = 0; i < size; ++i) { + TVField* field = (TVField*) fields[i]; + tvd->writeVLong(field->tvfPointer - lastFieldPointer); + + lastFieldPointer = field->tvfPointer; + } +} + +const TCHAR* TermVectorsWriter::TVTerm::getTermText() const +{ + return termText; +} + +size_t TermVectorsWriter::TVTerm::getTermTextLen() +{ + if (termTextLen==-1) + termTextLen = _tcslen(termText); + return termTextLen; +} + +void TermVectorsWriter::TVTerm::setTermText(const TCHAR* val) +{ + _CLDELETE_CARRAY(termText); + termText = STRDUP_TtoT(val); + termTextLen = -1; + +} + +TermVectorsWriter::TVTerm::TVTerm() + : freq(0) + , positions(NULL) + , offsets(NULL) +{ + termText=NULL; + termTextLen=-1; +} + +TermVectorsWriter::TVTerm::~TVTerm() +{ + _CLDELETE_CARRAY(termText) +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/index/Terms.h b/3rdparty/clucene/src/CLucene/index/Terms.h new file mode 100644 index 000000000..806441876 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/index/Terms.h @@ -0,0 +1,174 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_index_Terms_ +#define _lucene_index_Terms_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "Term.h" +CL_NS_DEF(index) + +class TermEnum; //predefine +class TermPositions; + +/** TermDocs provides an interface for enumerating <document, frequency> + pairs for a term.

The document portion names each document containing + the term. Documents are indicated by number. The frequency portion gives + the number of times the term occurred in each document.

The pairs are + ordered by document number. + + @see IndexReader#termDocs() + */ +class TermDocs: LUCENE_BASE { +public: + virtual ~TermDocs(){ + } + + // Sets this to the data for a term. + // The enumeration is reset to the start of the data for this term. + virtual void seek(Term* term)=0; + + /** Sets this to the data for the current term in a {@link TermEnum}. + * This may be optimized in some implementations. + */ + virtual void seek(TermEnum* termEnum)=0; + + // Returns the current document number.

This is invalid until {@link + // #next()} is called for the first time. + virtual int32_t doc() const=0; + + // Returns the frequency of the term within the current document.

This + // is invalid until {@link #next()} is called for the first time. + virtual int32_t freq() const=0; + + // Moves to the next pair in the enumeration.

Returns true iff there is + // such a next pair in the enumeration. + virtual bool next() =0; + + // Attempts to read multiple entries from the enumeration, up to length of + // docs. Document numbers are stored in docs, and term + // frequencies are stored in freqs. The freqs array must be as + // int64_t as the docs array. + // + //

Returns the number of entries read. Zero is only returned when the + // stream has been exhausted. + virtual int32_t read(int32_t* docs, int32_t* freqs, int32_t length)=0; + + // Skips entries to the first beyond the current whose document number is + // greater than or equal to target.

Returns true iff there is such + // an entry.

Behaves as if written:

+	//   bool skipTo(int32_t target) {
+	//     do {
+	//       if (!next())
+	// 	     return false;
+	//     } while (target > doc());
+	//     return true;
+	//   }
+	// 
+ // Some implementations are considerably more efficient than that. + virtual bool skipTo(const int32_t target)=0; + + // Frees associated resources. + virtual void close() = 0; + + + /** Solve the diamond inheritence problem by providing a reinterpret function. + * No dynamic casting is required and no RTTI data is needed to do this + */ + virtual TermPositions* __asTermPositions()=0; +}; + + +// Abstract class for enumerating terms. +// +//

Term enumerations are always ordered by Term.compareTo(). Each term in +//the enumeration is greater than all that precede it. +class TermEnum: LUCENE_BASE { +public: + // Increments the enumeration to the next element. True if one exists. + virtual bool next()=0; + + // Returns a pointer to the current Term in the enumeration. + virtual Term* term()=0; + + // Returns the current Term in the enumeration. + virtual Term* term(bool pointer){ + Term* ret = term(); + if ( !pointer ) + ret->__cl_decref(); + return ret; + } + + // Returns the docFreq of the current Term in the enumeration. + virtual int32_t docFreq() const=0; + + // Closes the enumeration to further activity, freeing resources. + virtual void close() =0; + + virtual ~TermEnum(){ + } + + // Term Vector support + /** Skips terms to the first beyond the current whose value is + * greater or equal to target.

Returns true iff there is such + * an entry.

Behaves as if written:

+	*   public boolean skipTo(Term target) {
+	*     do {
+	*       if (!next())
+	* 	     return false;
+	*     } while (target > term());
+	*     return true;
+	*   }
+	* 
+ * Some implementations are considerably more efficient than that. + */ + virtual bool skipTo(Term* target){ + do { + if (!next()) + return false; + } while (target->compareTo(term(false)) > 0); + return true; + } + + /** + * Because we need to know how to cast the object, we need the objects name. + */ + virtual const char* getObjectName() = 0; +}; + + + +/** + * TermPositions provides an interface for enumerating the <document, + * frequency, <position>* > tuples for a term.

The document and + * frequency are the same as for a TermDocs. The positions portion lists the ordinal + * positions of each occurrence of a term in a document. + * + * @see IndexReader#termPositions() + */ +class TermPositions: public virtual TermDocs { +public: + // Returns next position in the current document. It is an error to call + // this more than {@link #freq()} times + // without calling {@link #next()}

This is + // invalid until {@link #next()} is called for + // the first time. + virtual int32_t nextPosition() = 0; + + virtual ~TermPositions(){ + } + + /** Solve the diamond inheritence problem by providing a reinterpret function. + * No dynamic casting is required and no RTTI data is needed to do this + */ + virtual TermDocs* __asTermDocs()=0; + virtual TermPositions* __asTermPositions()=0; +}; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/queryParser/Lexer.cpp b/3rdparty/clucene/src/CLucene/queryParser/Lexer.cpp new file mode 100644 index 000000000..861c5d3cb --- /dev/null +++ b/3rdparty/clucene/src/CLucene/queryParser/Lexer.cpp @@ -0,0 +1,371 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "Lexer.h" + +#include "CLucene/util/FastCharStream.h" +#include "CLucene/util/Reader.h" +#include "CLucene/util/StringBuffer.h" +#include "TokenList.h" +#include "QueryToken.h" +#include "QueryParserBase.h" + +CL_NS_USE(util) + +CL_NS_DEF(queryParser) +Lexer::Lexer(QueryParserBase* queryparser, const TCHAR* query) { + //Func - Constructor + //Pre - query != NULL and contains the query string + //Post - An instance of Lexer has been created + + this->queryparser = queryparser; + + CND_PRECONDITION(query != NULL, "query is NULL"); + + //The InputStream of Reader must be destroyed in the destructor + delSR = true; + + StringReader *r = _CLNEW StringReader(query); + + //Check to see if r has been created properly + CND_CONDITION(r != NULL, "Could not allocate memory for StringReader r"); + + //Instantie a FastCharStream instance using r and assign it to reader + reader = _CLNEW FastCharStream(r); + + //Check to see if reader has been created properly + CND_CONDITION(reader != NULL, "Could not allocate memory for FastCharStream reader"); + + //The InputStream of Reader must be destroyed in the destructor + delSR = true; + +} + + +Lexer::Lexer(QueryParserBase* queryparser, Reader* source) { + //Func - Constructor + // Initializes a new instance of the Lexer class with the specified + // TextReader to lex. + //Pre - Source contains a valid reference to a Reader + //Post - An instance of Lexer has been created using source as the reader + + this->queryparser = queryparser; + + //Instantie a FastCharStream instance using r and assign it to reader + reader = _CLNEW FastCharStream(source); + + //Check to see if reader has been created properly + CND_CONDITION(reader != NULL, "Could not allocate memory for FastCharStream reader"); + + //The InputStream of Reader must not be destroyed in the destructor + delSR = false; +} + + +Lexer::~Lexer() { + //Func - Destructor + //Pre - true + //Post - if delSR was true the InputStream input of reader has been deleted + // The instance of Lexer has been destroyed + + if (delSR) { + _CLDELETE(reader->input); + } + + _CLDELETE(reader); +} + + +void Lexer::Lex(TokenList *tokenList) { + //Func - Breaks the input stream onto the tokens list tokens + //Pre - tokens != NULL and contains a TokenList in which the tokens can be stored + //Post - The tokens have been added to the TokenList tokens + + CND_PRECONDITION(tokenList != NULL, "tokens is NULL"); + + //Get all the tokens + while(true) { + //Add the token to the tokens list + + //Get the next token + QueryToken* token = _CLNEW QueryToken; + if ( !GetNextToken(token) ){ + _CLDELETE(token); + break; + } + tokenList->add(token); + } + + //The end has been reached so create an EOF_ token + //Add the final token to the TokenList _tokens + tokenList->add(_CLNEW QueryToken( QueryToken::EOF_)); +} + + +bool Lexer::GetNextToken(QueryToken* token) { + while(!reader->Eos()) { + int ch = reader->GetNext(); + + if ( ch == -1 ) + break; + + // skipping whitespaces + if( _istspace(ch)!=0 ) { + continue; + } + TCHAR buf[2] = {ch,'\0'}; + switch(ch) { + case '+': + token->set(buf, QueryToken::PLUS); + return true; + case '-': + token->set(buf, QueryToken::MINUS); + return true; + case '(': + token->set(buf, QueryToken::LPAREN); + return true; + case ')': + token->set(buf, QueryToken::RPAREN); + return true; + case ':': + token->set(buf, QueryToken::COLON); + return true; + case '!': + token->set(buf, QueryToken::NOT); + return true; + case '^': + token->set(buf, QueryToken::CARAT); + return true; + case '~': + if( _istdigit( reader->Peek() )!=0 ) { + TCHAR number[LUCENE_MAX_FIELD_LEN]; + ReadIntegerNumber(ch, number,LUCENE_MAX_FIELD_LEN); + token->set(number, QueryToken::SLOP); + return true; + }else{ + token->set(buf, QueryToken::FUZZY); + return true; + } + break; + case '"': + return ReadQuoted(ch, token); + case '[': + return ReadInclusiveRange(ch, token); + case '{': + return ReadExclusiveRange(ch, token); + case ']': + case '}': + case '*': + queryparser->throwParserException( _T("Unrecognized TCHAR %d at %d::%d."), + ch, reader->Column(), reader->Line() ); + return false; + default: + return ReadTerm(ch, token); + + // end of swith + } + + } + return false; +} + + +void Lexer::ReadIntegerNumber(const TCHAR ch, TCHAR* buf, int buflen) { + int bp=0; + buf[bp++] = ch; + + int c = reader->Peek(); + while( c!=-1 && _istdigit(c)!=0 && bpGetNext(); + c = reader->Peek(); + } + buf[bp++] = 0; +} + + +bool Lexer::ReadInclusiveRange(const TCHAR prev, QueryToken* token) { + int ch = prev; + StringBuffer range; + range.appendChar(ch); + + while(!reader->Eos()) { + ch = reader->GetNext(); + if ( ch == -1 ) + break; + range.appendChar(ch); + + if(ch == ']'){ + token->set(range.getBuffer(), QueryToken::RANGEIN); + return true; + } + } + queryparser->throwParserException(_T("Unterminated inclusive range! %d %d::%d"),' ', + reader->Column(),reader->Column()); + return false; +} + + +bool Lexer::ReadExclusiveRange(const TCHAR prev, QueryToken* token) { + int ch = prev; + StringBuffer range; + range.appendChar(ch); + + while(!reader->Eos()) { + ch = reader->GetNext(); + + if (ch==-1) + break; + range.appendChar(ch); + + if(ch == '}'){ + token->set(range.getBuffer(), QueryToken::RANGEEX); + return true; + } + } + queryparser->throwParserException(_T("Unterminated exclusive range! %d %d::%d"),' ', + reader->Column(),reader->Column() ); + return false; +} + +bool Lexer::ReadQuoted(const TCHAR prev, QueryToken* token) { + int ch = prev; + StringBuffer quoted; + quoted.appendChar(ch); + + while(!reader->Eos()) { + ch = reader->GetNext(); + + if (ch==-1) + break; + + quoted.appendChar(ch); + + if(ch == '"'){ + token->set(quoted.getBuffer(), QueryToken::QUOTED); + return true; + } + } + queryparser->throwParserException(_T("Unterminated string! %d %d::%d"),' ', + reader->Column(),reader->Column()); + return false; +} + + +bool Lexer::ReadTerm(const TCHAR prev, QueryToken* token) { + int ch = prev; + bool completed = false; + int32_t asteriskCount = 0; + bool hasQuestion = false; + + StringBuffer val; + TCHAR buf[3]; //used for readescaped + + while(true) { + switch(ch) { + case -1: + break; + case '\\': + { + if ( ReadEscape(ch, buf) ) + val.append( buf ); + else + return false; + } + break; + + case LUCENE_WILDCARDTERMENUM_WILDCARD_STRING: + asteriskCount++; + val.appendChar(ch); + break; + case LUCENE_WILDCARDTERMENUM_WILDCARD_CHAR: + hasQuestion = true; + val.appendChar(ch); + break; + case '\n': + case '\t': + case ' ': + case '+': + case '-': + case '!': + case '(': + case ')': + case ':': + case '^': + case '[': + case ']': + case '{': + case '}': + case '~': + case '"': + // create new QueryToken + reader->UnGet(); + completed = true; + break; + default: + val.appendChar(ch); + break; + // end of switch + } + + if(completed || ch==-1 || reader->Eos() ) + break; + else + ch = reader->GetNext(); + } + + // create new QueryToken + if(hasQuestion) + token->set(val.getBuffer(), QueryToken::WILDTERM); + else if(asteriskCount == 1 && val.getBuffer()[val.length() - 1] == '*') + token->set(val.getBuffer(), QueryToken::PREFIXTERM); + else if(asteriskCount > 0) + token->set(val.getBuffer(), QueryToken::WILDTERM); + else if( _tcsicmp(val.getBuffer(), _T("AND"))==0 || _tcscmp(val.getBuffer(), _T("&&"))==0 ) + token->set(val.getBuffer(), QueryToken::AND_); + else if( _tcsicmp(val.getBuffer(), _T("OR"))==0 || _tcscmp(val.getBuffer(), _T("||"))==0) + token->set(val.getBuffer(), QueryToken::OR); + else if( _tcsicmp(val.getBuffer(), _T("NOT"))==0 ) + token->set(val.getBuffer(), QueryToken::NOT); + else { + bool isnum = true; + int32_t nlen=val.length(); + for (int32_t i=0;iset(val.getBuffer(), QueryToken::NUMBER); + else + token->set(val.getBuffer(), QueryToken::TERM); + } + return true; +} + + +bool Lexer::ReadEscape(TCHAR prev, TCHAR* buf) { + TCHAR ch = prev; + int bp=0; + buf[bp++] = ch; + + ch = reader->GetNext(); + int32_t idx = _tcscspn( buf, _T("\\+-!():^[]{}\"~*") ); + if(idx == 0) { + buf[bp++] = ch; + buf[bp++]=0; + return true; + } + queryparser->throwParserException(_T("Unrecognized escape sequence at %d %d::%d"), ' ', + reader->Column(),reader->Line()); + return false; +} + + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/queryParser/Lexer.h b/3rdparty/clucene/src/CLucene/queryParser/Lexer.h new file mode 100644 index 000000000..b3b55523e --- /dev/null +++ b/3rdparty/clucene/src/CLucene/queryParser/Lexer.h @@ -0,0 +1,67 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +* +* Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +------------------------------------------------------------------------------*/ +#ifndef _lucene_queryParser_Lexer_ +#define _lucene_queryParser_Lexer_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/util/FastCharStream.h" +#include "CLucene/util/Reader.h" +#include "CLucene/util/StringBuffer.h" + +#include "TokenList.h" + +CL_NS_DEF(queryParser) +class QueryParserBase; + // A simple Lexer that is used by QueryParser. + class Lexer:LUCENE_BASE + { + private: + CL_NS(util)::FastCharStream* reader; + QueryParserBase* queryparser; //holds the queryparser so that we can do callbacks + bool delSR; //Indicates if the reader must be deleted or not + + public: + // Initializes a new instance of the Lexer class with the specified + // query to lex. + Lexer(QueryParserBase* queryparser, const TCHAR* query); + + // Initializes a new instance of the Lexer class with the specified + // TextReader to lex. + Lexer(QueryParserBase* queryparser, CL_NS(util)::Reader* source); + + //Breaks the input stream onto the tokens list tokens + void Lex(TokenList *tokens); + + ~Lexer(); + + private: + bool GetNextToken(QueryToken* token); + + // Reads an integer number. buf should quite large, probably as large as a field should ever be + void ReadIntegerNumber(const TCHAR ch, TCHAR* buf, int buflen); + + // Reads an inclusive range like [some words] + bool ReadInclusiveRange(const TCHAR prev, QueryToken* token); + + // Reads an exclusive range like {some words} + bool ReadExclusiveRange(const TCHAR prev, QueryToken* token); + + // Reads quoted string like "something else" + bool ReadQuoted(const TCHAR prev, QueryToken* token); + + bool ReadTerm(const TCHAR prev, QueryToken* token); + + //reads an escaped character into the buf. Buf requires at least 3 characters + bool ReadEscape(const TCHAR prev, TCHAR* buf); + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/queryParser/MultiFieldQueryParser.cpp b/3rdparty/clucene/src/CLucene/queryParser/MultiFieldQueryParser.cpp new file mode 100644 index 000000000..b57896b66 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/queryParser/MultiFieldQueryParser.cpp @@ -0,0 +1,215 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +* +* Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "MultiFieldQueryParser.h" +#include "CLucene/analysis/AnalysisHeader.h" +#include "CLucene/search/BooleanQuery.h" +#include "CLucene/search/PhraseQuery.h" +#include "CLucene/search/SearchHeader.h" +#include "QueryParser.h" + +CL_NS_USE(index) +CL_NS_USE(util) +CL_NS_USE(search) +CL_NS_USE(analysis) + +CL_NS_DEF(queryParser) + +MultiFieldQueryParser::MultiFieldQueryParser(const TCHAR** fields, + CL_NS(analysis)::Analyzer* analyzer, BoostMap* boosts) + : QueryParser(NULL, analyzer) +{ + this->fields = fields; + this->boosts = boosts; +} + +MultiFieldQueryParser::~MultiFieldQueryParser() +{ +} + +//static +Query* MultiFieldQueryParser::parse(const TCHAR* query, const TCHAR** fields, + Analyzer* analyzer) +{ + BooleanQuery* bQuery = _CLNEW BooleanQuery(); + int32_t i = 0; + while (fields[i] != NULL){ + Query* q = QueryParser::parse(query, fields[i], analyzer); + if (q && (q->getQueryName() != _T("BooleanQuery") + || ((BooleanQuery*)q)->getClauseCount() > 0)) { + bQuery->add(q , true, false, false); + } else { + _CLDELETE(q); + } + i++; + } + return bQuery; +} + +//static +Query* MultiFieldQueryParser::parse(const TCHAR* query, const TCHAR** fields, + const uint8_t* flags, Analyzer* analyzer) +{ + BooleanQuery* bQuery = _CLNEW BooleanQuery(); + int32_t i = 0; + while ( fields[i] != NULL ) { + Query* q = QueryParser::parse(query, fields[i], analyzer); + if (q && (q->getQueryName() != _T("BooleanQuery") + || ((BooleanQuery*)q)->getClauseCount() > 0)) { + uint8_t flag = flags[i]; + switch (flag) { + case MultiFieldQueryParser::REQUIRED_FIELD: + bQuery->add(q, true, true, false); + break; + case MultiFieldQueryParser::PROHIBITED_FIELD: + bQuery->add(q, true, false, true); + break; + default: + bQuery->add(q, true, false, false); + break; + } + } else { + _CLDELETE(q); + } + i++; + } + return bQuery; +} + + +Query* MultiFieldQueryParser::GetFieldQuery(const TCHAR* field, TCHAR* queryText, int32_t slop){ + if (field == NULL) { + CL_NS_STD(vector) clauses; + for (int i = 0; fields[i]!=NULL; ++i) { + Query* q = QueryParser::GetFieldQuery(fields[i], queryText); + if (q != NULL) { + //If the user passes a map of boosts + if (boosts != NULL) { + //Get the boost from the map and apply them + BoostMap::const_iterator itr = boosts->find(fields[i]); + if (itr != boosts->end()) { + q->setBoost(itr->second); + } + } + if (q->getQueryName() == PhraseQuery::getClassName()) { + ((PhraseQuery*)q)->setSlop(slop); + } + //if (q instanceof MultiPhraseQuery) { + // ((MultiPhraseQuery) q).setSlop(slop); + //} + q = QueryAddedCallback(fields[i], q); + if ( q ) + clauses.push_back(_CLNEW BooleanClause(q, true, false,false)); + } + } + if (clauses.size() == 0) // happens for stopwords + return NULL; + Query* q = QueryParser::GetBooleanQuery(clauses); + return q; + }else{ + Query* q = QueryParser::GetFieldQuery(field, queryText); + if ( q ) + q = QueryAddedCallback(field,q); + return q; + } +} + + +Query* MultiFieldQueryParser::GetFieldQuery(const TCHAR* field, TCHAR* queryText){ + return GetFieldQuery(field, queryText, 0); +} + + +CL_NS(search)::Query* MultiFieldQueryParser::GetFuzzyQuery(const TCHAR* field, TCHAR* termStr){ + if (field == NULL) { + CL_NS_STD(vector) clauses; + for (int i = 0; fields[i]!=NULL; ++i) { + Query* q = QueryParser::GetFuzzyQuery(fields[i], termStr); //todo: , minSimilarity + if ( q ){ + q = QueryAddedCallback(fields[i], q); + if ( q ){ + clauses.push_back(_CLNEW BooleanClause(q,true,false,false) ); + } + } + } + return QueryParser::GetBooleanQuery(clauses); + }else{ + Query* q = QueryParser::GetFuzzyQuery(field, termStr);//todo: , minSimilarity + if ( q ) + q = QueryAddedCallback(field,q); + return q; + } +} + +Query* MultiFieldQueryParser::GetPrefixQuery(const TCHAR* field, TCHAR* termStr){ + if (field == NULL) { + CL_NS_STD(vector) clauses; + for (int i = 0; fields[i]!=NULL; ++i) { + Query* q = QueryParser::GetPrefixQuery(fields[i], termStr); + if ( q ){ + q = QueryAddedCallback(fields[i],q); + if ( q ){ + clauses.push_back(_CLNEW BooleanClause(q,true,false,false)); + } + } + } + return QueryParser::GetBooleanQuery(clauses); + }else{ + Query* q = QueryParser::GetPrefixQuery(field, termStr); + if ( q ) + q = QueryAddedCallback(field,q); + return q; + } +} + +Query* MultiFieldQueryParser::GetWildcardQuery(const TCHAR* field, TCHAR* termStr){ + if (field == NULL) { + CL_NS_STD(vector) clauses; + for (int i = 0; fields[i]!=NULL; ++i) { + Query* q = QueryParser::GetWildcardQuery(fields[i], termStr); + if ( q ){ + q = QueryAddedCallback(fields[i],q); + if ( q ){ + clauses.push_back(_CLNEW BooleanClause(q,true,false,false)); + } + } + } + return QueryParser::GetBooleanQuery(clauses); + }else{ + Query* q = QueryParser::GetWildcardQuery(field, termStr); + if ( q ) + q = QueryAddedCallback(field,q); + return q; + } +} + + +Query* MultiFieldQueryParser::GetRangeQuery(const TCHAR* field, TCHAR* part1, TCHAR* part2, bool inclusive){ + if (field == NULL) { + CL_NS_STD(vector) clauses; + for (int i = 0; fields[i]!=NULL; ++i) { + Query* q = QueryParser::GetRangeQuery(fields[i], part1, part2, inclusive); + if ( q ){ + q = QueryAddedCallback(fields[i],q); + if ( q ){ + clauses.push_back(_CLNEW BooleanClause(q,true,false,false)); + } + } + } + return QueryParser::GetBooleanQuery(clauses); + }else{ + Query* q = QueryParser::GetRangeQuery(field, part1, part2, inclusive); + if ( q ) + q = QueryAddedCallback(field,q); + return q; + } +} + + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/queryParser/MultiFieldQueryParser.h b/3rdparty/clucene/src/CLucene/queryParser/MultiFieldQueryParser.h new file mode 100644 index 000000000..bf7d652a7 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/queryParser/MultiFieldQueryParser.h @@ -0,0 +1,136 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef MultiFieldQueryParser_H +#define MultiFieldQueryParser_H + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/analysis/AnalysisHeader.h" +#include "CLucene/search/SearchHeader.h" +#include "QueryParser.h" + + +CL_NS_DEF(queryParser) + +typedef CL_NS(util)::CLHashMap BoostMap; + + /** + * A QueryParser which constructs queries to search multiple fields. + * + */ + class MultiFieldQueryParser: public QueryParser + { + protected: + const TCHAR** fields; + BoostMap* boosts; + public: + LUCENE_STATIC_CONSTANT(uint8_t, NORMAL_FIELD=0); + LUCENE_STATIC_CONSTANT(uint8_t, REQUIRED_FIELD=1); + LUCENE_STATIC_CONSTANT(uint8_t, PROHIBITED_FIELD=2); + + /** + * Creates a MultiFieldQueryParser. + * + *

It will, when parse(String query) + * is called, construct a query like this (assuming the query consists of + * two terms and you specify the two fields title and body):

+ * + * + * (title:term1 body:term1) (title:term2 body:term2) + * + * + *

When setDefaultOperator(AND_OPERATOR) is set, the result will be:

+ * + * + * +(title:term1 body:term1) +(title:term2 body:term2) + * + * + *

In other words, all the query's terms must appear, but it doesn't matter in + * what fields they appear.

+ */ + MultiFieldQueryParser(const TCHAR** fields, CL_NS(analysis)::Analyzer* a, BoostMap* boosts = NULL); + virtual ~MultiFieldQueryParser(); + + /** + *

+ * Parses a query which searches on the fields specified. + *

+ * If x fields are specified, this effectively constructs: + *

+         * 
+         * (field1:query) (field2:query) (field3:query)...(fieldx:query)
+         * 
+         * 
+ * + * @param query Query string to parse + * @param fields Fields to search on + * @param analyzer Analyzer to use + * @throws ParserException if query parsing fails + * @throws TokenMgrError if query parsing fails + */ + static CL_NS(search)::Query* parse(const TCHAR* query, const TCHAR** fields, CL_NS(analysis)::Analyzer* analyzer); + + /** + *

+ * Parses a query, searching on the fields specified. + * Use this if you need to specify certain fields as required, + * and others as prohibited. + *

+         * Usage:
+         * 
+         * String[] fields = {"filename", "contents", "description"};
+         * int32_t[] flags = {MultiFieldQueryParser.NORMAL FIELD,
+         *                MultiFieldQueryParser.REQUIRED FIELD,
+         *                MultiFieldQueryParser.PROHIBITED FIELD,};
+         * parse(query, fields, flags, analyzer);
+         * 
+         * 
+ *

+ * The code above would construct a query: + *

+         * 
+         * (filename:query) +(contents:query) -(description:query)
+         * 
+         * 
+ * + * @param query Query string to parse + * @param fields Fields to search on + * @param flags Flags describing the fields + * @param analyzer Analyzer to use + * @throws ParserException if query parsing fails + * @throws TokenMgrError if query parsing fails + */ + static CL_NS(search)::Query* parse(const TCHAR* query, const TCHAR** fields, const uint8_t* flags, CL_NS(analysis)::Analyzer* analyzer); + + + + protected: + CL_NS(search)::Query* GetFieldQuery(const TCHAR* field, TCHAR* queryText); + CL_NS(search)::Query* GetFieldQuery(const TCHAR* field, TCHAR* queryText, int32_t slop); + CL_NS(search)::Query* GetFuzzyQuery(const TCHAR* field, TCHAR* termStr); + CL_NS(search)::Query* GetRangeQuery(const TCHAR* field, TCHAR* part1, TCHAR* part2, bool inclusive); + CL_NS(search)::Query* GetPrefixQuery(const TCHAR* field, TCHAR* termStr); + CL_NS(search)::Query* GetWildcardQuery(const TCHAR* field, TCHAR* termStr); + + /** + * A special virtual function for the MultiFieldQueryParser which can be used + * to clean up queries. Once the field name is known and the query has been + * created, its passed to this function. + * An example of this usage is to set boosts. + */ + virtual CL_NS(search)::Query* QueryAddedCallback(const TCHAR* field, CL_NS(search)::Query* query){ return query; } + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/queryParser/QueryParser.cpp b/3rdparty/clucene/src/CLucene/queryParser/QueryParser.cpp new file mode 100644 index 000000000..b11eec0bb --- /dev/null +++ b/3rdparty/clucene/src/CLucene/queryParser/QueryParser.cpp @@ -0,0 +1,509 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +* +* Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "QueryParser.h" + +#include "CLucene/analysis/AnalysisHeader.h" +#include "CLucene/util/Reader.h" +#include "CLucene/search/SearchHeader.h" +#include "CLucene/index/Term.h" + +#include "TokenList.h" +#include "QueryToken.h" +#include "QueryParserBase.h" +#include "Lexer.h" + +CL_NS_USE(util) +CL_NS_USE(index) +CL_NS_USE(analysis) +CL_NS_USE(search) + +CL_NS_DEF(queryParser) + + QueryParser::QueryParser(const TCHAR* _field, Analyzer* _analyzer) : QueryParserBase(_analyzer){ + //Func - Constructor. + // Instantiates a QueryParser for the named field _field + //Pre - _field != NULL + //Post - An instance has been created + + if ( _field ) + field = STRDUP_TtoT(_field); + else + field = NULL; + tokens = NULL; + lowercaseExpandedTerms = true; + } + + QueryParser::~QueryParser() { + //Func - Destructor + //Pre - true + //Post - The instance has been destroyed + + _CLDELETE_CARRAY(field); + } + + //static + Query* QueryParser::parse(const TCHAR* query, const TCHAR* field, Analyzer* analyzer){ + //Func - Returns a new instance of the Query class with a specified query, field and + // analyzer values. + //Pre - query != NULL and holds the query to parse + // field != NULL and holds the default field for query terms + // analyzer holds a valid reference to an Analyzer and is used to + // find terms in the query text + //Post - query has been parsed and an instance of Query has been returned + + CND_PRECONDITION(query != NULL, "query is NULL"); + CND_PRECONDITION(field != NULL, "field is NULL"); + + QueryParser parser(field, analyzer); + return parser.parse(query); + } + + Query* QueryParser::parse(const TCHAR* query){ + //Func - Returns a parsed Query instance + //Pre - query != NULL and contains the query value to be parsed + //Post - Returns a parsed Query Instance + + CND_PRECONDITION(query != NULL, "query is NULL"); + + //Instantie a Stringer that can read the query string + Reader* r = _CLNEW StringReader(query); + + //Check to see if r has been created properly + CND_CONDITION(r != NULL, "Could not allocate memory for StringReader r"); + + //Pointer for the return value + Query* ret = NULL; + + try{ + //Parse the query managed by the StringReader R and return a parsed Query instance + //into ret + ret = parse(r); + }_CLFINALLY ( + _CLDELETE(r); + ); + + return ret; + } + + Query* QueryParser::parse(Reader* reader){ + //Func - Returns a parsed Query instance + //Pre - reader contains a valid reference to a Reader and manages the query string + //Post - A parsed Query instance has been returned or + + //instantiate the TokenList tokens + TokenList _tokens; + this->tokens = &_tokens; + + //Instantiate a lexer + Lexer lexer(this, reader); + + //tokens = lexer.Lex(); + //Lex the tokens + lexer.Lex(tokens); + + //Peek to the first token and check if is an EOF + if (tokens->peek()->Type == QueryToken::EOF_){ + // The query string failed to yield any tokens. We discard the + // TokenList tokens and raise an exceptioin. + QueryToken* token = this->tokens->extract(); + _CLDELETE(token); + _CLTHROWA(CL_ERR_Parse, "No query given."); + } + + //Return the parsed Query instance + Query* ret = MatchQuery(field); + this->tokens = NULL; + return ret; + } + + int32_t QueryParser::MatchConjunction(){ + //Func - matches for CONJUNCTION + // CONJUNCTION ::= | + //Pre - tokens != NULL + //Post - if the first token is an AND or an OR then + // the token is extracted and deleted and CONJ_AND or CONJ_OR is returned + // otherwise CONJ_NONE is returned + + CND_PRECONDITION(tokens != NULL, "tokens is NULL"); + + switch(tokens->peek()->Type){ + case QueryToken::AND_ : + //Delete the first token of tokenlist + ExtractAndDeleteToken(); + return CONJ_AND; + case QueryToken::OR : + //Delete the first token of tokenlist + ExtractAndDeleteToken(); + return CONJ_OR; + default : + return CONJ_NONE; + } + } + + int32_t QueryParser::MatchModifier(){ + //Func - matches for MODIFIER + // MODIFIER ::= | | + //Pre - tokens != NULL + //Post - if the first token is a PLUS the token is extracted and deleted and MOD_REQ is returned + // if the first token is a MINUS or NOT the token is extracted and deleted and MOD_NOT is returned + // otherwise MOD_NONE is returned + CND_PRECONDITION(tokens != NULL, "tokens is NULL"); + + switch(tokens->peek()->Type){ + case QueryToken::PLUS : + //Delete the first token of tokenlist + ExtractAndDeleteToken(); + return MOD_REQ; + case QueryToken::MINUS : + case QueryToken::NOT : + //Delete the first token of tokenlist + ExtractAndDeleteToken(); + return MOD_NOT; + default : + return MOD_NONE; + } + } + + Query* QueryParser::MatchQuery(const TCHAR* field){ + //Func - matches for QUERY + // QUERY ::= [MODIFIER] QueryParser::CLAUSE ( [MODIFIER] CLAUSE)* + //Pre - field != NULL + //Post - + + CND_PRECONDITION(tokens != NULL, "tokens is NULL"); + + CL_NS_STD(vector) clauses; + + Query* q = NULL; + + int32_t mods = MOD_NONE; + int32_t conj = CONJ_NONE; + + //match for MODIFIER + mods = MatchModifier(); + + //match for CLAUSE + q = MatchClause(field); + AddClause(clauses, CONJ_NONE, mods, q); + + // match for CLAUSE* + while(true){ + QueryToken* p = tokens->peek(); + if(p->Type == QueryToken::EOF_){ + QueryToken* qt = MatchQueryToken(QueryToken::EOF_); + _CLDELETE(qt); + break; + } + + if(p->Type == QueryToken::RPAREN){ + //MatchQueryToken(QueryToken::RPAREN); + break; + } + + //match for a conjuction (AND OR NOT) + conj = MatchConjunction(); + //match for a modifier + mods = MatchModifier(); + + q = MatchClause(field); + if ( q != NULL ) + AddClause(clauses, conj, mods, q); + } + + // finalize query + if(clauses.size() == 1){ //bvk: removed this && firstQuery != NULL + BooleanClause* c = clauses[0]; + Query* q = c->query; + + //Condition check to be sure clauses[0] is valid + CND_CONDITION(c != NULL, "c is NULL"); + + //Tell the boolean clause not to delete its query + c->deleteQuery=false; + //Clear the clauses list + clauses.clear(); + _CLDELETE(c); + + return q; + }else{ + return GetBooleanQuery(clauses); + } + } + + Query* QueryParser::MatchClause(const TCHAR* field){ + //Func - matches for CLAUSE + // CLAUSE ::= [TERM ] ( TERM | ( QUERY )) + //Pre - field != NULL + //Post - + + Query* q = NULL; + const TCHAR* sfield = field; + bool delField = false; + + QueryToken *DelToken = NULL; + + //match for [TERM ] + QueryToken* term = tokens->extract(); + if(term->Type == QueryToken::TERM && tokens->peek()->Type == QueryToken::COLON){ + DelToken = MatchQueryToken(QueryToken::COLON); + + CND_CONDITION(DelToken != NULL,"DelToken is NULL"); + _CLDELETE(DelToken); + + TCHAR* tmp = STRDUP_TtoT(term->Value); + discardEscapeChar(tmp); + delField = true; + sfield = tmp; + _CLDELETE(term); + }else{ + tokens->push(term); + term = NULL; + } + + // match for + // TERM | ( QUERY ) + if(tokens->peek()->Type == QueryToken::LPAREN){ + DelToken = MatchQueryToken(QueryToken::LPAREN); + + CND_CONDITION(DelToken != NULL,"DelToken is NULL"); + _CLDELETE(DelToken); + + q = MatchQuery(sfield); + //DSR:2004.11.01: + //If exception is thrown while trying to match trailing parenthesis, + //need to prevent q from leaking. + + try{ + DelToken = MatchQueryToken(QueryToken::RPAREN); + + CND_CONDITION(DelToken != NULL,"DelToken is NULL"); + _CLDELETE(DelToken); + + }catch(...) { + _CLDELETE(q); + throw; + } + }else{ + q = MatchTerm(sfield); + } + + if ( delField ) + _CLDELETE_CARRAY(sfield); + return q; + } + + + Query* QueryParser::MatchTerm(const TCHAR* field){ + //Func - matches for TERM + // TERM ::= TERM | PREFIXTERM | WILDTERM | NUMBER + // [ ] [ []] + // | ( | ) [ ] + // | [SLOP] [ ] + //Pre - field != NULL + //Post - + + QueryToken* term = NULL; + QueryToken* slop = NULL; + QueryToken* boost = NULL; + + bool prefix = false; + bool wildcard = false; + bool fuzzy = false; + bool rangein = false; + Query* q = NULL; + + term = tokens->extract(); + QueryToken* DelToken = NULL; //Token that is about to be deleted + + switch(term->Type){ + case QueryToken::TERM: + case QueryToken::NUMBER: + case QueryToken::PREFIXTERM: + case QueryToken::WILDTERM: + { //start case + //Check if type of QueryToken term is a prefix term + if(term->Type == QueryToken::PREFIXTERM){ + prefix = true; + } + //Check if type of QueryToken term is a wildcard term + if(term->Type == QueryToken::WILDTERM){ + wildcard = true; + } + //Peek to see if the type of the next token is fuzzy term + if(tokens->peek()->Type == QueryToken::FUZZY){ + DelToken = MatchQueryToken(QueryToken::FUZZY); + + CND_CONDITION(DelToken !=NULL, "DelToken is NULL"); + _CLDELETE(DelToken); + + fuzzy = true; + } + if(tokens->peek()->Type == QueryToken::CARAT){ + DelToken = MatchQueryToken(QueryToken::CARAT); + + CND_CONDITION(DelToken !=NULL, "DelToken is NULL"); + _CLDELETE(DelToken); + + boost = MatchQueryToken(QueryToken::NUMBER); + + if(tokens->peek()->Type == QueryToken::FUZZY){ + DelToken = MatchQueryToken(QueryToken::FUZZY); + + CND_CONDITION(DelToken !=NULL, "DelToken is NULL"); + _CLDELETE(DelToken); + + fuzzy = true; + } + } //end if type==CARAT + + discardEscapeChar(term->Value); //clean up + if(wildcard){ + q = GetWildcardQuery(field,term->Value); + break; + }else if(prefix){ + //Create a PrefixQuery + term->Value[_tcslen(term->Value)-1] = 0; //discard the * + q = GetPrefixQuery(field,term->Value); + break; + }else if(fuzzy){ + //Create a FuzzyQuery + + //Check if the last char is a ~ + if(term->Value[_tcslen(term->Value)-1] == '~'){ + //remove the ~ + term->Value[_tcslen(term->Value)-1] = '\0'; + } + + q = GetFuzzyQuery(field,term->Value); + break; + }else{ + q = GetFieldQuery(field, term->Value); + break; + } + } + + + case QueryToken::RANGEIN: + case QueryToken::RANGEEX:{ + if(term->Type == QueryToken::RANGEIN){ + rangein = true; + } + + if(tokens->peek()->Type == QueryToken::CARAT){ + DelToken = MatchQueryToken(QueryToken::CARAT); + + CND_CONDITION(DelToken !=NULL, "DelToken is NULL"); + _CLDELETE(DelToken); + + boost = MatchQueryToken(QueryToken::NUMBER); + } + + TCHAR* noBrackets = term->Value + 1; + noBrackets[_tcslen(noBrackets)-1] = 0; + q = ParseRangeQuery(field, noBrackets, rangein); + break; + } + + + case QueryToken::QUOTED:{ + if(tokens->peek()->Type == QueryToken::SLOP){ + slop = MatchQueryToken(QueryToken::SLOP); + } + + if(tokens->peek()->Type == QueryToken::CARAT){ + DelToken = MatchQueryToken(QueryToken::CARAT); + + CND_CONDITION(DelToken !=NULL, "DelToken is NULL"); + _CLDELETE(DelToken); + + boost = MatchQueryToken(QueryToken::NUMBER); + } + + //remove the quotes + TCHAR* quotedValue = term->Value+1; + quotedValue[_tcslen(quotedValue)-1] = '\0'; + + int32_t islop = phraseSlop; + if(slop != NULL ){ + try { + TCHAR* end; //todo: should parse using float... + islop = (int32_t)_tcstoi64(slop->Value+1, &end, 10); + }catch(...){ + //ignored + } + } + + q = GetFieldQuery(field, quotedValue, islop); + _CLDELETE(slop); + } + } // end of switch + + _CLDELETE(term); + + + if( q!=NULL && boost != NULL ){ + qreal f = 1.0F; + try { + TCHAR* tmp; + f = _tcstod(boost->Value, &tmp); + }catch(...){ + //ignored + } + _CLDELETE(boost); + + q->setBoost( f); + } + + return q; + } + + QueryToken* QueryParser::MatchQueryToken(QueryToken::Types expectedType){ + //Func - matches for QueryToken of the specified type and returns it + // otherwise Exception throws + //Pre - tokens != NULL + //Post - + + CND_PRECONDITION(tokens != NULL,"tokens is NULL"); + + if(tokens->count() == 0){ + throwParserException(_T("Error: Unexpected end of program"),' ',0,0); + } + + //Extract a token form the TokenList tokens + QueryToken* t = tokens->extract(); + //Check if the type of the token t matches the expectedType + if (expectedType != t->Type){ + TCHAR buf[200]; + _sntprintf(buf,200,_T("Error: Unexpected QueryToken: %d, expected: %d"),t->Type,expectedType); + _CLDELETE(t); + throwParserException(buf,' ',0,0); + } + + //Return the matched token + return t; + } + + void QueryParser::ExtractAndDeleteToken(void){ + //Func - Extracts the first token from the Tokenlist tokenlist + // and destroys it + //Pre - true + //Post - The first token has been extracted and destroyed + + CND_PRECONDITION(tokens != NULL, "tokens is NULL"); + + //Extract the token from the TokenList tokens + QueryToken* t = tokens->extract(); + //Condition Check Token may not be NULL + CND_CONDITION(t != NULL, "Token is NULL"); + //Delete Token + _CLDELETE(t); + } + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/queryParser/QueryParser.h b/3rdparty/clucene/src/CLucene/queryParser/QueryParser.h new file mode 100644 index 000000000..a2fc85c89 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/queryParser/QueryParser.h @@ -0,0 +1,165 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_queryParser_QueryParser_ +#define _lucene_queryParser_QueryParser_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/analysis/AnalysisHeader.h" +#include "CLucene/util/Reader.h" +#include "CLucene/search/SearchHeader.h" +#include "CLucene/index/Term.h" + +#include "TokenList.h" +#include "QueryToken.h" +#include "QueryParserBase.h" +#include "Lexer.h" + +CL_NS_DEF(queryParser) + +/** +* @brief CLucene's default query parser. +* +*

It's a query parser. +* The only method that clients should need to call is Parse(). +* The syntax for query const TCHAR*s is as follows: +* A Query is a series of clauses. A clause may be prefixed by:

+*
    +*
  • a plus (+) or a minus (-) sign, indicating that the +* clause is required or prohibited respectively; or
  • +*
  • a term followed by a colon, indicating the field to be searched. +* This enables one to construct queries which search multiple fields.
  • +*
+*

+* A clause may be either:

+*
    +*
  • a term, indicating all the documents that contain this term; or
  • +*
  • a nested query, enclosed in parentheses. Note that this may be +* used with a +/- prefix to require any of a set of terms.
  • +*
+*

+* Thus, in BNF, the query grammar is:

+* +* Query ::= ( Clause )* +* Clause ::= ["+", "-"] [<TERM> ":"] ( <TERM> | "(" Query ")" ) +* +*

+* Examples of appropriately formatted queries can be found in the test cases. +*

+*/ +class QueryParser : public QueryParserBase +{ +private: + const TCHAR* field; + TokenList* tokens; +public: + /** + * Initializes a new instance of the QueryParser class with a specified field and + * analyzer values. + */ + QueryParser(const TCHAR* field, CL_NS(analysis)::Analyzer* analyzer); + ~QueryParser(); + + /** + * Returns a parsed Query instance. + * Note: this call is not threadsafe, either use a seperate QueryParser for each thread, or use a thread lock + * The query value to be parsed. + * A parsed Query instance. + */ + virtual CL_NS(search)::Query* parse(const TCHAR* query); + + /** + * Returns a parsed Query instance. + * Note: this call is not threadsafe, either use a seperate QueryParser for each thread, or use a thread lock + * The TextReader value to be parsed. + * A parsed Query instance. + */ + virtual CL_NS(search)::Query* parse(CL_NS(util)::Reader* reader); + + /** + * Returns a new instance of the Query class with a specified query, field and + * analyzer values. + */ + static CL_NS(search)::Query* parse(const TCHAR* query, const TCHAR* field, CL_NS(analysis)::Analyzer* analyzer); + + CL_NS(analysis)::Analyzer* getAnalyzer() { return analyzer; } + + /** + * @return Returns the field. + */ + const TCHAR* getField() { return field; } + + //deprecated functions + _CL_DEPRECATED( setLowercaseExpandedTerms ) void setLowercaseWildcardTerms(bool lowercaseWildcardTerms){ setLowercaseExpandedTerms(lowercaseWildcardTerms); } + _CL_DEPRECATED( getLowercaseExpandedTerms ) bool getLowercaseWildcardTerms() const { return getLowercaseExpandedTerms(); } +protected: + //these functions may be defined under certain compilation conditions. + //note that this functionality is deprecated, you should create your own queryparser + //if you want to remove this functionality...it will be removed... be warned! +#ifdef NO_PREFIX_QUERY + virtual CL_NS(search)::Query* GetPrefixQuery(const TCHAR* field,const TCHAR* termStr){ return NULL; } +#endif +#ifdef NO_FUZZY_QUERY + virtual CL_NS(search)::Query* GetFuzzyQuery(const TCHAR* field,const TCHAR* termStr){ return NULL; } +#endif +#ifdef NO_RANGE_QUERY + virtual CL_NS(search)::Query* GetRangeQuery(const TCHAR* field, const TCHAR* part1, const TCHAR* part2, bool inclusive) { return NULL; } +#endif +#ifdef NO_WILDCARD_QUERY + virtual CL_NS(search)::Query* GetWildcardQuery(const TCHAR* field, TCHAR* termStr) { return NULL; } +#endif +private: + /** + * matches for CONJUNCTION + * CONJUNCTION ::= | + */ + int32_t MatchConjunction(); + + /** + * matches for MODIFIER + * MODIFIER ::= | | + */ + int32_t MatchModifier(); + + /** + * matches for QUERY + * QUERY ::= [MODIFIER] CLAUSE ( [MODIFIER] CLAUSE)* + */ + CL_NS(search)::Query* MatchQuery(const TCHAR* field); + + /** + * matches for CLAUSE + * CLAUSE ::= [TERM ] ( TERM | ( QUERY )) + */ + CL_NS(search)::Query* MatchClause(const TCHAR* field); + + /** + * matches for TERM + * TERM ::= TERM | PREFIXTERM | WILDTERM | NUMBER + * [ ] [ []] + * + * | ( | ) [ ] + * | [SLOP] [ ] + */ + CL_NS(search)::Query* MatchTerm(const TCHAR* field); + + /** + * matches for QueryToken of the specified type and returns it + * otherwise Exception throws + */ + QueryToken* MatchQueryToken(QueryToken::Types expectedType); + + /** + * Extracts the first token from the Tokenlist tokenlist + * and destroys it + */ + void ExtractAndDeleteToken(void); +}; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/queryParser/QueryParserBase.cpp b/3rdparty/clucene/src/CLucene/queryParser/QueryParserBase.cpp new file mode 100644 index 000000000..7b95b30f9 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/queryParser/QueryParserBase.cpp @@ -0,0 +1,369 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +* +* Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "QueryParserBase.h" + +#include "CLucene/search/TermQuery.h" +#include "CLucene/search/PhraseQuery.h" +#include "CLucene/search/RangeQuery.h" +#include "CLucene/search/FuzzyQuery.h" +#include "CLucene/search/WildcardQuery.h" +#include "CLucene/search/PrefixQuery.h" + + +CL_NS_USE(search) +CL_NS_USE(util) +CL_NS_USE(analysis) +CL_NS_USE(index) + +CL_NS_DEF(queryParser) + +QueryParserBase::QueryParserBase(Analyzer* analyzer){ +//Func - Constructor +//Pre - true +//Post - instance has been created with PhraseSlop = 0 + this->analyzer = analyzer; + this->defaultOperator = OR_OPERATOR; + this->phraseSlop = 0; + this->lowercaseExpandedTerms = true; +} + +QueryParserBase::~QueryParserBase(){ +//Func - Destructor +//Pre - true +//Post - The instance has been destroyed +} + + +void QueryParserBase::discardEscapeChar(TCHAR* source) const{ + int len = _tcslen(source); + int j = 0; + for (int i = 0; i < len; i++) { + if (source[i] == '\\' && source[i+1] != '\0' ) { + _tcscpy(source+i,source+i+1); + len--; + } + } +} + +void QueryParserBase::AddClause(CL_NS_STD(vector)& clauses, int32_t conj, int32_t mods, Query* q){ +//Func - Adds the next parsed clause. +//Pre - +//Post - + + bool required, prohibited; + + // If this term is introduced by AND, make the preceding term required, + // unless it's already prohibited. + const uint32_t nPreviousClauses = clauses.size(); + if (nPreviousClauses > 0 && conj == CONJ_AND) { + BooleanClause* c = clauses[nPreviousClauses-1]; + if (!c->prohibited) + c->required = true; + } + + if (nPreviousClauses > 0 && defaultOperator == AND_OPERATOR && conj == CONJ_OR) { + // If this term is introduced by OR, make the preceding term optional, + // unless it's prohibited (that means we leave -a OR b but +a OR b-->a OR b) + // notice if the input is a OR b, first term is parsed as required; without + // this modification a OR b would parse as +a OR b + BooleanClause* c = clauses[nPreviousClauses-1]; + if (!c->prohibited){ + c->required = false; + c->prohibited = false; + } + } + + // We might have been passed a NULL query; the term might have been + // filtered away by the analyzer. + if (q == NULL) + return; + + if (defaultOperator == OR_OPERATOR) { + // We set REQUIRED if we're introduced by AND or +; PROHIBITED if + // introduced by NOT or -; make sure not to set both. + prohibited = (mods == MOD_NOT); + required = (mods == MOD_REQ); + if (conj == CONJ_AND && !prohibited) { + required = true; + } + } else { + // We set PROHIBITED if we're introduced by NOT or -; We set REQUIRED + // if not PROHIBITED and not introduced by OR + prohibited = (mods == MOD_NOT); + required = (!prohibited && conj != CONJ_OR); + } + + if ( required && prohibited ) + throwParserException( _T("Clause cannot be both required and prohibited"), ' ',0,0); + clauses.push_back(_CLNEW BooleanClause(q,true, required, prohibited)); +} + +void QueryParserBase::throwParserException(const TCHAR* message, TCHAR ch, int32_t col, int32_t line ) +{ + TCHAR msg[1024]; + _sntprintf(msg,1024,message,ch,col,line); + _CLTHROWT (CL_ERR_Parse, msg ); +} + + +Query* QueryParserBase::GetFieldQuery(const TCHAR* field, TCHAR* queryText, int32_t slop){ + Query* ret = GetFieldQuery(field,queryText); + if ( ret && ret->getQueryName() == PhraseQuery::getClassName() ) + ((PhraseQuery*)ret)->setSlop(slop); + + return ret; +} + +Query* QueryParserBase::GetFieldQuery(const TCHAR* field, TCHAR* queryText){ +//Func - Returns a query for the specified field. +// Use the analyzer to get all the tokens, and then build a TermQuery, +// PhraseQuery, or nothing based on the term count +//Pre - field != NULL +// analyzer contains a valid reference to an Analyzer +// queryText != NULL and contains the query +//Post - A query instance has been returned for the specified field + + CND_PRECONDITION(field != NULL, "field is NULL"); + CND_PRECONDITION(queryText != NULL, "queryText is NULL"); + + //Instantiate a stringReader for queryText + StringReader reader(queryText); + TokenStream* source = analyzer->tokenStream(field, &reader); + CND_CONDITION(source != NULL,"source is NULL"); + + StringArrayConstWithDeletor v; + + Token t; + int positionCount = 0; + bool severalTokensAtSamePosition = false; + + //Get the tokens from the source + try{ + while (source->next(&t)){ + v.push_back(STRDUP_TtoT(t.termText())); + + if (t.getPositionIncrement() != 0) + positionCount += t.getPositionIncrement(); + else + severalTokensAtSamePosition = true; + } + }catch(CLuceneError& err){ + if ( err.number() != CL_ERR_IO ) + throw err; + } + _CLDELETE(source); + + //Check if there are any tokens retrieved + if (v.size() == 0){ + return NULL; + }else{ + if (v.size() == 1){ + Term* t = _CLNEW Term(field, v[0]); + Query* ret = _CLNEW TermQuery( t ); + _CLDECDELETE(t); + return ret; + }else{ + if (severalTokensAtSamePosition) { + if (positionCount == 1) { + // no phrase query: + BooleanQuery* q = _CLNEW BooleanQuery; //todo: disableCoord=true here, but not implemented in BooleanQuery + StringArrayConst::iterator itr = v.begin(); + while ( itr != v.end() ){ + Term* t = _CLNEW Term(field, *itr); + q->add(_CLNEW TermQuery(t),true, false,false);//should occur... + _CLDECDELETE(t); + ++itr; + } + return q; + }else { + _CLTHROWA(CL_ERR_UnsupportedOperation, "MultiPhraseQuery NOT Implemented"); + } + }else{ + PhraseQuery* q = _CLNEW PhraseQuery; + q->setSlop(phraseSlop); + + StringArrayConst::iterator itr = v.begin(); + while ( itr != v.end() ){ + const TCHAR* data = *itr; + Term* t = _CLNEW Term(field, data); + q->add(t); + _CLDECDELETE(t); + ++itr; + } + return q; + } + } + } +} + +void QueryParserBase::setLowercaseExpandedTerms(bool lowercaseExpandedTerms){ + this->lowercaseExpandedTerms = lowercaseExpandedTerms; +} +bool QueryParserBase::getLowercaseExpandedTerms() const { + return lowercaseExpandedTerms; +} +void QueryParserBase::setDefaultOperator(int oper){ + this->defaultOperator=oper; +} +int QueryParserBase::getDefaultOperator() const{ + return defaultOperator; +} + + +Query* QueryParserBase::ParseRangeQuery(const TCHAR* field, TCHAR* queryText, bool inclusive) +{ + //todo: this must be fixed, [-1--5] (-1 to -5) should yield a result, but won't parse properly + //because it uses an analyser, should split it up differently... + + // Use the analyzer to get all the tokens. There should be 1 or 2. + StringReader reader(queryText); + TokenStream* source = analyzer->tokenStream(field, &reader); + + TCHAR* terms[2]; + terms[0]=NULL;terms[1]=NULL; + Token t; + bool tret=true; + bool from=true; + while(tret) + { + try{ + tret = source->next(&t); + }catch (CLuceneError& err){ + if ( err.number() == CL_ERR_IO ) + tret=false; + else + throw err; + } + if (tret) + { + if ( !from && _tcscmp(t.termText(),_T("TO"))==0 ) + continue; + + + TCHAR* tmp = STRDUP_TtoT(t.termText()); + discardEscapeChar(tmp); + terms[from? 0 : 1] = tmp; + + if (from) + from = false; + else + break; + } + } + Query* ret = GetRangeQuery(field, terms[0], terms[1],inclusive); + _CLDELETE_CARRAY(terms[0]); + _CLDELETE_CARRAY(terms[1]); + _CLDELETE(source); + + return ret; +} + +Query* QueryParserBase::GetPrefixQuery(const TCHAR* field, TCHAR* termStr){ +//Pre - field != NULL and field contains the name of the field that the query will use +// termStr != NULL and is the token to use for building term for the query +// (WITH or WITHOUT a trailing '*' character!) +//Post - A PrefixQuery instance has been returned + + CND_PRECONDITION(field != NULL,"field is NULL"); + CND_PRECONDITION(termStr != NULL,"termStr is NULL"); + + if ( lowercaseExpandedTerms ) + _tcslwr(termStr); + + Term* t = _CLNEW Term(field, termStr); + CND_CONDITION(t != NULL,"Could not allocate memory for term t"); + + Query *q = _CLNEW PrefixQuery(t); + CND_CONDITION(q != NULL,"Could not allocate memory for PrefixQuery q"); + + _CLDECDELETE(t); + return q; +} + +Query* QueryParserBase::GetFuzzyQuery(const TCHAR* field, TCHAR* termStr){ +//Func - Factory method for generating a query (similar to getPrefixQuery}). Called when parser parses +// an input term token that has the fuzzy suffix (~) appended. +//Pre - field != NULL and field contains the name of the field that the query will use +// termStr != NULL and is the token to use for building term for the query +// (WITH or WITHOUT a trailing '*' character!) +//Post - A FuzzyQuery instance has been returned + + CND_PRECONDITION(field != NULL,"field is NULL"); + CND_PRECONDITION(termStr != NULL,"termStr is NULL"); + + if ( lowercaseExpandedTerms ) + _tcslwr(termStr); + + Term* t = _CLNEW Term(field, termStr); + CND_CONDITION(t != NULL,"Could not allocate memory for term t"); + + Query *q = _CLNEW FuzzyQuery(t); + CND_CONDITION(q != NULL,"Could not allocate memory for FuzzyQuery q"); + + _CLDECDELETE(t); + return q; +} + + +Query* QueryParserBase::GetWildcardQuery(const TCHAR* field, TCHAR* termStr){ + CND_PRECONDITION(field != NULL,"field is NULL"); + CND_PRECONDITION(termStr != NULL,"termStr is NULL"); + + if ( lowercaseExpandedTerms ) + _tcslwr(termStr); + + Term* t = _CLNEW Term(field, termStr); + CND_CONDITION(t != NULL,"Could not allocate memory for term t"); + Query* q = _CLNEW WildcardQuery(t); + _CLDECDELETE(t); + + return q; +} + +Query* QueryParserBase::GetBooleanQuery(CL_NS_STD(vector)& clauses){ + if ( clauses.size() == 0 ) + return NULL; + + BooleanQuery* query = _CLNEW BooleanQuery(); + //Condition check to see if query has been allocated properly + CND_CONDITION(query != NULL, "No memory could be allocated for query"); + + //iterate through all the clauses + for( uint32_t i=0;iadd(clauses[i]); + } + return query; +} + + +CL_NS(search)::Query* QueryParserBase::GetRangeQuery(const TCHAR* field, TCHAR* part1, TCHAR* part2, bool inclusive){ + //todo: does jlucene handle rangequeries differntly? if we are using + //a certain type of analyser, the terms may be filtered out, which + //is not necessarily what we want. + if (lowercaseExpandedTerms) { + _tcslwr(part1); + _tcslwr(part2); + } + //todo: should see if we can parse the strings as dates... currently we leave that up to the end-developer... + Term* t1 = _CLNEW Term(field,part1); + Term* t2 = _CLNEW Term(field,part2); + Query* ret = _CLNEW RangeQuery(t1, t2, inclusive); + _CLDECDELETE(t1); + _CLDECDELETE(t2); + + return ret; +} + + + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/queryParser/QueryParserBase.h b/3rdparty/clucene/src/CLucene/queryParser/QueryParserBase.h new file mode 100644 index 000000000..261e587b0 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/queryParser/QueryParserBase.h @@ -0,0 +1,204 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_queryParser_QueryParserBase_ +#define _lucene_queryParser_QueryParserBase_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/util/VoidList.h" +#include "CLucene/search/BooleanClause.h" +#include "CLucene/analysis/Analyzers.h" +#include "QueryToken.h" + +CL_NS_DEF(queryParser) + + /** + * Contains default implementations used by QueryParser. + * You can override any of these to provide a customised QueryParser. + */ + class QueryParserBase:LUCENE_BASE + { + protected: + /* The actual operator the parser uses to combine query terms */ + int defaultOperator; + int32_t phraseSlop; + + bool lowercaseExpandedTerms; + + LUCENE_STATIC_CONSTANT(int, CONJ_NONE=0); + LUCENE_STATIC_CONSTANT(int, CONJ_AND=1); + LUCENE_STATIC_CONSTANT(int, CONJ_OR=2); + + LUCENE_STATIC_CONSTANT(int, MOD_NONE=0); + LUCENE_STATIC_CONSTANT(int, MOD_NOT=10); + LUCENE_STATIC_CONSTANT(int, MOD_REQ=11); + + CL_NS(analysis)::Analyzer* analyzer; + + public: + QueryParserBase(CL_NS(analysis)::Analyzer* analyzer); + ~QueryParserBase(); + + /** + * Whether terms of wildcard, prefix, fuzzy and range queries are to be automatically + * lower-cased or not. Default is true. + */ + void setLowercaseExpandedTerms(bool lowercaseExpandedTerms); + + /** + * @see #setLowercaseExpandedTerms(boolean) + */ + bool getLowercaseExpandedTerms() const; + + //values used for setOperator + LUCENE_STATIC_CONSTANT(int, OR_OPERATOR=0); + LUCENE_STATIC_CONSTANT(int, AND_OPERATOR=1); + + /** + * Sets the boolean operator of the QueryParser. + * In default mode (OR_OPERATOR) terms without any modifiers + * are considered optional: for example capital of Hungary is equal to + * capital OR of OR Hungary.
+ * In AND_OPERATOR mode terms are considered to be in conjuction: the + * above mentioned query is parsed as capital AND of AND Hungary + */ + void setDefaultOperator(int oper); + /** + * Gets implicit operator setting, which will be either AND_OPERATOR + * or OR_OPERATOR. + */ + int getDefaultOperator() const; + + //public so that the lexer can call this + virtual void throwParserException(const TCHAR* message, TCHAR ch, int32_t col, int32_t line ); + + /** + * Sets the default slop for phrases. If zero, then exact phrase matches + * are required. Default value is zero. + */ + void setPhraseSlop(int phraseSlop) { this->phraseSlop = phraseSlop; } + + /** + * Gets the default slop for phrases. + */ + int getPhraseSlop() { return phraseSlop; } + + protected: + + /** + * Removes the escaped characters + */ + void discardEscapeChar(TCHAR* token) const; + + //Analyzes the expanded term termStr with the StandardFilter and the LowerCaseFilter. + TCHAR* AnalyzeExpandedTerm(const TCHAR* field, TCHAR* termStr); + + // Adds the next parsed clause. + virtual void AddClause(std::vector& clauses, int32_t conj, int32_t mods, CL_NS(search)::Query* q); + + /** + * Returns a termquery, phrasequery for the specified field. + * Note: this is only a partial implementation, since MultiPhraseQuery is not implemented yet + * return NULL to disallow + */ + virtual CL_NS(search)::Query* GetFieldQuery(const TCHAR* field, TCHAR* queryText); + + /** + * Delegates to GetFieldQuery(string, string), and adds slop onto phrasequery. + * Can be used to remove slop functionality + */ + virtual CL_NS(search)::Query* GetFieldQuery(const TCHAR* field, TCHAR* queryText, int32_t slop); + + /** + * Factory method for generating a query (similar to + * {@link #GetWildcardQuery}). Called when parser parses an input term + * token that uses prefix notation; that is, contains a single '*' wildcard + * character as its last character. Since this is a special case + * of generic wildcard term, and such a query can be optimized easily, + * this usually results in a different query object. + *

+ * Depending on settings, a prefix term may be lower-cased + * automatically. It will not go through the default Analyzer, + * however, since normal Analyzers are unlikely to work properly + * with wildcard templates. + *

+ * Can be overridden by extending classes, to provide custom handling for + * wild card queries, which may be necessary due to missing analyzer calls. + * + * @param field Name of the field query will use. + * @param termStr Term token to use for building term for the query + * (without trailing '*' character!) + * + * @return Resulting {@link Query} built for the term + * return NULL to disallow + */ + virtual CL_NS(search)::Query* GetPrefixQuery(const TCHAR* field, TCHAR* termStr); + + /** + * Factory method for generating a query. Called when parser + * parses an input term token that contains one or more wildcard + * characters (? and *), but is not a prefix term token (one + * that has just a single * character at the end) + *

+ * Depending on settings, prefix term may be lower-cased + * automatically. It will not go through the default Analyzer, + * however, since normal Analyzers are unlikely to work properly + * with wildcard templates. + *

+ * Can be overridden by extending classes, to provide custom handling for + * wildcard queries, which may be necessary due to missing analyzer calls. + * + * @param field Name of the field query will use. + * @param termStr Term token that contains one or more wild card + * characters (? or *), but is not simple prefix term + * + * @return Resulting {@link Query} built for the term + * return NULL to disallow + */ + virtual CL_NS(search)::Query* GetWildcardQuery(const TCHAR* field, TCHAR* termStr); + + /** + * Factory method for generating a query (similar to + * {@link #GetWildcardQuery}). Called when parser parses + * an input term token that has the fuzzy suffix (~) appended. + * + * @param field Name of the field query will use. + * @param termStr Term token to use for building term for the query + * + * @return Resulting {@link Query} built for the term + * return NULL to disallow + */ + virtual CL_NS(search)::Query* GetFuzzyQuery(const TCHAR* field, TCHAR* termStr); + + /** + * Factory method for generating query, given a set of clauses. + * By default creates a boolean query composed of clauses passed in. + * + * Can be overridden by extending classes, to modify query being + * returned. + * + * @param clauses Vector that contains {@link BooleanClause} instances + * to join. + * + * @return Resulting {@link Query} object. + * return NULL to disallow + * + * Memory: clauses must all be cleaned up by this function. + */ + virtual CL_NS(search)::Query* GetBooleanQuery(std::vector& clauses); + + /** + * return NULL to disallow + */ + virtual CL_NS(search)::Query* GetRangeQuery(const TCHAR* field, TCHAR* part1, TCHAR* part2, bool inclusive); + virtual CL_NS(search)::Query* ParseRangeQuery(const TCHAR* field, TCHAR* str, bool inclusive); + + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/queryParser/QueryToken.cpp b/3rdparty/clucene/src/CLucene/queryParser/QueryToken.cpp new file mode 100644 index 000000000..ee88a3cb6 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/queryParser/QueryToken.cpp @@ -0,0 +1,73 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "QueryToken.h" + +CL_NS_DEF(queryParser) + + +QueryToken::QueryToken(): + Value(NULL) +{ + set(UNKNOWN_); +} +QueryToken::QueryToken(TCHAR* value, const int32_t start, const int32_t end, const QueryToken::Types type): + Value(NULL) +{ + set(value,start,end,type); +} + +QueryToken::~QueryToken(){ +//Func - Destructor +//Pre - true +//Post - Instance has been destroyed + + #ifndef LUCENE_TOKEN_WORD_LENGTH + _CLDELETE_CARRAY( Value ); + #endif +} + +// Initializes a new instance of the Token class LUCENE_EXPORT. +// +QueryToken::QueryToken(TCHAR* value, const QueryToken::Types type): + Value(NULL) +{ + set(value,type); +} + +// Initializes a new instance of the Token class LUCENE_EXPORT. +// +QueryToken::QueryToken(QueryToken::Types type): + Value(NULL) +{ + set(type); +} + + +void QueryToken::set(TCHAR* value, const Types type){ + set(value,0,-1,type); +} +void QueryToken::set(TCHAR* value, const int32_t start, const int32_t end, const Types type){ + #ifndef LUCENE_TOKEN_WORD_LENGTH + _CLDELETE_CARRAY(Value); + Value = STRDUP_TtoT(value); + #else + _tcsncpy(Value,value,LUCENE_TOKEN_WORD_LENGTH); + Value[LUCENE_TOKEN_WORD_LENGTH]; + #endif + this->Start = start; + this->End = end; + this->Type = type; + + if ( this->End < 0 ) + this->End = _tcslen(Value); +} +void QueryToken::set(Types type){ + set(LUCENE_BLANK_STRING,0,0,type); +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/queryParser/QueryToken.h b/3rdparty/clucene/src/CLucene/queryParser/QueryToken.h new file mode 100644 index 000000000..739a667ba --- /dev/null +++ b/3rdparty/clucene/src/CLucene/queryParser/QueryToken.h @@ -0,0 +1,76 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_queryParser_QueryToken_ +#define _lucene_queryParser_QueryToken_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "QueryParserBase.h" + +CL_NS_DEF(queryParser) + + // Token class that used by QueryParser. + class QueryToken:LUCENE_BASE + { + public: + enum Types + { + AND_, + OR, + NOT, + PLUS, + MINUS, + LPAREN, + RPAREN, + COLON, + CARAT, + QUOTED, + TERM, + SLOP, + FUZZY, + PREFIXTERM, + WILDTERM, + RANGEIN, + RANGEEX, + NUMBER, + EOF_, + UNKNOWN_ + }; + + + #ifdef LUCENE_TOKEN_WORD_LENGTH + TCHAR Value[LUCENE_TOKEN_WORD_LENGTH+1]; + #else + TCHAR* Value; + #endif + + int32_t Start; + int32_t End; + QueryToken::Types Type; + + // Initializes a new instance of the Token class. + QueryToken(TCHAR* value, const int32_t start, const int32_t end, const Types type); + + // Initializes a new instance of the Token class. + QueryToken(TCHAR* value, const Types type); + + // Initializes a new instance of the Token class. + QueryToken(Types type); + + // Initializes an empty instance of the Token class. + QueryToken(); + + ~QueryToken(); + + void set(TCHAR* value, const int32_t start, const int32_t end, const Types type); + void set(TCHAR* value, const Types type); + void set(Types type); + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/queryParser/TokenList.cpp b/3rdparty/clucene/src/CLucene/queryParser/TokenList.cpp new file mode 100644 index 000000000..7d30b931f --- /dev/null +++ b/3rdparty/clucene/src/CLucene/queryParser/TokenList.cpp @@ -0,0 +1,79 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "TokenList.h" + +#include "CLucene/util/VoidMap.h" +#include "CLucene/util/VoidList.h" +#include "QueryToken.h" + +CL_NS_DEF(queryParser) + + TokenList::TokenList(){ + //Func - Constructor + //Pre - true + //Post - Instance has been created + } + + TokenList::~TokenList(){ + //Func - Destructor + //Pre - true + //Post - The tokenlist has been destroyed + + tokens.clear(); + } + + void TokenList::add(QueryToken* token){ + //Func - Adds a QueryToken token to the TokenList + //Pre - token != NULL + //Post - token has been added to the token list + + CND_PRECONDITION(token != NULL, "token != NULL"); + + tokens.insert(tokens.begin(),token); + } + + void TokenList::push(QueryToken* token){ + //Func - + //Pre - token != NULL + //Post - + + CND_PRECONDITION(token != NULL, "token is NULL"); + + tokens.push_back(token); + } + + QueryToken* TokenList::peek() { + /* DSR:2004.11.01: Reverted my previous (circa April 2004) fix (which + ** raised an exception if Peek was called when there were no tokens) in + ** favor of returning the EOF token. This solution is much better + ** integrated with the rest of the code in the queryParser subsystem. */ + size_t nTokens = tokens.size(); + if (nTokens == 0) { + push(_CLNEW QueryToken(QueryToken::EOF_)); + nTokens++; + } + return tokens[nTokens-1]; + } + + QueryToken* TokenList::extract(){ + //Func - Extract token from the TokenList + //Pre - true + //Post - Retracted token has been returned + + QueryToken* token = peek(); + //Retract the current peeked token + tokens.delete_back(); + + return token; + } + + int32_t TokenList::count() const + { + return tokens.size(); + } +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/queryParser/TokenList.h b/3rdparty/clucene/src/CLucene/queryParser/TokenList.h new file mode 100644 index 000000000..3166bba78 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/queryParser/TokenList.h @@ -0,0 +1,38 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_queryParser_TokenList_ +#define _lucene_queryParser_TokenList_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/util/VoidList.h" +#include "QueryToken.h" +CL_NS_DEF(queryParser) + + // Represents a list of the tokens. + class TokenList:LUCENE_BASE + { + private: + CL_NS(util)::CLVector tokens; //todo:,CL_NS(util)::Deletor::Object + public: + TokenList(); + ~TokenList(); + + void add(QueryToken* token); + + void push(QueryToken* token); + + QueryToken* peek(); + + QueryToken* extract(); + + int32_t count() const; + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/BooleanClause.h b/3rdparty/clucene/src/CLucene/search/BooleanClause.h new file mode 100644 index 000000000..b89cb31d7 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/BooleanClause.h @@ -0,0 +1,90 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_BooleanClause_ +#define _lucene_search_BooleanClause_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif +#include "SearchHeader.h" + +CL_NS_DEF(search) + // A clause in a BooleanQuery. + class BooleanClause:LUCENE_BASE { + public: + class Compare:public CL_NS_STD(binary_function) + { + public: + bool operator()( const BooleanClause* val1, const BooleanClause* val2 ) const{ + return val1->equals(val2); + } + }; + + // The query whose matching documents are combined by the boolean query. + Query* query; + + int32_t getClauseCount(); + + // If true, documents documents which do not + // match this sub-query will not match the boolean query. + bool required; + + // If true, documents documents which do + // match this sub-query will not match the boolean query. + bool prohibited; + + bool deleteQuery; + + // Constructs a BooleanClause with query q, required + // r and prohibited p. + BooleanClause(Query* q, const bool DeleteQuery,const bool req, const bool p): + query(q), + required(req), + prohibited(p), + deleteQuery(DeleteQuery) + { + } + + BooleanClause(const BooleanClause& clone): +#if defined(LUCENE_ENABLE_MEMLEAKTRACKING) +#elif defined(LUCENE_ENABLE_REFCOUNT) +#else + LuceneVoidBase(), +#endif + query(clone.query->clone()), + required(clone.required), + prohibited(clone.prohibited), + deleteQuery(true) + { + } + + BooleanClause* clone() const{ + BooleanClause* ret = _CLNEW BooleanClause(*this); + return ret; + } + + ~BooleanClause(){ + if ( deleteQuery ) + _CLDELETE( query ); + } + + /** Returns true iff o is equal to this. */ + bool equals(const BooleanClause* other) const { + return this->query->equals(other->query) + && (this->required == other->required) + && (this->prohibited == other->prohibited); + } + + size_t hashCode() const{ + return query->hashCode() ^ (this->required?1:0) ^ (this->prohibited?2:0); + } + }; + + +CL_NS_END +#endif + diff --git a/3rdparty/clucene/src/CLucene/search/BooleanQuery.cpp b/3rdparty/clucene/src/CLucene/search/BooleanQuery.cpp new file mode 100644 index 000000000..3fd36d847 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/BooleanQuery.cpp @@ -0,0 +1,363 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "BooleanQuery.h" + +#include "BooleanClause.h" +#include "CLucene/index/IndexReader.h" +#include "CLucene/util/StringBuffer.h" +#include "CLucene/util/Arrays.h" +#include "SearchHeader.h" +#include "BooleanScorer.h" +#include "Scorer.h" + +CL_NS_USE(index) +CL_NS_USE(util) +CL_NS_DEF(search) + + BooleanQuery::BooleanQuery(): + clauses(true) + { + } + + BooleanQuery::BooleanQuery(const BooleanQuery& clone): + Query(clone) + { + for ( uint32_t i=0;iclone(); + clause->deleteQuery=true; + add(clause); + } + } + + BooleanQuery::~BooleanQuery(){ + clauses.clear(); + } + + size_t BooleanQuery::hashCode() const { + //todo: do cachedHashCode, and invalidate on add/remove clause + size_t ret = 0; + for (uint32_t i = 0 ; i < clauses.size(); i++) { + BooleanClause* c = clauses[i]; + ret = 31 * ret + c->hashCode(); + } + ret = ret ^ Similarity::floatToByte(getBoost()); + return ret; + } + + const TCHAR* BooleanQuery::getQueryName() const{ + return getClassName(); + } + const TCHAR* BooleanQuery::getClassName(){ + return _T("BooleanQuery"); + } + + /** + * Default value is 1024. Use org.apache.lucene.maxClauseCount + * system property to override. + */ + size_t BooleanQuery::maxClauseCount = LUCENE_BOOLEANQUERY_MAXCLAUSECOUNT; + size_t BooleanQuery::getMaxClauseCount(){ + return maxClauseCount; + } + + void BooleanQuery::setMaxClauseCount(size_t maxClauseCount){ + BooleanQuery::maxClauseCount = maxClauseCount; + } + + void BooleanQuery::add(Query* query, const bool deleteQuery, const bool required, const bool prohibited) { + BooleanClause* bc = _CLNEW BooleanClause(query,deleteQuery,required, prohibited); + try{ + add(bc); + }catch(...){ + _CLDELETE(bc); + throw; + } + } + + void BooleanQuery::add(BooleanClause* clause) { + if (clauses.size() >= getMaxClauseCount()) + _CLTHROWA(CL_ERR_TooManyClauses,"Too Many Clauses"); + + clauses.push_back(clause); + } + + + size_t BooleanQuery::getClauseCount() const { + return (int32_t) clauses.size(); + } + + TCHAR* BooleanQuery::toString(const TCHAR* field) const{ + StringBuffer buffer; + if (getBoost() != 1.0) { + buffer.append(_T("(")); + } + + for (uint32_t i = 0 ; i < clauses.size(); i++) { + BooleanClause* c = clauses[i]; + if (c->prohibited) + buffer.append(_T("-")); + else if (c->required) + buffer.append(_T("+")); + + if ( c->query->instanceOf(BooleanQuery::getClassName()) ) { // wrap sub-bools in parens + buffer.append(_T("(")); + + TCHAR* buf = c->query->toString(field); + buffer.append(buf); + _CLDELETE_CARRAY( buf ); + + buffer.append(_T(")")); + } else { + TCHAR* buf = c->query->toString(field); + buffer.append(buf); + _CLDELETE_CARRAY( buf ); + } + if (i != clauses.size()-1) + buffer.append(_T(" ")); + + if (getBoost() != 1.0) { + buffer.append(_T(")^")); + buffer.appendFloat(getBoost(),1); + } + } + return buffer.toString(); + } + + + + + BooleanClause** BooleanQuery::getClauses() const + { + CND_MESSAGE(false, "Warning: BooleanQuery::getClauses() is deprecated") + BooleanClause** ret = _CL_NEWARRAY(BooleanClause*, clauses.size()+1); + getClauses(ret); + return ret; + } + + void BooleanQuery::getClauses(BooleanClause** ret) const + { + size_t size=clauses.size(); + for ( uint32_t i=0;iprohibited) { // just return clause + Query* query = c->query->rewrite(reader); // rewrite first + + //if the query doesn't actually get re-written, + //then return a clone (because the BooleanQuery + //will register different to the returned query. + if ( query == c->query ) + query = query->clone(); + + if (getBoost() != 1.0f) { // incorporate boost + query->setBoost(getBoost() * query->getBoost()); + } + + return query; + } + } + + BooleanQuery* clone = NULL; // recursively rewrite + for (uint32_t i = 0 ; i < clauses.size(); i++) { + BooleanClause* c = clauses[i]; + Query* query = c->query->rewrite(reader); + if (query != c->query) { // clause rewrote: must clone + if (clone == NULL) + clone = (BooleanQuery*)this->clone(); + //todo: check if delete query should be on... + //in fact we should try and get rid of these + //for compatibility sake + clone->clauses.set (i, _CLNEW BooleanClause(query, true, c->required, c->prohibited)); + } + } + if (clone != NULL) { + return clone; // some clauses rewrote + } else + return this; // no clauses rewrote + } + + + Query* BooleanQuery::clone() const{ + BooleanQuery* clone = _CLNEW BooleanQuery(*this); + return clone; + } + + /** Returns true iff o is equal to this. */ + bool BooleanQuery::equals(Query* o)const { + if (!(o->instanceOf(BooleanQuery::getClassName()))) + return false; + const BooleanQuery* other = (BooleanQuery*)o; + + bool ret = (this->getBoost() == other->getBoost()); + if ( ret ){ + CLListEquals comp; + ret = comp.equals(&this->clauses,&other->clauses); + } + return ret; + } + + qreal BooleanQuery::BooleanWeight::getValue() { return parentQuery->getBoost(); } + Query* BooleanQuery::BooleanWeight::getQuery() { return (Query*)parentQuery; } + + + + + + BooleanQuery::BooleanWeight::BooleanWeight(Searcher* searcher, + CLVector >* clauses, BooleanQuery* parentQuery) + { + this->searcher = searcher; + this->parentQuery = parentQuery; + this->clauses = clauses; + for (uint32_t i = 0 ; i < clauses->size(); i++) { + weights.push_back((*clauses)[i]->query->_createWeight(searcher)); + } + } + BooleanQuery::BooleanWeight::~BooleanWeight(){ + this->weights.clear(); + } + + qreal BooleanQuery::BooleanWeight::sumOfSquaredWeights() { + qreal sum = 0.0f; + for (uint32_t i = 0 ; i < weights.size(); i++) { + BooleanClause* c = (*clauses)[i]; + Weight* w = weights[i]; + if (!c->prohibited) + sum += w->sumOfSquaredWeights(); // sum sub weights + } + sum *= parentQuery->getBoost() * parentQuery->getBoost(); // boost each sub-weight + return sum ; + } + + void BooleanQuery::BooleanWeight::normalize(qreal norm) { + norm *= parentQuery->getBoost(); // incorporate boost + for (uint32_t i = 0 ; i < weights.size(); i++) { + BooleanClause* c = (*clauses)[i]; + Weight* w = weights[i]; + if (!c->prohibited) + w->normalize(norm); + } + } + + Scorer* BooleanQuery::BooleanWeight::scorer(IndexReader* reader){ + // First see if the (faster) ConjunctionScorer will work. This can be + // used when all clauses are required. Also, at this point a + // BooleanScorer cannot be embedded in a ConjunctionScorer, as the hits + // from a BooleanScorer are not always sorted by document number (sigh) + // and hence BooleanScorer cannot implement skipTo() correctly, which is + // required by ConjunctionScorer. + bool allRequired = true; + bool noneBoolean = true; + { //msvc6 scope fix + for (uint32_t i = 0 ; i < weights.size(); i++) { + BooleanClause* c = (*clauses)[i]; + if (!c->required) + allRequired = false; + if (c->query->instanceOf(BooleanQuery::getClassName())) + noneBoolean = false; + } + } + + if (allRequired && noneBoolean) { // ConjunctionScorer is okay + ConjunctionScorer* result = + _CLNEW ConjunctionScorer(parentQuery->getSimilarity(searcher)); + for (uint32_t i = 0 ; i < weights.size(); i++) { + Weight* w = weights[i]; + Scorer* subScorer = w->scorer(reader); + if (subScorer == NULL) + return NULL; + result->add(subScorer); + } + return result; + } + + // Use good-old BooleanScorer instead. + BooleanScorer* result = _CLNEW BooleanScorer(parentQuery->getSimilarity(searcher)); + + { //msvc6 scope fix + for (uint32_t i = 0 ; i < weights.size(); i++) { + BooleanClause* c = (*clauses)[i]; + Weight* w = weights[i]; + Scorer* subScorer = w->scorer(reader); + if (subScorer != NULL) + result->add(subScorer, c->required, c->prohibited); + else if (c->required) + return NULL; + } + } + + return result; + } + + void BooleanQuery::BooleanWeight::explain(IndexReader* reader, int32_t doc, Explanation* result){ + int32_t coord = 0; + int32_t maxCoord = 0; + qreal sum = 0.0f; + Explanation* sumExpl = _CLNEW Explanation; + for (uint32_t i = 0 ; i < weights.size(); i++) { + BooleanClause* c = (*clauses)[i]; + Weight* w = weights[i]; + Explanation* e = _CLNEW Explanation; + w->explain(reader, doc, e); + if (!c->prohibited) + maxCoord++; + if (e->getValue() > 0) { + if (!c->prohibited) { + sumExpl->addDetail(e); + sum += e->getValue(); + coord++; + e = NULL; //prevent e from being deleted + } else { + //we want to return something else... + _CLDELETE(sumExpl); + result->setValue(0.0f); + result->setDescription(_T("match prohibited")); + return; + } + } else if (c->required) { + _CLDELETE(sumExpl); + result->setValue(0.0f); + result->setDescription(_T("match prohibited")); + return; + } + + _CLDELETE(e); + } + sumExpl->setValue(sum); + + if (coord == 1){ // only one clause matched + Explanation* tmp = sumExpl; + sumExpl = sumExpl->getDetail(0)->clone(); // eliminate wrapper + _CLDELETE(tmp); + } + + sumExpl->setDescription(_T("sum of:")); + qreal coordFactor = parentQuery->getSimilarity(searcher)->coord(coord, maxCoord); + if (coordFactor == 1.0f){ // coord is no-op + result->set(*sumExpl); // eliminate wrapper + _CLDELETE(sumExpl); + } else { + result->setDescription( _T("product of:")); + result->addDetail(sumExpl); + + StringBuffer explbuf; + explbuf.append(_T("coord(")); + explbuf.appendInt(coord); + explbuf.append(_T("/")); + explbuf.appendInt(maxCoord); + explbuf.append(_T(")")); + result->addDetail(_CLNEW Explanation(coordFactor, explbuf.getBuffer())); + result->setValue(sum*coordFactor); + } + } + + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/BooleanQuery.h b/3rdparty/clucene/src/CLucene/search/BooleanQuery.h new file mode 100644 index 000000000..27b67d1e5 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/BooleanQuery.h @@ -0,0 +1,126 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_BooleanQuery_ +#define _lucene_search_BooleanQuery_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "ConjunctionScorer.h" +#include "CLucene/index/IndexReader.h" +#include "CLucene/util/StringBuffer.h" +#include "SearchHeader.h" +#include "BooleanClause.h" +#include "BooleanScorer.h" +#include "Scorer.h" + +CL_NS_DEF(search) + + + // A Query that matches documents matching boolean combinations of other + // queries, typically {@link TermQuery}s or {@link PhraseQuery}s. + class BooleanQuery:public Query { + public: + typedef CL_NS(util)::CLVector > ClausesType; + private: + BooleanQuery::ClausesType clauses; + static size_t maxClauseCount; + + class BooleanWeight: public Weight { + private: + Searcher* searcher; + CL_NS(util)::CLVector > weights; + ClausesType* clauses; + BooleanQuery* parentQuery; + public: + BooleanWeight(Searcher* searcher, + CL_NS(util)::CLVector >* clauses, + BooleanQuery* parentQuery); + ~BooleanWeight(); + Query* getQuery(); + qreal getValue(); + qreal sumOfSquaredWeights(); + void normalize(qreal norm); + Scorer* scorer(CL_NS(index)::IndexReader* reader); + void explain(CL_NS(index)::IndexReader* reader, int32_t doc, Explanation* ret); + };//booleanweight + + protected: + Weight* _createWeight(Searcher* searcher) { + return _CLNEW BooleanWeight(searcher,&clauses,this); + } + BooleanQuery(const BooleanQuery& clone); + public: + /** Constructs an empty boolean query. */ + BooleanQuery(); + + ~BooleanQuery(); + + const TCHAR* getQueryName() const; + static const TCHAR* getClassName(); + + /** Return the maximum number of clauses permitted, 1024 by default. + * Attempts to add more than the permitted number of clauses cause {@link + * TooManyClauses} to be thrown.*/ + static size_t getMaxClauseCount(); + + /** Set the maximum number of clauses permitted. */ + static void setMaxClauseCount(size_t maxClauseCount); + + /** Adds a clause to a boolean query. Clauses may be: + *

    + *
  • required which means that documents which do not + * match this sub-query will not match the boolean query; + *
  • prohibited which means that documents which do + * match this sub-query will not match the boolean query; or + *
  • neither, in which case matched documents are neither prohibited from + * nor required to match the sub-query. However, a document must match at + * least 1 sub-query to match the boolean query. + *
+ * It is an error to specify a clause as both required and + * prohibited. + * + * @see #getMaxClauseCount() + */ + void add(Query* query, const bool required, const bool prohibited){ + add(query,false,required,prohibited); + } + void add(Query* query, const bool deleteQuery, const bool required, const bool prohibited); + + /** Copies the clauses of this query into the array. + * The array must be at least as long as getClauseCount() + * If you want to use the clauses, make sure you null terminate it. + */ + void getClauses(BooleanClause** clauses) const; + + ///@deprecated + _CL_DEPRECATED( getClauses(clauses) ) BooleanClause** getClauses() const; + + /** + * Give client code access to clauses.size() so we know how + * large the array returned by getClauses is. + */ + size_t getClauseCount() const; + + /** Adds a clause to a boolean query. + * @see #getMaxClauseCount() + */ + void add(BooleanClause* clause); + + Query* rewrite(CL_NS(index)::IndexReader* reader); + Query* clone() const; + bool equals(Query* o) const; + + /** Prints a user-readable version of this query. */ + TCHAR* toString(const TCHAR* field) const; + /** Returns a hash code value for this object.*/ + size_t hashCode() const; + }; + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/BooleanScorer.cpp b/3rdparty/clucene/src/CLucene/search/BooleanScorer.cpp new file mode 100644 index 000000000..ae7ee40d6 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/BooleanScorer.cpp @@ -0,0 +1,248 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "BooleanScorer.h" + +#include "Scorer.h" +#include "Similarity.h" + +CL_NS_USE(util) +CL_NS_DEF(search) + + BooleanScorer::BooleanScorer(Similarity* similarity): + Scorer(similarity), + scorers(NULL), + maxCoord (1), + nextMask (1), + end(0), + current(NULL), + requiredMask (0), + prohibitedMask (0), + coordFactors (NULL) + { + bucketTable = _CLNEW BucketTable(this); + } + + BooleanScorer::~BooleanScorer(){ + //Func - Destructor + //Pre - true + //Post - The instance has been destroyed + + _CLDELETE(bucketTable); + _CLDELETE_ARRAY(coordFactors); + _CLDELETE(scorers); + } + + + bool BooleanScorer::next() { + bool more; + do { + while (bucketTable->first != NULL) { // more queued + current = bucketTable->first; + bucketTable->first = current->next; // pop the queue + + // check prohibited & required + if ((current->bits & prohibitedMask) == 0 && + (current->bits & requiredMask) == requiredMask) { + return true; + } + } + + // refill the queue + more = false; + end += BooleanScorer::BucketTable_SIZE; + for (SubScorer* sub = scorers; sub != NULL; sub = sub->next) { + Scorer* scorer = sub->scorer; + int32_t doc; + while (!sub->done && (doc=scorer->doc()) < end) { + sub->collector->collect(doc, scorer->score()); + sub->done = !scorer->next(); + } + if (!sub->done) { + more = true; + } + } + } while (bucketTable->first != NULL || more); + + return false; + } + + qreal BooleanScorer::score(){ + if (coordFactors == NULL) + computeCoordFactors(); + return current->score * coordFactors[current->coord]; + } + + bool BooleanScorer::skipTo(int32_t target) { + _CLTHROWA(CL_ERR_UnsupportedOperation,"UnsupportedOperationException: BooleanScorer::skipTo"); + } + + void BooleanScorer::explain(int32_t doc, Explanation* ret) { + _CLTHROWA(CL_ERR_UnsupportedOperation,"UnsupportedOperationException: BooleanScorer::explain"); + } + + TCHAR* BooleanScorer::toString() { + CL_NS(util)::StringBuffer buffer; + buffer.append(_T("boolean(")); + for (SubScorer* sub = scorers; sub != NULL; sub = sub->next) { + buffer.append(sub->scorer->toString()); + buffer.append(_T(" ")); + } + buffer.appendChar(')'); + return buffer.toString(); + } + + void BooleanScorer::add(Scorer* scorer, const bool required, const bool prohibited) { + int32_t mask = 0; + if (required || prohibited) { + if (nextMask == 0) + _CLTHROWA(CL_ERR_IndexOutOfBounds, "More than 32 required/prohibited clauses in query."); + mask = nextMask; + nextMask = ( nextMask << 1 ); + } else + mask = 0; + + if (!prohibited) + maxCoord++; + + if (prohibited) + prohibitedMask |= mask; // update prohibited mask + else if (required) + requiredMask |= mask; // update required mask + + //scorer, HitCollector, and scorers is delete in the SubScorer + scorers = _CLNEW SubScorer(scorer, required, prohibited, + bucketTable->newCollector(mask), scorers); + } + + void BooleanScorer::computeCoordFactors(){ + coordFactors = _CL_NEWARRAY(qreal,maxCoord); + for (int32_t i = 0; i < maxCoord; i++) + coordFactors[i] = getSimilarity()->coord(i, maxCoord-1); + } + + /*void BooleanScorer::score(HitCollector* results, const int32_t maxDoc) { + if (coordFactors == NULL) + computeCoordFactors(); + + while (currentDoc < maxDoc) { + currentDoc = (currentDoc+BucketTable_SIZEnext) + t->scorer->score((t->collector), currentDoc); + bucketTable->collectHits(results); + } + }*/ + + + + + BooleanScorer::SubScorer::SubScorer(Scorer* scr, const bool r, const bool p, HitCollector* c, SubScorer* nxt): + scorer(scr), + required(r), + prohibited(p), + collector(c), + next(nxt) + { + //Func - Constructor + //Pre - scr != NULL, + // c != NULL + // nxt may or may not be NULL + //Post - The instance has been created + + CND_PRECONDITION(scr != NULL,"scr is NULL"); + CND_PRECONDITION(c != NULL,"c is NULL"); + + done = !scorer->next(); + } + + BooleanScorer::SubScorer::~SubScorer(){ + //Func - Destructor + //Pre - true + //Post - The instance has been destroyed + + for (SubScorer * ptr = next; ptr; ){ + SubScorer* next = ptr->next; + ptr->next = NULL; + _CLDELETE(ptr); + ptr = next; + } + _CLDELETE(scorer); + _CLDELETE(collector); + } + + BooleanScorer::Bucket::Bucket(): + doc(-1), + score(0.0), + bits(0), + coord(0), + next(NULL) + { + } + BooleanScorer::Bucket::~Bucket(){ + } + + + + + BooleanScorer::BucketTable::BucketTable(BooleanScorer* scr): + scorer(scr), + first(NULL) + { + buckets = _CL_NEWARRAY(Bucket,BucketTable_SIZE); + } + BooleanScorer::BucketTable::~BucketTable(){ + clear(); + _CLDELETE_ARRAY(buckets); + } + + void BooleanScorer::BucketTable::clear(){ + //delete first; + first = NULL; + } + int32_t BooleanScorer::BucketTable::size() const { return BooleanScorer::BucketTable_SIZE; } + + HitCollector* BooleanScorer::BucketTable::newCollector(const int32_t mask) { + return _CLNEW Collector(mask, this); + } + + + + + + + + + + BooleanScorer::Collector::Collector(const int32_t msk, BucketTable* bucketTbl): + bucketTable(bucketTbl), + mask(msk) + { + } + + void BooleanScorer::Collector::collect(const int32_t doc, const qreal score){ + BucketTable* table = bucketTable; + int32_t i = doc & (BooleanScorer::BucketTable_SIZE-1); + Bucket* bucket = &table->buckets[i]; + + if (bucket->doc != doc) { // invalid bucket + bucket->doc = doc; // set doc + bucket->score = score; // initialize score + bucket->bits = mask; // initialize mask + bucket->coord = 1; // initialize coord + + bucket->next = table->first; // push onto valid list + table->first = bucket; + } else { // valid bucket + bucket->score += score; // increment score + bucket->bits |= mask; // add bits in mask + bucket->coord++; // increment coord + } + } + + + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/BooleanScorer.h b/3rdparty/clucene/src/CLucene/search/BooleanScorer.h new file mode 100644 index 000000000..2147bc516 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/BooleanScorer.h @@ -0,0 +1,99 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +* +* Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_BooleanScorer_ +#define _lucene_search_BooleanScorer_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "Scorer.h" + +CL_NS_DEF(search) + +class BooleanScorer : public Scorer { +public: + class Bucket : LUCENE_BASE { + public: + int32_t doc; // tells if bucket is valid + qreal score; // incremental score + int32_t bits; // used for bool constraints + int32_t coord; // count of terms in score + Bucket* next; // next valid bucket + + Bucket(); + ~Bucket(); + }; + + class SubScorer: LUCENE_BASE { + public: + bool done; + Scorer* scorer; + bool required; + bool prohibited; + HitCollector* collector; + SubScorer* next; + SubScorer(Scorer* scr, const bool r, const bool p, HitCollector* c, SubScorer* nxt); + ~SubScorer(); + }; + + class BucketTable:LUCENE_BASE { + private: + BooleanScorer* scorer; + public: + Bucket* buckets; + Bucket* first; // head of valid list + + BucketTable(BooleanScorer* scr); + int32_t size() const; + HitCollector* newCollector(const int32_t mask); + void clear(); + ~BucketTable(); + + }; + + class Collector: public HitCollector { + private: + BucketTable* bucketTable; + int32_t mask; + public: + Collector(const int32_t mask, BucketTable* bucketTable); + + void collect(const int32_t doc, const qreal score); + }; + + SubScorer* scorers; + BucketTable* bucketTable; + + int32_t maxCoord; + int32_t nextMask; + + int32_t end; + Bucket* current; + +public: + LUCENE_STATIC_CONSTANT(int32_t,BucketTable_SIZE=1024); + int32_t requiredMask; + int32_t prohibitedMask; + qreal* coordFactors; + + BooleanScorer(Similarity* similarity); + ~BooleanScorer(); + void add(Scorer* scorer, const bool required, const bool prohibited); + int32_t doc() const { return current->doc; } + bool next(); + qreal score(); + bool skipTo(int32_t target); + void explain(int32_t doc, Explanation* ret); + TCHAR* toString(); + void computeCoordFactors(); +}; + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/CachingWrapperFilter.cpp b/3rdparty/clucene/src/CLucene/search/CachingWrapperFilter.cpp new file mode 100644 index 000000000..694556ca7 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/CachingWrapperFilter.cpp @@ -0,0 +1,86 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "CachingWrapperFilter.h" + +CL_NS_DEF(search) +CL_NS_USE(index) +CL_NS_USE(util) + +AbstractCachingFilter::AbstractCachingFilter(): + cache(false,true) +{ +} +AbstractCachingFilter::AbstractCachingFilter(const AbstractCachingFilter& copy): + cache(false,true) +{ +} +AbstractCachingFilter::~AbstractCachingFilter(){ +} +AbstractCachingFilter::BitSetHolder::BitSetHolder(CL_NS(util)::BitSet* bits, bool deleteBs){ + this->bits = bits; + this->deleteBs = deleteBs; +} +AbstractCachingFilter::BitSetHolder::~BitSetHolder(){ + if ( deleteBs ) + _CLDELETE(bits); +} + + +BitSet* AbstractCachingFilter::bits(IndexReader* reader){ + SCOPED_LOCK_MUTEX(cache.THIS_LOCK) + BitSetHolder* cached = cache.get(reader); + if ( cached != NULL ) + return cached->bits; + BitSet* bs = doBits(reader); + BitSetHolder* bsh = _CLNEW BitSetHolder(bs, doShouldDeleteBitSet(bs)); + cache.put(reader,bsh); + return bs; +} +void AbstractCachingFilter::closeCallback(CL_NS(index)::IndexReader* reader, void*){ + SCOPED_LOCK_MUTEX(cache.THIS_LOCK) + cache.remove(reader); +} + + + + +CachingWrapperFilter::CachingWrapperFilter(Filter* filter, bool deleteFilter){ + this->filter = filter; + this->deleteFilter = deleteFilter; +} +CachingWrapperFilter::CachingWrapperFilter(const CachingWrapperFilter& copy): + AbstractCachingFilter(copy) +{ + this->filter = copy.filter->clone(); + this->deleteFilter = true; +} +Filter* CachingWrapperFilter::clone() const{ + return _CLNEW CachingWrapperFilter(*this); +} +TCHAR* CachingWrapperFilter::toString(){ + TCHAR* fs = filter->toString(); + int len = _tcslen(fs)+23; + TCHAR* ret = _CL_NEWARRAY(TCHAR,len); + _sntprintf(ret,len,_T("CachingWrapperFilter(%s)"),fs); + _CLDELETE_CARRAY(fs); + return ret; +} +BitSet* CachingWrapperFilter::doBits(IndexReader* reader){ + return filter->bits(reader); +} +bool CachingWrapperFilter::doShouldDeleteBitSet( CL_NS(util)::BitSet* bits ){ + return filter->shouldDeleteBitSet(bits); +} +CachingWrapperFilter::~CachingWrapperFilter(){ + if ( deleteFilter ){ + _CLDELETE(filter); + }else + filter=NULL; +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/CachingWrapperFilter.h b/3rdparty/clucene/src/CLucene/search/CachingWrapperFilter.h new file mode 100644 index 000000000..e48a18292 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/CachingWrapperFilter.h @@ -0,0 +1,80 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_CachingWrapperFilter_ +#define _lucene_search_CachingWrapperFilter_ + +#include "CLucene/util/BitSet.h" +#include "CLucene/index/IndexReader.h" +#include "Filter.h" + +CL_NS_DEF(search) +/** + * Wraps another filter's result and caches it. The purpose is to allow + * filters to implement this and allow itself to be cached. Alternatively, + * use the CachingWrapperFilter to cache the filter. + */ +class AbstractCachingFilter: public Filter +{ + class BitSetHolder: LUCENE_BASE{ + bool deleteBs; + public: + BitSetHolder(CL_NS(util)::BitSet* bits, bool deleteBs); + ~BitSetHolder(); + CL_NS(util)::BitSet* bits; + }; + void closeCallback(CL_NS(index)::IndexReader* reader, void* param); + typedef CL_NS(util)::CLHashMap, + CL_NS(util)::Equals::Void, + CL_NS(util)::Deletor::Object, + CL_NS(util)::Deletor::Object > CacheType; + + CacheType cache; + +protected: + AbstractCachingFilter( const AbstractCachingFilter& copy ); + virtual CL_NS(util)::BitSet* doBits( CL_NS(index)::IndexReader* reader ) = 0; + virtual bool doShouldDeleteBitSet( CL_NS(util)::BitSet* bits ){ return false; } + AbstractCachingFilter(); +public: + virtual ~AbstractCachingFilter(); + + /** Returns a BitSet with true for documents which should be permitted in + search results, and false for those that should not. */ + CL_NS(util)::BitSet* bits( CL_NS(index)::IndexReader* reader ); + + virtual Filter *clone() const = 0; + virtual TCHAR *toString() = 0; + + bool shouldDeleteBitSet( const CL_NS(util)::BitSet* bits ) const{ return false; } +}; + +/** + * Wraps another filter's result and caches it. The purpose is to allow + * filters to simply filter, and then wrap with this class to add + * caching, keeping the two concerns decoupled yet composable. + */ +class CachingWrapperFilter: public AbstractCachingFilter +{ +private: + Filter* filter; + bool deleteFilter; +protected: + CachingWrapperFilter( const CachingWrapperFilter& copy ); + CL_NS(util)::BitSet* doBits( CL_NS(index)::IndexReader* reader ); + bool doShouldDeleteBitSet( CL_NS(util)::BitSet* bits ); +public: + CachingWrapperFilter( Filter* filter, bool deleteFilter=true ); + ~CachingWrapperFilter(); + + Filter *clone() const; + TCHAR *toString(); +}; + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/ChainedFilter.cpp b/3rdparty/clucene/src/CLucene/search/ChainedFilter.cpp new file mode 100644 index 000000000..4b6389c0f --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/ChainedFilter.cpp @@ -0,0 +1,213 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ + +#include +#include +#include "ChainedFilter.h" + +CL_NS_DEF(search) +CL_NS_USE(index) +CL_NS_USE(util) +CL_NS_USE(document) + + +ChainedFilter::ChainedFilter( Filter ** _filters, int _op ): + filters(_filters), + logicArray(NULL), + logic(_op) +{ +} +ChainedFilter::ChainedFilter( Filter** _filters, int* _array ): + filters(_filters), + logicArray(_array), + logic(-1) +{ +} +ChainedFilter::ChainedFilter( const ChainedFilter& copy ) : + logicArray( copy.logicArray ), + logic( copy.logic ) +{ + filters = copy.filters; +} +ChainedFilter::~ChainedFilter(void) +{ + +} + +Filter* ChainedFilter::clone() const { + return _CLNEW ChainedFilter(*this ); +} + +const TCHAR* ChainedFilter::getLogicString(int logic){ + if ( logic == ChainedFilter::OR ) + return _T("OR"); + else if ( logic == ChainedFilter::AND ) + return _T("AND"); + else if ( logic == ChainedFilter::ANDNOT ) + return _T("ANDNOT"); + else if ( logic == ChainedFilter::XOR ) + return _T("XOR"); + else if ( logic >= ChainedFilter::USER ){ + return _T("USER"); + } + return _T(""); +} + +TCHAR* ChainedFilter::toString() +{ + + Filter** filter = filters; + + StringBuffer buf(_T("ChainedFilter: [")); + int* la = logicArray; + while(*filter ) + { + if ( filter != filters ) + buf.appendChar(' '); + buf.append(getLogicString(logic==-1?*la:logic)); + buf.appendChar(' '); + + TCHAR* filterstr = (*filter)->toString(); + buf.append(filterstr); + _CLDELETE_ARRAY( filterstr ); + + filter++; + if ( logic == -1 ) + la++; + } + + buf.appendChar(']'); + + return buf.toString(); +} + + +/** Returns a BitSet with true for documents which should be permitted in +search results, and false for those that should not. */ +BitSet* ChainedFilter::bits( IndexReader* reader ) +{ + if( logic != -1 ) + return bits( reader, logic ); + else if( logicArray != NULL ) + return bits( reader, logicArray ); + else + return bits( reader, DEFAULT ); +} + + +BitSet* ChainedFilter::bits( IndexReader* reader, int logic ) +{ + BitSet* bts = NULL; + + Filter** filter = filters; + + // see discussion at top of file + if( *filter ) { + BitSet* tmp = (*filter)->bits( reader ); + if ( (*filter)->shouldDeleteBitSet(tmp) ) //if we are supposed to delete this BitSet, then + bts = tmp; //we can safely call it our own + else if ( tmp == NULL ){ + int32_t len = reader->maxDoc(); + bts = _CLNEW BitSet( len ); //bitset returned null, which means match _all_ + for (int32_t i=0;iset(i); + }else{ + bts = tmp->clone(); //else it is probably cached, so we need to copy it before using it. + } + filter++; + } + else + bts = _CLNEW BitSet( reader->maxDoc() ); + + while( *filter ) { + doChain( bts, reader, logic, *filter ); + filter++; + } + + return bts; +} + + +BitSet* ChainedFilter::bits( IndexReader* reader, int* _logicArray ) +{ + BitSet* bts = NULL; + + Filter** filter = filters; + int* logic = _logicArray; + + // see discussion at top of file + if( *filter ) { + BitSet* tmp = (*filter)->bits( reader ); + if ( (*filter)->shouldDeleteBitSet(tmp) ) //if we are supposed to delete this BitSet, then + bts = tmp; //we can safely call it our own + else if ( tmp == NULL ){ + int32_t len = reader->maxDoc(); + bts = _CLNEW BitSet( len ); //bitset returned null, which means match _all_ + for (int32_t i=0;iset(i); //todo: this could mean that we can skip certain types of filters + } + else + { + bts = tmp->clone(); //else it is probably cached, so we need to copy it before using it. + } + filter++; + logic++; + } + else + bts = _CLNEW BitSet( reader->maxDoc() ); + + while( *filter ) { + doChain( bts, reader, *logic, *filter ); + filter++; + logic++; + } + + return bts; +} + +void ChainedFilter::doUserChain( CL_NS(util)::BitSet* chain, CL_NS(util)::BitSet* filter, int logic ){ + _CLTHROWA(CL_ERR_Runtime,"User chain logic not implemented by superclass"); +} + +BitSet* ChainedFilter::doChain( BitSet* resultset, IndexReader* reader, int logic, Filter* filter ) +{ + BitSet* filterbits = filter->bits( reader ); + int32_t maxDoc = reader->maxDoc(); + int32_t i=0; + if ( logic >= ChainedFilter::USER ){ + doUserChain(resultset,filterbits,logic); + }else{ + switch( logic ) + { + case OR: + for( i=0; i < maxDoc; i++ ) + resultset->set( i, (resultset->get(i) || (filterbits==NULL || filterbits->get(i) ))?1:0 ); + break; + case AND: + for( i=0; i < maxDoc; i++ ) + resultset->set( i, (resultset->get(i) && (filterbits==NULL || filterbits->get(i) ))?1:0 ); + break; + case ANDNOT: + for( i=0; i < maxDoc; i++ ) + resultset->set( i, (resultset->get(i) && (filterbits==NULL || filterbits->get(i)))?0:1 ); + break; + case XOR: + for( i=0; i < maxDoc; i++ ) + resultset->set( i, resultset->get(i) ^ ((filterbits==NULL || filterbits->get(i) )?1:0) ); + break; + default: + doChain( resultset, reader, DEFAULT, filter ); + } + } + + if ( filter->shouldDeleteBitSet(filterbits) ) + _CLDELETE( filterbits ); + + return resultset; +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/ChainedFilter.h b/3rdparty/clucene/src/CLucene/search/ChainedFilter.h new file mode 100644 index 000000000..f4d9d0049 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/ChainedFilter.h @@ -0,0 +1,86 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_ChainedFilter_ +#define _lucene_search_ChainedFilter_ + +#include "CLucene/index/IndexReader.h" +#include "CLucene/util/BitSet.h" +#include "CLucene/search/Filter.h" + +CL_NS_DEF(search) + +/* +Discussion - brian@unixpoet.com + +From ChainedFilter.java: + +... + +// First AND operation takes place against a completely false +// bitset and will always return zero results. Thanks to +// Daniel Armbrust for pointing this out and suggesting workaround. + +if (logic[0] == AND) +{ + result = (BitSet) chain[i].bits(reader).clone(); + ++i; +} + +... + +The observation is correct and it was buggy. The problem is that the same +issue remains for the ANDNOT logic op but with the inverse result: all bits +set to 1. The result of the other ops, i.e. OR, AND, XOR for the first filter +ends up just copying the bitset of the first filter (explicitly in the case of the AND). + +Why not do the same for the NAND? This will have the side effect of rendering the first op +in the logic array superflous - not a big problem. + +The only "problem" is that we will return different results then the Java +Lucene code - though I prefer CLucene to be a correct implementation and only maintain +API compat rather than full 100% compat with Lucene. +*/ +class ChainedFilter: public Filter +{ +public: + LUCENE_STATIC_CONSTANT(int, OR = 0); //set current bit if the chain is set OR if the filter bit is set + LUCENE_STATIC_CONSTANT(int, AND = 1); //set current bit if the chain is set AND the filter bit is set + LUCENE_STATIC_CONSTANT(int, ANDNOT = 2); //set current bit if the chain is not set AND the filter bit is not set + LUCENE_STATIC_CONSTANT(int, XOR = 3); //set current bit if the chain is set OR the filter bit is set BUT not both is set + + LUCENE_STATIC_CONSTANT(int, USER = 5); //add this value to user defined value, then override doUserChain + + LUCENE_STATIC_CONSTANT(int, DEFAULT = OR); + +protected: + Filter **filters; + int *logicArray; + int logic; + + ChainedFilter( const ChainedFilter& copy ); + CL_NS(util)::BitSet* bits( CL_NS(index)::IndexReader* reader, int logic ); + CL_NS(util)::BitSet* bits( CL_NS(index)::IndexReader* reader, int* logicArray ); + CL_NS(util)::BitSet* doChain( CL_NS(util)::BitSet* result, CL_NS(index)::IndexReader* reader, int logic, Filter* filter ); + + virtual void doUserChain( CL_NS(util)::BitSet* chain, CL_NS(util)::BitSet* filter, int logic ); + virtual const TCHAR* getLogicString(int logic); +public: + ChainedFilter( Filter** filters, int op = DEFAULT ); + ChainedFilter( Filter** filters, int* _array ); + virtual ~ChainedFilter(); + + /** Returns a BitSet with true for documents which should be permitted in + search results, and false for those that should not. */ + CL_NS(util)::BitSet* bits( CL_NS(index)::IndexReader* reader ); + + virtual Filter* clone() const; + + TCHAR* toString(); +}; + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/Compare.h b/3rdparty/clucene/src/CLucene/search/Compare.h new file mode 100644 index 000000000..ab38b17f1 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/Compare.h @@ -0,0 +1,161 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_Compare_ +#define _lucene_search_Compare_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "FieldSortedHitQueue.h" + +CL_NS_DEF(search) + + +class ScoreDocComparators:LUCENE_BASE { +protected: + ScoreDocComparators(){} +public: + ~ScoreDocComparators(){ + } + + class Relevance:public ScoreDocComparator { + public: + int32_t compare (struct ScoreDoc* i, struct ScoreDoc* j) { + if (i->score > j->score) return -1; + if (i->score < j->score) return 1; + return 0; + } + CL_NS(util)::Comparable* sortValue (struct ScoreDoc* i) { + return _CLNEW CL_NS(util)::Compare::Float (i->score); + } + int32_t sortType() { + return SortField::DOCSCORE; + } + }; + + class IndexOrder:public ScoreDocComparator{ + public: + IndexOrder(): + ScoreDocComparator() + { + + } + int32_t compare (struct ScoreDoc* i, struct ScoreDoc* j) { + if (i->doc < j->doc) return -1; + if (i->doc > j->doc) return 1; + return 0; + } + CL_NS(util)::Comparable* sortValue (struct ScoreDoc* i) { + return _CLNEW CL_NS(util)::Compare::Int32(i->doc); + } + int32_t sortType() { + return SortField::DOC; + } + }; + + + class String: public ScoreDocComparator { + FieldCache::StringIndex* index; +#ifdef _CL__CND_DEBUG + int32_t length; +#endif + public: + String(FieldCache::StringIndex* index, int32_t len) + { +#ifdef _CL__CND_DEBUG + this->length = len; +#endif + this->index = index; + } + + int32_t compare (struct ScoreDoc* i, struct ScoreDoc* j) { + CND_PRECONDITION(i->docdoc>=length") + CND_PRECONDITION(j->docdoc>=length") + if (index->order[i->doc] < index->order[j->doc]) return -1; + if (index->order[i->doc] > index->order[j->doc]) return 1; + return 0; + } + + CL_NS(util)::Comparable* sortValue (struct ScoreDoc* i) { + return _CLNEW CL_NS(util)::Compare::TChar(index->lookup[index->order[i->doc]]); + } + + int32_t sortType() { + return SortField::STRING; + } + }; + + class Int32:public ScoreDocComparator{ + int32_t* fieldOrder; +#ifdef _CL__CND_DEBUG + int32_t length; +#endif + public: + Int32(int32_t* fieldOrder, int32_t len) + { + this->fieldOrder = fieldOrder; +#ifdef _CL__CND_DEBUG + this->length = len; +#endif + } + + + int32_t compare (struct ScoreDoc* i, struct ScoreDoc* j) { + CND_PRECONDITION(i->docdoc>=length") + CND_PRECONDITION(j->docdoc>=length") + if (fieldOrder[i->doc] < fieldOrder[j->doc]) return -1; + if (fieldOrder[i->doc] > fieldOrder[j->doc]) return 1; + return 0; + } + + CL_NS(util)::Comparable* sortValue (struct ScoreDoc* i) { + CND_PRECONDITION(i->docdoc>=length") + return _CLNEW CL_NS(util)::Compare::Int32(fieldOrder[i->doc]); + } + + int32_t sortType() { + return SortField::INT; + } + }; + + class Float:public ScoreDocComparator { + qreal* fieldOrder; +#ifdef _CL__CND_DEBUG + int32_t length; +#endif + public: + Float(qreal* fieldOrder, int32_t len) + { + this->fieldOrder = fieldOrder; +#ifdef _CL__CND_DEBUG + this->length = len; +#endif + } + + int32_t compare (struct ScoreDoc* i, struct ScoreDoc* j) { + CND_PRECONDITION(i->docdoc>=length") + CND_PRECONDITION(j->docdoc>=length") + if (fieldOrder[i->doc] < fieldOrder[j->doc]) return -1; + if (fieldOrder[i->doc] > fieldOrder[j->doc]) return 1; + return 0; + } + + CL_NS(util)::Comparable* sortValue (struct ScoreDoc* i) { + CND_PRECONDITION(i->docdoc>=length") + return _CLNEW CL_NS(util)::Compare::Float(fieldOrder[i->doc]); + } + + int32_t sortType() { + return SortField::FLOAT; + } + }; +}; + + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/ConjunctionScorer.cpp b/3rdparty/clucene/src/CLucene/search/ConjunctionScorer.cpp new file mode 100644 index 000000000..9b7846f8e --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/ConjunctionScorer.cpp @@ -0,0 +1,144 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "ConjunctionScorer.h" +#include "CLucene/util/Arrays.h" + +CL_NS_USE(index) +CL_NS_USE(util) +CL_NS_DEF(search) + + Scorer* ConjunctionScorer::first() const{ + if ( scorers.end() == scorers.begin() ) + return NULL; + + return *scorers.begin(); + } //get First + Scorer* ConjunctionScorer::last() { + if ( scorers.end() == scorers.begin() ) + return NULL; + + CL_NS_STD(list)::iterator i = scorers.end(); + --i; + return *i; + } //get Last + + class _ScorerSorter:public CL_NS(util)::Arrays::_Arrays{ + public: + bool equals(Scorer* o1,Scorer* o2) const{ + return o1->doc() == o2->doc(); + } + int32_t compare(Scorer* o1,Scorer* o2) const{ + return o1->doc() - o2->doc(); + } + }; + _ScorerSorter __ScorerSorter; + + void ConjunctionScorer::sortScorers() { + // move scorers to an array + int32_t size = scorers.size(); + Scorer** array = _CL_NEWARRAY(Scorer*,size+1); + scorers.toArray(array); + scorers.clear(); // empty the list + + // note that this comparator is not consistent with equals! + __ScorerSorter.sort(array,size,0,size); + + for (int32_t i = 0; idoc() < last()->doc()) { // find doc w/ all clauses + more = first()->skipTo(last()->doc()); // skip first upto last + Scorer* scorer = *scorers.begin(); + scorers.delete_front(); + scorers.push_back(scorer); // move first to last + } + return more; // found a doc with all clauses + } + + + void ConjunctionScorer::init() { + more = scorers.size() > 0; + + // compute coord factor + coord = getSimilarity()->coord(scorers.size(), scorers.size()); + + // move each scorer to its first entry + CL_NS_STD(list)::iterator i = scorers.begin(); + while (more && i!=scorers.end()) { + more = ((Scorer*)*i)->next(); + ++i; + } + + if (more) + sortScorers(); // initial sort of list + + firstTime = false; + } + + ConjunctionScorer::ConjunctionScorer(Similarity* similarity): + Scorer(similarity), + scorers(false), + firstTime(true), + more(true), + coord(0.0) + { + } + ConjunctionScorer::~ConjunctionScorer(){ + scorers.setDoDelete(true); + } + + TCHAR *CL_NS(search)::Scorer::toString(void){ + return STRDUP_TtoT(_T("ConjunctionScorer")); + } + + + void ConjunctionScorer::add(Scorer* scorer){ + scorers.push_back(scorer); + } + + + int32_t ConjunctionScorer::doc() const{ return first()->doc(); } + + bool ConjunctionScorer::next() { + if (firstTime) { + init(); + } else if (more) { + more = last()->next(); // trigger further scanning + } + return doNext(); + } + + bool ConjunctionScorer::skipTo(int32_t target) { + CL_NS_STD(list)::iterator i = scorers.begin(); + while (more && i!=scorers.end()) { + more = ((Scorer*)*i)->skipTo(target); + ++i; + } + if (more) + sortScorers(); // re-sort scorers + return doNext(); + } + + qreal ConjunctionScorer::score(){ + qreal score = 0.0f; // sum scores + CL_NS_STD(list)::const_iterator i = scorers.begin(); + while (i!=scorers.end()){ + score += (*i)->score(); + ++i; + } + score *= coord; + return score; + } + + + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/ConjunctionScorer.h b/3rdparty/clucene/src/CLucene/search/ConjunctionScorer.h new file mode 100644 index 000000000..4b6807209 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/ConjunctionScorer.h @@ -0,0 +1,50 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_ConjunctionScorer_ +#define _lucene_search_ConjunctionScorer_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif +#include "Scorer.h" +#include "Similarity.h" + +CL_NS_DEF(search) + +/** Scorer for conjunctions, sets of queries, all of which are required. */ +class ConjunctionScorer: public Scorer { +private: + CL_NS(util)::CLLinkedList > scorers; + bool firstTime; + bool more; + qreal coord; + + Scorer* first() const; + Scorer* last(); + void sortScorers(); + bool doNext(); + void init(); +public: + ConjunctionScorer(Similarity* similarity); + virtual ~ConjunctionScorer(); + TCHAR* toString(void){ + return STRDUP_TtoT(_T("ConjunctionScorer")); + } + void add(Scorer* scorer); + int32_t doc() const; + bool next(); + bool skipTo(int32_t target); + qreal score(); + virtual void explain(int32_t doc, Explanation* ret) { + _CLTHROWA(CL_ERR_UnsupportedOperation,"UnsupportedOperationException: ConjunctionScorer::explain"); + } + + +}; + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/DateFilter.cpp b/3rdparty/clucene/src/CLucene/search/DateFilter.cpp new file mode 100644 index 000000000..925858204 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/DateFilter.cpp @@ -0,0 +1,93 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "DateFilter.h" + +CL_NS_USE(index) +CL_NS_USE(util) +CL_NS_USE(document) +CL_NS_DEF(search) + + DateFilter::~DateFilter(){ + _CLDECDELETE( start ); + _CLDECDELETE( end ); + } + + DateFilter::DateFilter(const DateFilter& copy): + start( _CL_POINTER(copy.start) ), + end ( _CL_POINTER(copy.end) ) + { + } + + /** Constructs a filter for field f matching times between + from and to. */ + DateFilter::DateFilter(const TCHAR* f, int64_t from, int64_t to) + { + TCHAR* tmp = DateField::timeToString(from); + start = _CLNEW Term(f, tmp); + _CLDELETE_CARRAY(tmp); + + tmp = DateField::timeToString(to); + end = _CLNEW Term(start, tmp); + _CLDELETE_CARRAY(tmp); + } + + /** Constructs a filter for field f matching times before + time. */ + DateFilter* DateFilter::Before(const TCHAR* field, int64_t time) { + return _CLNEW DateFilter(field, 0,time); + } + + /** Constructs a filter for field f matching times after + time. */ + DateFilter* DateFilter::After(const TCHAR* field, int64_t time) { + return _CLNEW DateFilter(field,time, DATEFIELD_DATE_MAX ); + } + + /** Returns a BitSet with true for documents which should be permitted in + search results, and false for those that should not. */ + BitSet* DateFilter::bits(IndexReader* reader) { + BitSet* bts = _CLNEW BitSet(reader->maxDoc()); + + TermEnum* enumerator = reader->terms(start); + if (enumerator->term(false) == NULL){ + _CLDELETE(enumerator); + return bts; + } + TermDocs* termDocs = reader->termDocs(); + + try { + while (enumerator->term(false)->compareTo(end) <= 0) { + termDocs->seek(enumerator->term(false)); + while (termDocs->next()) { + bts->set(termDocs->doc()); + } + if (!enumerator->next()) { + break; + } + } + } _CLFINALLY ( + termDocs->close(); + _CLDELETE(termDocs); + enumerator->close(); + _CLDELETE(enumerator); + ); + return bts; + } + + Filter* DateFilter::clone() const{ + return _CLNEW DateFilter(*this); + } + + TCHAR* DateFilter::toString(){ + size_t len = _tcslen(start->field()) + start->textLength() + end->textLength() + 8; + TCHAR* ret = _CL_NEWARRAY(TCHAR,len); + ret[0]=0; + _sntprintf(ret,len,_T("%s: [%s-%s]"), start->field(),start->text(),end->text()); + return ret; + } +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/DateFilter.h b/3rdparty/clucene/src/CLucene/search/DateFilter.h new file mode 100644 index 000000000..b37272b84 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/DateFilter.h @@ -0,0 +1,59 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_DateFilter_ +#define _lucene_search_DateFilter_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/document/DateField.h" +#include "CLucene/index/Term.h" +#include "CLucene/index/Terms.h" +#include "CLucene/index/IndexReader.h" +#include "CLucene/util/BitSet.h" +#include "Filter.h" + +CL_NS_DEF(search) + /** + * A Filter that restricts search results to a range of time. + * + *

For this to work, documents must have been indexed with a + * {@link DateField}. + */ + class DateFilter: public Filter { + private: + CL_NS(index)::Term* start; + CL_NS(index)::Term* end; + + protected: + DateFilter(const DateFilter& copy); + public: + ~DateFilter(); + + /** Constructs a filter for field f matching times between + from and to. */ + DateFilter(const TCHAR* f, int64_t from, int64_t to); + + /** Constructs a filter for field f matching times before + time. */ + static DateFilter* Before(const TCHAR* field, int64_t time) ; + + /** Constructs a filter for field f matching times after + time. */ + static DateFilter* After(const TCHAR* field, int64_t time) ; + + /** Returns a BitSet with true for documents which should be permitted in + search results, and false for those that should not. */ + CL_NS(util)::BitSet* bits(CL_NS(index)::IndexReader* reader) ; + + Filter* clone() const; + + TCHAR* toString(); + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/ExactPhraseScorer.cpp b/3rdparty/clucene/src/CLucene/search/ExactPhraseScorer.cpp new file mode 100644 index 000000000..1fbf2e99d --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/ExactPhraseScorer.cpp @@ -0,0 +1,85 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "ExactPhraseScorer.h" + +#include "PhraseScorer.h" +#include "CLucene/index/Terms.h" + +CL_NS_USE(index) +CL_NS_DEF(search) + + ExactPhraseScorer::ExactPhraseScorer(Weight* weight, TermPositions** tps, + int32_t* positions, Similarity* similarity, uint8_t* norms): + PhraseScorer(weight, tps, positions, similarity, norms){ + //Func - Constructor + //Pre - tps != NULL + // tpsLength >= 0 + // n != NULL + //Post - Instance has been created + + CND_PRECONDITION(tps != NULL,"tps is NULL"); + CND_PRECONDITION(tps[0] != NULL,"tps is NULL"); + //CND_PRECONDITION(n != NULL,"n is NULL") =this is checked already in PhraseScorer + + } + + qreal ExactPhraseScorer::phraseFreq(){ + //Func - Returns the freqency of the phrase + //Pre - first != NULL + // last != NULL + // pq != NULL + // size of the PhraseQueue pq is 0 + //Post - The frequency of the phrase has been returned + + CND_PRECONDITION(first != NULL,"first is NULL"); + CND_PRECONDITION(last != NULL,"last is NULL"); + CND_PRECONDITION(pq != NULL,"pq is NULL"); + CND_PRECONDITION(pq->size()==0,"pq is not empty"); + + //build pq from list + + //Add the nodes of the list of PhrasePositions and store them + //into the PhraseQueue pq so it can used to build + //a list of sorted nodes + for (PhrasePositions* pp = first; pp != NULL; pp = pp->_next) { + //Read the first TermPosition of the current PhrasePositions pp + pp->firstPosition(); + //Store the current PhrasePositions pp into the PhraseQueue pq + pq->put(pp); + } + //pqToList requires that first and last be NULL when it's called. + //This is done at the beginning of pqToList() + //In this case, the nodes of the linked list are referenced by pq (see + //above loop), so we can clear our pointers to the head and tail of the + //linked list without fear of leaking the nodes. + + //rebuild list from pq + pqToList(); + + //Initialize freq at 0 + int32_t freq = 0; + + //find position with all terms + do { + //scan forward in first + while (first->position < last->position){ + do{ + if (!first->nextPosition()){ + return (qreal)freq; + } + } while (first->position < last->position); + //Make the current first node the last node in the list + firstToLast(); + } + //all equal: a match has been found + freq++; + } while (last->nextPosition()); + + return (qreal)freq; + } +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/ExactPhraseScorer.h b/3rdparty/clucene/src/CLucene/search/ExactPhraseScorer.h new file mode 100644 index 000000000..d82aa9e9a --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/ExactPhraseScorer.h @@ -0,0 +1,31 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_ExactPhraseScorer_ +#define _lucene_search_ExactPhraseScorer_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "PhraseScorer.h" +#include "CLucene/index/Terms.h" + +CL_NS_DEF(search) + + class ExactPhraseScorer: public PhraseScorer { + public: + ExactPhraseScorer(Weight* weight, CL_NS(index)::TermPositions** tps, int32_t* positions, + Similarity* similarity, uint8_t* norms ); + + ~ExactPhraseScorer(){ + } + protected: + //Returns the exact freqency of the phrase + qreal phraseFreq(); + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/Explanation.cpp b/3rdparty/clucene/src/CLucene/search/Explanation.cpp new file mode 100644 index 000000000..87189b71b --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/Explanation.cpp @@ -0,0 +1,133 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "Explanation.h" +#include "CLucene/util/StringBuffer.h" + +CL_NS_USE(util) +CL_NS_DEF(search) + + +Explanation::Explanation(qreal value, const TCHAR* description) { + this->value = value; + _tcsncpy(this->description,description,LUCENE_SEARCH_EXPLANATION_DESC_LEN); +} + +Explanation::Explanation() { + this->value = 0; + this->description[0]=0; +} + +Explanation::Explanation(const Explanation& copy){ + set(copy); +} +void Explanation::set(const Explanation& copy){ + this->value = copy.value; + STRCPY_TtoT(description,copy.description,LUCENE_SEARCH_EXPLANATION_DESC_LEN); + + details.clear(); + typedef CL_NS(util)::Deletor::Object Deletor; + CL_NS(util)::CLArrayList::const_iterator itr; + itr = copy.details.begin(); + while ( itr != copy.details.end() ){ + details.push_back( (*itr)->clone() ); + ++itr; + } +} + +Explanation::~Explanation(){ +} + +void Explanation::setDescription(const TCHAR* description) { + _tcsncpy(this->description,description,LUCENE_SEARCH_EXPLANATION_DESC_LEN); +} + + +Explanation* Explanation::clone() const{ + return _CLNEW Explanation(*this); +} + +qreal Explanation::getValue() const{ + return value; +} + +void Explanation::setValue(qreal value) { + this->value = value; +} + +const TCHAR* Explanation::getDescription() const { + return description; +} + +///todo: mem leaks +TCHAR* Explanation::toString(int32_t depth) { + StringBuffer buffer; + for (int32_t i = 0; i < depth; i++) { + buffer.append(_T(" ")); + } + buffer.appendFloat(getValue(),2); + buffer.append(_T(" = ")); + buffer.append(getDescription()); + buffer.append(_T("\n")); + + for ( uint32_t j=0;jtoString(depth+1); + buffer.append(tmp); + _CLDELETE_CARRAY(tmp); + } + return buffer.toString(); +} + +int Explanation::getDetailsLength(){ + return details.size(); +} +Explanation* Explanation::getDetail(int i){ + return details[i]; +} +/** The sub-nodes of this explanation node. */ +void Explanation::getDetails(Explanation** ret) { + uint32_t size = details.size(); + for ( uint32_t i=0;iclone(); + } + ret[size] = NULL; +} + +/** Adds a sub-node to this explanation node. */ +void Explanation::addDetail(Explanation* detail) { + details.push_back(detail); +} + +/** Render an explanation as text. */ +TCHAR* Explanation::toString() { + return toString(0); +} + +/** Render an explanation as HTML. */ +///todo: mem leaks +TCHAR* Explanation::toHtml() { + StringBuffer buffer; + TCHAR* tmp; + buffer.append(_T("

    \n")); + + buffer.append(_T("
  • ")); + buffer.appendFloat(getValue(),2); + buffer.append(_T(" = ")); + + buffer.append(getDescription()); + buffer.append(_T("
  • \n")); + + for ( uint32_t i=0;itoHtml(); + buffer.append(tmp); + _CLDELETE_CARRAY(tmp); + } + buffer.append(_T("
\n")); + + return buffer.toString(); +} +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/Explanation.h b/3rdparty/clucene/src/CLucene/search/Explanation.h new file mode 100644 index 000000000..7c95822b6 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/Explanation.h @@ -0,0 +1,66 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_Explanation +#define _lucene_search_Explanation + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +CL_NS_DEF(search) + + #define LUCENE_SEARCH_EXPLANATION_DESC_LEN 200 + class Explanation :LUCENE_BASE { + private: + qreal value; // the value of this node + TCHAR description[LUCENE_SEARCH_EXPLANATION_DESC_LEN]; // what it represents + CL_NS(util)::CLArrayList > details; // sub-explanations + + TCHAR* toString(int32_t depth); + protected: + Explanation(const Explanation& copy); + public: + Explanation(); + ~Explanation(); + + Explanation(qreal value, const TCHAR* description); + void set(const Explanation& other); + + Explanation* clone() const; + + /** The value assigned to this explanation node. */ + qreal getValue() const; + + /** Sets the value assigned to this explanation node. */ + void setValue(qreal value); + + /** A description of this explanation node. */ + const TCHAR* getDescription() const; ///count = count; + this->order = values; + this->lookup = lookup; + } + + ~StringIndex(){ + _CLDELETE_ARRAY(order); + + for ( int i=0;ifield as integers and returns an array + * of size reader.maxDoc() of the value each document + * has in the given field. + * @param reader Used to get field values. + * @param field Which field contains the integers. + * @return The values in the given field for each document. + * @throws IOException If any error occurs. + */ + virtual FieldCacheAuto* getInts (CL_NS(index)::IndexReader* reader, const TCHAR* field) = 0; + + /** Checks the internal cache for an appropriate entry, and if + * none is found, reads the terms in field as floats and returns an array + * of size reader.maxDoc() of the value each document + * has in the given field. + * @param reader Used to get field values. + * @param field Which field contains the floats. + * @return The values in the given field for each document. + * @throws IOException If any error occurs. + */ + virtual FieldCacheAuto* getFloats (CL_NS(index)::IndexReader* reader, const TCHAR* field) = 0; + + /** Checks the internal cache for an appropriate entry, and if none + * is found, reads the term values in field and returns an array + * of size reader.maxDoc() containing the value each document + * has in the given field. + * @param reader Used to get field values. + * @param field Which field contains the strings. + * @return The values in the given field for each document. + * @throws IOException If any error occurs. + */ + virtual FieldCacheAuto* getStrings (CL_NS(index)::IndexReader* reader, const TCHAR* field) = 0; + + /** Checks the internal cache for an appropriate entry, and if none + * is found reads the term values in field and returns + * an array of them in natural order, along with an array telling + * which element in the term array each document uses. + * @param reader Used to get field values. + * @param field Which field contains the strings. + * @return Array of terms and index into the array for each document. + * @throws IOException If any error occurs. + */ + virtual FieldCacheAuto* getStringIndex (CL_NS(index)::IndexReader* reader, const TCHAR* field) = 0; + + /** Checks the internal cache for an appropriate entry, and if + * none is found reads field to see if it contains integers, floats + * or strings, and then calls one of the other methods in this class to get the + * values. For string values, a FieldCache::StringIndex is returned. After + * calling this method, there is an entry in the cache for both + * type AUTO and the actual found type. + * @param reader Used to get field values. + * @param field Which field contains the values. + * @return int32_t[], qreal[] or FieldCache::StringIndex. + * @throws IOException If any error occurs. + */ + virtual FieldCacheAuto* getAuto (CL_NS(index)::IndexReader* reader, const TCHAR* field) = 0; + + /** Checks the internal cache for an appropriate entry, and if none + * is found reads the terms out of field and calls the given SortComparator + * to get the sort values. A hit in the cache will happen if reader, + * field, and comparator are the same (using equals()) + * as a previous call to this method. + * @param reader Used to get field values. + * @param field Which field contains the values. + * @param comparator Used to convert terms into something to sort by. + * @return Array of sort objects, one for each document. + * @throws IOException If any error occurs. + */ + virtual FieldCacheAuto* getCustom (CL_NS(index)::IndexReader* reader, const TCHAR* field, SortComparator* comparator) = 0; +}; + +/** A class holding an AUTO field. In java lucene an Object + is used, but we use this. + contentType: + 1 - integer array + 2 - float array + 3 - FieldCache::StringIndex object + This class is also used when returning getInt, getFloat, etc + because we have no way of returning the size of the array and this + class can be used to determine the array size +*/ +class FieldCacheAuto:LUCENE_BASE{ +public: + enum{ + INT_ARRAY=1, + FLOAT_ARRAY=2, + STRING_INDEX=3, + STRING_ARRAY=4, + COMPARABLE_ARRAY=5, + SORT_COMPARATOR=6, + SCOREDOC_COMPARATOR=7 + }; + + FieldCacheAuto(int32_t len, int32_t type); + ~FieldCacheAuto(); + ///if contents should be deleted too, depending on type + bool ownContents; + int32_t contentLen; //number of items in the list + uint8_t contentType; + int32_t* intArray; //item 1 + qreal* floatArray; //item 2 + FieldCache::StringIndex* stringIndex; //item 3 + TCHAR** stringArray; //item 4 + CL_NS(util)::Comparable** comparableArray; //item 5 + SortComparator* sortComparator; //item 6 + ScoreDocComparator* scoreDocComparator; //item 7 + +}; + + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/search/FieldCacheImpl.cpp b/3rdparty/clucene/src/CLucene/search/FieldCacheImpl.cpp new file mode 100644 index 000000000..62052097e --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/FieldCacheImpl.cpp @@ -0,0 +1,529 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "FieldCacheImpl.h" + +CL_NS_USE(util) +CL_NS_USE(index) +CL_NS_DEF(search) + +FieldCacheImpl::FieldCacheImpl(): + cache(false,true){ +} +FieldCacheImpl::~FieldCacheImpl(){ + cache.clear(); +} + +FieldCacheImpl::FileEntry::FileEntry (const TCHAR* field, int32_t type) { + this->field = CLStringIntern::intern(field CL_FILELINE); + this->type = type; + this->custom = NULL; + this->_hashCode = 0; + } + + /** Creates one of these objects for a custom comparator. */ + FieldCacheImpl::FileEntry::FileEntry (const TCHAR* field, SortComparatorSource* custom) { + this->field = CLStringIntern::intern(field CL_FILELINE); + this->type = SortField::CUSTOM; + this->custom = custom; + this->_hashCode = 0; + } + FieldCacheImpl::FileEntry::~FileEntry(){ + CLStringIntern::unintern(field); + } + + size_t FieldCacheImpl::FileEntry::hashCode(){ + if ( _hashCode == 0 ){ + //todo: cache hashcode? + size_t ret = Misc::thashCode(field); + if ( custom != NULL ) + ret = ret ^ custom->hashCode(); + ret = ret ^ (type*7); //type with a seed + _hashCode = ret; + } + return _hashCode; + } + int32_t FieldCacheImpl::FileEntry::compareTo(const FieldCacheImpl::FileEntry* other) const{ + if ( other->field == this->field ){ + if ( other->type == this->type ){ + if ( other->custom == NULL ){ + if ( this->custom == NULL ) + return 0; //both null + else + return 1; + }else if ( this->custom == NULL ) + return -1; + else if ( other->custom < this->custom ) + return -1; + else if ( other->custom > this->custom ) + return 1; + else + return 0; + }else if ( other->type > this->type ) + return 1; + else + return -1; + + }else + return _tcscmp(other->field,this->field); + } + + /** Two of these are equal iff they reference the same field and type. */ + /*bool FieldCacheImpl::FileEntry::equals (FileEntry* other) { + if (other->field == field && other->type == type) { + if (other->custom == NULL) { + if (custom == NULL) + return true; + } else if (other->custom->equals (custom)) { + return true; + } + } + }*/ + + /** Composes a hashcode based on the field and type. */ + /*size_t FieldCacheImpl::FileEntry::hashCode() { + return field->hashCode() ^ type ^ (custom==NULL ? 0 : custom->hashCode()); + }*/ + + + + + + /** See if an object is in the cache. */ + FieldCacheAuto* FieldCacheImpl::lookup (IndexReader* reader, const TCHAR* field, int32_t type) { + FieldCacheAuto* ret = NULL; + FileEntry* entry = _CLNEW FileEntry (field, type); + { + SCOPED_LOCK_MUTEX(THIS_LOCK) + fieldcacheCacheReaderType* readerCache = cache.get(reader); + if (readerCache != NULL) + ret = readerCache->get (entry); + _CLDELETE(entry); + } + return ret; + } + + + /** See if a custom object is in the cache. */ + FieldCacheAuto* FieldCacheImpl::lookup (IndexReader* reader, const TCHAR* field, SortComparatorSource* comparer) { + FieldCacheAuto* ret = NULL; + FileEntry* entry = _CLNEW FileEntry (field, comparer); + { + SCOPED_LOCK_MUTEX(THIS_LOCK) + fieldcacheCacheReaderType* readerCache = cache.get(reader); + if (readerCache != NULL) + ret = readerCache->get (entry); + _CLDELETE(entry); +} + return ret; + } + + void FieldCacheImpl::closeCallback(CL_NS(index)::IndexReader* reader, void* fieldCacheImpl){ + FieldCacheImpl* fci = (FieldCacheImpl*)fieldCacheImpl; + SCOPED_LOCK_MUTEX(fci->THIS_LOCK) + fci->cache.remove(reader); + } + + /** Put an object into the cache. */ + void FieldCacheImpl::store (IndexReader* reader, const TCHAR* field, int32_t type, FieldCacheAuto* value) { + FileEntry* entry = _CLNEW FileEntry (field, type); + { + SCOPED_LOCK_MUTEX(THIS_LOCK) + fieldcacheCacheReaderType* readerCache = cache.get(reader); + if (readerCache == NULL) { + readerCache = _CLNEW fieldcacheCacheReaderType; + cache.put(reader,readerCache); + reader->addCloseCallback(closeCallback, this); + } + readerCache->put (entry, value); + //this is supposed to return the previous value, but it needs to be deleted!!! + } + } + + /** Put a custom object into the cache. */ + void FieldCacheImpl::store (IndexReader* reader, const TCHAR* field, SortComparatorSource* comparer, FieldCacheAuto* value) { + FileEntry* entry = _CLNEW FileEntry (field, comparer); + { + SCOPED_LOCK_MUTEX(THIS_LOCK) + fieldcacheCacheReaderType* readerCache = cache.get(reader); + if (readerCache == NULL) { + readerCache = _CLNEW fieldcacheCacheReaderType; + cache.put(reader, readerCache); + reader->addCloseCallback(FieldCacheImpl::closeCallback, this); + } + readerCache->put(entry, value); + //this is supposed to return the previous value, but it needs to be deleted!!! + } + } + + + + + + // inherit javadocs + FieldCacheAuto* FieldCacheImpl::getInts (IndexReader* reader, const TCHAR* field) { + field = CLStringIntern::intern(field CL_FILELINE); + FieldCacheAuto* ret = lookup (reader, field, SortField::INT); + if (ret == NULL) { + int32_t retLen = reader->maxDoc(); + int32_t* retArray = _CL_NEWARRAY(int32_t,retLen); + memset(retArray,0,sizeof(int32_t)*retLen); + if (retLen > 0) { + TermDocs* termDocs = reader->termDocs(); + + Term* term = _CLNEW Term (field, LUCENE_BLANK_STRING, false); + TermEnum* termEnum = reader->terms (term); + _CLDECDELETE(term); + try { + if (termEnum->term(false) == NULL) { + _CLTHROWA(CL_ERR_Runtime,"no terms in field"); //todo: add detailed error: + field); + } + do { + Term* term = termEnum->term(false); + if (term->field() != field) + break; + + TCHAR* end; + int32_t termval = (int32_t)_tcstoi64(term->text(), &end, 10); + termDocs->seek (termEnum); + while (termDocs->next()) { + retArray[termDocs->doc()] = termval; + } + } while (termEnum->next()); + } _CLFINALLY( + termDocs->close(); + _CLDELETE(termDocs); + termEnum->close(); + _CLDELETE(termEnum); + ) + } + + FieldCacheAuto* fa = _CLNEW FieldCacheAuto(retLen,FieldCacheAuto::INT_ARRAY); + fa->intArray = retArray; + + store (reader, field, SortField::INT, fa); + CLStringIntern::unintern(field); + return fa; + } + CLStringIntern::unintern(field); + return ret; + } + + // inherit javadocs + FieldCacheAuto* FieldCacheImpl::getFloats (IndexReader* reader, const TCHAR* field){ + field = CLStringIntern::intern(field CL_FILELINE); + FieldCacheAuto* ret = lookup (reader, field, SortField::FLOAT); + if (ret == NULL) { + int32_t retLen = reader->maxDoc(); + qreal* retArray = _CL_NEWARRAY(qreal,retLen); + memset(retArray,0,sizeof(qreal)*retLen); + if (retLen > 0) { + TermDocs* termDocs = reader->termDocs(); + + Term* term = _CLNEW Term (field, LUCENE_BLANK_STRING, false); + TermEnum* termEnum = reader->terms (term); + _CLDECDELETE(term); + + try { + if (termEnum->term(false) == NULL) { + _CLTHROWA(CL_ERR_Runtime,"no terms in field "); //todo: make richer error + field); + } + do { + Term* term = termEnum->term(false); + if (term->field() != field) + break; + + TCHAR* tmp; + qreal termval = _tcstod(term->text(),&tmp); + termDocs->seek (termEnum); + while (termDocs->next()) { + retArray[termDocs->doc()] = termval; + } + } while (termEnum->next()); + } _CLFINALLY( + termDocs->close(); + _CLDELETE(termDocs); + termEnum->close(); + _CLDELETE(termEnum); + ) + } + + FieldCacheAuto* fa = _CLNEW FieldCacheAuto(retLen,FieldCacheAuto::FLOAT_ARRAY); + fa->floatArray = retArray; + + store (reader, field, SortField::FLOAT, fa); + CLStringIntern::unintern(field); + return fa; + } + CLStringIntern::unintern(field); + return ret; + } + + + // inherit javadocs + FieldCacheAuto* FieldCacheImpl::getStrings (IndexReader* reader, const TCHAR* field){ + //todo: this is not really used, i think? + field = CLStringIntern::intern(field CL_FILELINE); + FieldCacheAuto* ret = lookup (reader, field, SortField::STRING); + if (ret == NULL) { + int32_t retLen = reader->maxDoc(); + TCHAR** retArray = _CL_NEWARRAY(TCHAR*,retLen+1); + memset(retArray,0,sizeof(TCHAR*)*(retLen+1)); + if (retLen > 0) { + TermDocs* termDocs = reader->termDocs(); + + Term* term = _CLNEW Term (field, LUCENE_BLANK_STRING, false); + TermEnum* termEnum = reader->terms (term); + _CLDECDELETE(term); + + try { + if (termEnum->term(false) == NULL) { + _CLTHROWA(CL_ERR_Runtime,"no terms in field "); //todo: extend to + field); + } + do { + Term* term = termEnum->term(false); + if (term->field() != field) + break; + const TCHAR* termval = term->text(); + termDocs->seek (termEnum); + while (termDocs->next()) { + retArray[termDocs->doc()] = STRDUP_TtoT(termval); //todo: any better way of doing this??? + } + } while (termEnum->next()); + } _CLFINALLY( + retArray[retLen]=NULL; + termDocs->close(); + _CLDELETE(termDocs); + termEnum->close(); + _CLDELETE(termEnum); + ) + } + + + FieldCacheAuto* fa = _CLNEW FieldCacheAuto(retLen,FieldCacheAuto::STRING_ARRAY); + fa->stringArray = retArray; + fa->ownContents=true; + store (reader, field, SortField::STRING, fa); + CLStringIntern::unintern(field); + return fa; + } + CLStringIntern::unintern(field); + return ret; + } + + // inherit javadocs + FieldCacheAuto* FieldCacheImpl::getStringIndex (IndexReader* reader, const TCHAR* field){ + field = CLStringIntern::intern(field CL_FILELINE); + FieldCacheAuto* ret = lookup (reader, field, STRING_INDEX); + int32_t t = 0; // current term number + if (ret == NULL) { + int32_t retLen = reader->maxDoc(); + int32_t* retArray = _CL_NEWARRAY(int32_t,retLen); + memset(retArray,0,sizeof(int32_t)*retLen); + + TCHAR** mterms = _CL_NEWARRAY(TCHAR*,retLen+2); + mterms[0]=NULL; + if ( retLen > 0 ) { + TermDocs* termDocs = reader->termDocs(); + + Term* term = _CLNEW Term (field, LUCENE_BLANK_STRING, false); + TermEnum* termEnum = reader->terms (term); + _CLDECDELETE(term); + + + CND_PRECONDITION(t+1 <= retLen, "t out of bounds"); + + // an entry for documents that have no terms in this field + // should a document with no terms be at top or bottom? + // this puts them at the top - if it is changed, FieldDocSortedHitQueue + // needs to change as well. + mterms[t++] = NULL; + + try { + if (termEnum->term(false) == NULL) { + _CLTHROWA(CL_ERR_Runtime,"no terms in field"); //todo: make rich message " + field); + } + do { + Term* term = termEnum->term(false); + if (term->field() != field) + break; + + // store term text + // we expect that there is at most one term per document + if (t >= retLen+1) + _CLTHROWA(CL_ERR_Runtime,"there are more terms than documents in field"); //todo: rich error \"" + field + "\""); + mterms[t] = STRDUP_TtoT(term->text()); + + termDocs->seek (termEnum); + while (termDocs->next()) { + retArray[termDocs->doc()] = t; + } + + t++; + } while (termEnum->next()); + CND_PRECONDITION(tclose(); + _CLDELETE(termDocs); + termEnum->close(); + _CLDELETE(termEnum); + ); + + if (t == 0) { + // if there are no terms, make the term array + // have a single NULL entry + _CLDELETE_ARRAY(mterms); + mterms = _CL_NEWARRAY(TCHAR*,1); //todo: delete old mterms? + mterms[0]=NULL; + } else if (t < retLen) { //todo: check, was mterms.length + // if there are less terms than documents, + // trim off the dead array space + //const TCHAR** terms = _CL_NEWARRAY(TCHAR,t); + //System.arraycopy (mterms, 0, terms, 0, t); + //mterms = terms; + + //we simply shorten the length of the array... + + } + } + FieldCache::StringIndex* value = _CLNEW FieldCache::StringIndex (retArray, mterms,t); + + FieldCacheAuto* fa = _CLNEW FieldCacheAuto(retLen,FieldCacheAuto::STRING_INDEX); + fa->stringIndex = value; + fa->ownContents=true; + store (reader, field, STRING_INDEX, fa); + CLStringIntern::unintern(field); + return fa; + } + CLStringIntern::unintern(field); + return ret; + } + + // inherit javadocs + FieldCacheAuto* FieldCacheImpl::getAuto (IndexReader* reader, const TCHAR* field) { + field = CLStringIntern::intern(field CL_FILELINE); + FieldCacheAuto* ret = lookup (reader, field, SortField::AUTO); + if (ret == NULL) { + Term* term = _CLNEW Term (field, LUCENE_BLANK_STRING, false); + TermEnum* enumerator = reader->terms (term); + _CLDECDELETE(term); + + try { + Term* term = enumerator->term(false); + if (term == NULL) { + _CLTHROWA(CL_ERR_Runtime,"no terms in field - cannot determine sort type"); //todo: make rich error: " + field + " + } + if (term->field() == field) { + const TCHAR* termtext = term->text(); + size_t termTextLen = term->textLength(); + + bool isint=true; + for ( size_t i=0;iclose(); _CLDELETE(enumerator) ); + + } + CLStringIntern::unintern(field); + return ret; + } + + + // inherit javadocs + FieldCacheAuto* FieldCacheImpl::getCustom (IndexReader* reader, const TCHAR* field, SortComparator* comparator){ + field = CLStringIntern::intern(field CL_FILELINE); + + FieldCacheAuto* ret = lookup (reader, field, comparator); + if (ret == NULL) { + int32_t retLen = reader->maxDoc(); + Comparable** retArray = _CL_NEWARRAY(Comparable*,retLen); + memset(retArray,0,sizeof(Comparable*)*retLen); + if (retLen > 0) { + TermDocs* termDocs = reader->termDocs(); + TermEnum* termEnum = reader->terms (); + + try { + if (termEnum->term(false) == NULL) { + _CLTHROWA(CL_ERR_Runtime,"no terms in field "); //todo: make rich error + field); + } + do { + Term* term = termEnum->term(false); + if (term->field() != field) + break; + Comparable* termval = comparator->getComparable (term->text()); + termDocs->seek (termEnum); + while (termDocs->next()) { + retArray[termDocs->doc()] = termval; + } + } while (termEnum->next()); + } _CLFINALLY ( + termDocs->close(); + _CLDELETE(termDocs); + termEnum->close(); + _CLDELETE(termEnum); + ); + } + + FieldCacheAuto* fa = _CLNEW FieldCacheAuto(retLen,FieldCacheAuto::COMPARABLE_ARRAY); + fa->comparableArray = retArray; + fa->ownContents=true; + store (reader, field, SortField::CUSTOM, fa); + CLStringIntern::unintern(field); + return fa; + } + CLStringIntern::unintern(field); + return ret; + } + + + FieldCacheImpl::fieldcacheCacheReaderType::fieldcacheCacheReaderType(){ + setDeleteKey(false); + setDeleteValue(false); + } + FieldCacheImpl::fieldcacheCacheReaderType::~fieldcacheCacheReaderType(){ + iterator itr = begin(); + while ( itr != end() ){ + FileEntry* f = itr->first; + if ( f->getType() != SortField::AUTO ) + _CLDELETE( itr->second ); + _CLDELETE( f ); + ++itr; + } + clear(); + } +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/FieldCacheImpl.h b/3rdparty/clucene/src/CLucene/search/FieldCacheImpl.h new file mode 100644 index 000000000..ac3c4cabc --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/FieldCacheImpl.h @@ -0,0 +1,144 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_FieldCacheImpl_ +#define _lucene_search_FieldCacheImpl_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/index/IndexReader.h" +#include "FieldCache.h" +#include "Sort.h" + + +CL_NS_DEF(search) + + +/** + * Expert: The default cache implementation, storing all values in memory. + * + */ +class FieldCacheImpl: public FieldCache { +public: + DEFINE_MUTEX(THIS_LOCK) + + /** Expert: Every key in the internal cache is of this type. */ + class FileEntry:LUCENE_BASE { + const TCHAR* field; // which Field + int32_t type; // which SortField type + SortComparatorSource* custom; // which custom comparator + size_t _hashCode; + public: + /** Creates one of these objects. */ + FileEntry (const TCHAR* field, int32_t type); + + /** Creates one of these objects for a custom comparator. */ + FileEntry (const TCHAR* field, SortComparatorSource* custom); + ~FileEntry(); + + int32_t getType() const{ return type; } + + /** Two of these are equal iff they reference the same field and type. */ + bool equals (FileEntry* other) const; + + /** Composes a hashcode based on the field and type. */ + size_t hashCode(); + + int32_t compareTo(const FileEntry* other) const; + + class Compare:LUCENE_BASE, public CL_NS(util)::Compare::_base // + { + public: + bool operator()( FileEntry* f1, FileEntry* f2 ) const{ + return ( f1->compareTo(f2) < 0 ); + } + size_t operator()( FileEntry* t ) const{ + return t->hashCode(); + } + }; + class Equals:LUCENE_BASE, public CL_NS(util)::Compare::_base // + { + public: + bool operator()( FileEntry* f1, FileEntry* f2 ) const{ + return ( f1->compareTo(f2) == 0 ); + } + }; + }; + + FieldCacheImpl(); + ~FieldCacheImpl(); +private: + + ///the type that is stored in the field cache. can't use a typedef because + ///the decorated name would become too long + class fieldcacheCacheReaderType: public CL_NS(util)::CLHashMap, + CL_NS(util)::Deletor::Object >{ + public: + fieldcacheCacheReaderType(); + ~fieldcacheCacheReaderType(); + }; + + //note: typename gets too long if using cacheReaderType as a typename + typedef CL_NS(util)::CLHashMap, + CL_NS(util)::Equals::Void, + CL_NS(util)::Deletor::Object, + CL_NS(util)::Deletor::Object > fieldcacheCacheType; + + /** The internal cache. Maps FileEntry to array of interpreted term values. **/ + //todo: make indexreader remove itself from here when the reader is shut + fieldcacheCacheType cache; + + /** See if an object is in the cache. */ + FieldCacheAuto* lookup (CL_NS(index)::IndexReader* reader, const TCHAR* field, int32_t type) ; + + /** See if a custom object is in the cache. */ + FieldCacheAuto* lookup (CL_NS(index)::IndexReader* reader, const TCHAR* field, SortComparatorSource* comparer); + + /** Put an object into the cache. */ + void store (CL_NS(index)::IndexReader* reader, const TCHAR* field, int32_t type, FieldCacheAuto* value); + + /** Put a custom object into the cache. */ + void store (CL_NS(index)::IndexReader* reader, const TCHAR* field, SortComparatorSource* comparer, FieldCacheAuto* value); + +public: + + // inherit javadocs + FieldCacheAuto* getInts (CL_NS(index)::IndexReader* reader, const TCHAR* field); + + // inherit javadocs + FieldCacheAuto* getFloats (CL_NS(index)::IndexReader* reader, const TCHAR* field); + + // inherit javadocs + FieldCacheAuto* getStrings (CL_NS(index)::IndexReader* reader, const TCHAR* field); + + // inherit javadocs + FieldCacheAuto* getStringIndex (CL_NS(index)::IndexReader* reader, const TCHAR* field); + + // inherit javadocs + FieldCacheAuto* getAuto (CL_NS(index)::IndexReader* reader, const TCHAR* field); + + // inherit javadocs + FieldCacheAuto* getCustom (CL_NS(index)::IndexReader* reader, const TCHAR* field, SortComparator* comparator); + + + /** + * Callback for when IndexReader closes. This causes + * any cache to be removed for the specified reader. + */ + static void closeCallback(CL_NS(index)::IndexReader* reader, void* fieldCacheImpl); +}; + + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/FieldDoc.h b/3rdparty/clucene/src/CLucene/search/FieldDoc.h new file mode 100644 index 000000000..6ce915acf --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/FieldDoc.h @@ -0,0 +1,70 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_FieldDoc_ +#define _lucene_search_FieldDoc_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "ScoreDoc.h" + +CL_NS_DEF(search) + +/** + * Expert: A ScoreDoc which also contains information about + * how to sort the referenced document. In addition to the + * document number and score, this object contains an array + * of values for the document from the field(s) used to sort. + * For example, if the sort criteria was to sort by fields + * "a", "b" then "c", the fields object array + * will have three elements, corresponding respectively to + * the term values for the document in fields "a", "b" and "c". + * The class of each element in the array will be either + * Integer, Float or String depending on the type of values + * in the terms of each field. + * + * @see ScoreDoc + * @see TopFieldDocs + */ +class FieldDoc: public ScoreDoc { +public: + + /** Expert: The values which are used to sort the referenced document. + * The order of these will match the original sort criteria given by a + * Sort object. Each Object will be either an Integer, Float or String, + * depending on the type of values in the terms of the original field. + * @see Sort + * @see Searchable#search(Query,Filter,int32_t,Sort) + */ + CL_NS(util)::Comparable** fields; + + /** Expert: Creates one of these objects with empty sort information. */ + FieldDoc (int32_t doc, qreal score): + ScoreDoc(doc,score) { + fields=NULL; + } + + /** Expert: Creates one of these objects with the given sort information. */ + FieldDoc (int32_t doc, qreal score, CL_NS(util)::Comparable** fields): + ScoreDoc(doc,score) + { + this->fields = fields; + } + + ~FieldDoc(){ + if ( fields != NULL ){ + for ( int i=0;fields[i]!=NULL;i++ ) + _CLDELETE(fields[i]); + _CLDELETE_ARRAY(fields); + } + } +}; + +CL_NS_END +#endif + diff --git a/3rdparty/clucene/src/CLucene/search/FieldDocSortedHitQueue.cpp b/3rdparty/clucene/src/CLucene/search/FieldDocSortedHitQueue.cpp new file mode 100644 index 000000000..0a5210903 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/FieldDocSortedHitQueue.cpp @@ -0,0 +1,171 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "FieldDocSortedHitQueue.h" + + +CL_NS_USE(util) +CL_NS_DEF(search) + + +FieldDoc::FieldDoc (int32_t doc, qreal score) +{ + this->scoreDoc.doc = doc; + this->scoreDoc.score = score; + fields=NULL; +} + +FieldDoc::FieldDoc (int32_t doc, qreal score, CL_NS(util)::Comparable** fields) +{ + this->scoreDoc.doc = doc; + this->scoreDoc.score = score; + this->fields = fields; +} + +FieldDoc::~FieldDoc(){ + if ( fields != NULL ){ + for ( int i=0;fields[i]!=NULL;i++ ) + _CLDELETE(fields[i]); + _CLDELETE_ARRAY(fields); + } +} + + + +FieldDocSortedHitQueue::FieldDocSortedHitQueue (SortField** fields, int32_t size) { + this->fields = fields; + _countsize(); + //this->collators = hasCollators (fields); + initialize (size,true); +} + +bool FieldDocSortedHitQueue::lessThan (FieldDoc* docA, FieldDoc* docB) { + int32_t n = fieldsLen; + int32_t c = 0; + qreal f1,f2,r1,r2; + int32_t i1,i2; + const TCHAR *s1, *s2; + + for (int32_t i=0; igetType(); + if (fields[i]->getReverse()) { + switch (type) { + case SortField::DOCSCORE: + r1 = __REINTERPRET_CAST(Compare::Float*, docA->fields[i])->getValue(); + r2 = __REINTERPRET_CAST(Compare::Float*, docB->fields[i])->getValue(); + if (r1 < r2) c = -1; + if (r1 > r2) c = 1; + break; + case SortField::DOC: + case SortField::INT: + i1 = __REINTERPRET_CAST(Compare::Int32*, docA->fields[i])->getValue(); + i2 = __REINTERPRET_CAST(Compare::Int32*, docB->fields[i])->getValue(); + if (i1 > i2) c = -1; + if (i1 < i2) c = 1; + break; + case SortField::STRING: + s1 = __REINTERPRET_CAST(Compare::TChar*, docA->fields[i])->getValue(); + s2 = __REINTERPRET_CAST(Compare::TChar*, docB->fields[i])->getValue(); + if (s2 == NULL) c = -1; // could be NULL if there are + else if (s1 == NULL) c = 1; // no terms in the given field + else c = _tcscmp(s2,s1); //else if (fields[i].getLocale() == NULL) { + + /*todo: collators not impl + } else { + c = collators[i].compare (s2, s1); + }*/ + break; + case SortField::FLOAT: + f1 = __REINTERPRET_CAST(Compare::Float*, docA->fields[i])->getValue(); + f2 = __REINTERPRET_CAST(Compare::Float*, docB->fields[i])->getValue(); + if (f1 > f2) c = -1; + if (f1 < f2) c = 1; + break; + case SortField::CUSTOM: + c = docB->fields[i]->compareTo (docA->fields[i]); + break; + case SortField::AUTO: + // we cannot handle this - even if we determine the type of object (qreal or + // Integer), we don't necessarily know how to compare them (both SCORE and + // qreal both contain floats, but are sorted opposite of each other). Before + // we get here, each AUTO should have been replaced with its actual value. + _CLTHROWA (CL_ERR_Runtime,"FieldDocSortedHitQueue cannot use an AUTO SortField"); + default: + _CLTHROWA (CL_ERR_Runtime, "invalid SortField type"); //todo: rich error... : "+type); + } + } else { + switch (type) { + case SortField::DOCSCORE: + r1 = __REINTERPRET_CAST(Compare::Float*, docA->fields[i])->getValue(); + r2 = __REINTERPRET_CAST(Compare::Float*, docB->fields[i])->getValue(); + if (r1 > r2) c = -1; + if (r1 < r2) c = 1; + break; + case SortField::DOC: + case SortField::INT: + i1 = __REINTERPRET_CAST(Compare::Int32*, docA->fields[i])->getValue(); + i2 = __REINTERPRET_CAST(Compare::Int32*, docB->fields[i])->getValue(); + if (i1 < i2) c = -1; + if (i1 > i2) c = 1; + break; + case SortField::STRING: + s1 = __REINTERPRET_CAST(Compare::TChar*, docA->fields[i])->getValue(); + s2 = __REINTERPRET_CAST(Compare::TChar*, docB->fields[i])->getValue(); + // NULL values need to be sorted first, because of how FieldCache.getStringIndex() + // works - in that routine, any documents without a value in the given field are + // put first. + if (s1 == NULL) c = -1; // could be NULL if there are + else if (s2 == NULL) c = 1; // no terms in the given field + else c = _tcscmp(s1,s2); //else if (fields[i].getLocale() == NULL) { + + /* todo: collators not implemented } else { + c = collators[i].compare (s1, s2); + }*/ + break; + case SortField::FLOAT: + f1 = __REINTERPRET_CAST(Compare::Float*, docA->fields[i])->getValue(); + f2 = __REINTERPRET_CAST(Compare::Float*, docB->fields[i])->getValue(); + if (f1 < f2) c = -1; + if (f1 > f2) c = 1; + break; + case SortField::CUSTOM: + c = docA->fields[i]->compareTo (docB->fields[i]); + break; + case SortField::AUTO: + // we cannot handle this - even if we determine the type of object (qreal or + // Integer), we don't necessarily know how to compare them (both SCORE and + // qreal both contain floats, but are sorted opposite of each other). Before + // we get here, each AUTO should have been replaced with its actual value. + _CLTHROWA (CL_ERR_Runtime,"FieldDocSortedHitQueue cannot use an AUTO SortField"); + default: + _CLTHROWA (CL_ERR_Runtime,"invalid SortField type"); //todo: rich error... : "+type); + } + } + } + return c > 0; +} + +void FieldDocSortedHitQueue::setFields (SortField** fields) { + SCOPED_LOCK_MUTEX(THIS_LOCK) + if (this->fields == NULL) { + this->fields = fields; + _countsize(); + //this->collators = hasCollators (fields); + }else if ( fields == NULL ) + this->fields = NULL; +} + +FieldDocSortedHitQueue::~FieldDocSortedHitQueue(){ + if ( fields != NULL ){ + for ( int i=0;fields[i]!=NULL;i++ ) + _CLDELETE(fields[i]); + _CLDELETE_ARRAY(fields); + } +} + +CL_NS_END + diff --git a/3rdparty/clucene/src/CLucene/search/FieldDocSortedHitQueue.h b/3rdparty/clucene/src/CLucene/search/FieldDocSortedHitQueue.h new file mode 100644 index 000000000..5a46b3b65 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/FieldDocSortedHitQueue.h @@ -0,0 +1,159 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_FieldDocSortedHitQueue_ +#define _lucene_search_FieldDocSortedHitQueue_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "Sort.h" +#include "CLucene/util/PriorityQueue.h" + +CL_NS_DEF(search) + +/** + * Expert: A ScoreDoc which also contains information about + * how to sort the referenced document. In addition to the + * document number and score, this object contains an array + * of values for the document from the field(s) used to sort. + * For example, if the sort criteria was to sort by fields + * "a", "b" then "c", the fields object array + * will have three elements, corresponding respectively to + * the term values for the document in fields "a", "b" and "c". + * The class of each element in the array will be either + * Integer, Float or String depending on the type of values + * in the terms of each field. + * + * @see ScoreDoc + * @see TopFieldDocs + */ +class FieldDoc: LUCENE_BASE { +public: + //FieldDoc did inherit from ScoreDoc, but now we make the scoredoc a member + struct ScoreDoc scoreDoc; + + /** Expert: The values which are used to sort the referenced document. + * The order of these will match the original sort criteria given by a + * Sort object. Each Object will be either an Integer, Float or String, + * depending on the type of values in the terms of the original field. + * @see Sort + * @see Searchable#search(Query,Filter,int32_t,Sort) + */ + CL_NS(util)::Comparable** fields; + + /** Expert: Creates one of these objects with empty sort information. */ + FieldDoc (int32_t doc, qreal score); + /** Expert: Creates one of these objects with the given sort information. */ + FieldDoc (int32_t doc, qreal score, CL_NS(util)::Comparable** fields); + ~FieldDoc(); +}; + +/** + * Expert: Collects sorted results from Searchable's and collates them. + * The elements put into this queue must be of type FieldDoc. + */ +class FieldDocSortedHitQueue: + public CL_NS(util)::PriorityQueue > +{ +private: + DEFINE_MUTEX(THIS_LOCK) + + // this cannot contain AUTO fields - any AUTO fields should + // have been resolved by the time this class is used. + SortField** fields; + int32_t fieldsLen; + + void _countsize(){ + fieldsLen=0; + while(fields[fieldsLen]!=NULL) + fieldsLen++; + } + + // used in the case where the fields are sorted by locale + // based strings + //todo: not implemented in clucene because locales has not been implemented + //Collator[] collators; //volatile + +public: + /** + * Creates a hit queue sorted by the given list of fields. + * @param fields Field names, in priority order (highest priority first). + * @param size The number of hits to retain. Must be greater than zero. + */ + FieldDocSortedHitQueue (SortField** fields, int32_t size); + ~FieldDocSortedHitQueue(); + + + /** + * Allows redefinition of sort fields if they are NULL. + * This is to handle the case using ParallelMultiSearcher where the + * original list contains AUTO and we don't know the actual sort + * type until the values come back. The fields can only be set once. + * This method is thread safe. + * @param fields + */ + void setFields (SortField** fields); + + /** Returns the fields being used to sort. */ + SortField** getFields() { + return fields; + } + + /** Returns an array of collators, possibly NULL. The collators + * correspond to any SortFields which were given a specific locale. + * @param fields Array of sort fields. + * @return Array, possibly NULL. + + private Collator[] hasCollators (SortField[] fields) { + if (fields == NULL) return NULL; + Collator[] ret = new Collator[fields.length]; + for (int32_t i=0; ia is less relevant than b. + * @param a FieldDoc + * @param b FieldDoc + * @return true if document a should be sorted after document b. + */ + bool lessThan (FieldDoc* docA, FieldDoc* docB); +}; + + +/** +* Expert: Returned by low-level sorted search implementations. +* +* @see Searchable#search(Query,Filter,int32_t,Sort) +*/ +class TopFieldDocs: public TopDocs { +public: + /// The fields which were used to sort results by. + SortField** fields; + + FieldDoc** fieldDocs; + + /** Creates one of these objects. + * @param totalHits Total number of hits for the query. + * @param fieldDocs The top hits for the query. + * @param scoreDocs The top hits for the query. + * @param scoreDocsLen Length of fieldDocs and scoreDocs + * @param fields The sort criteria used to find the top hits. + */ + TopFieldDocs (int32_t totalHits, FieldDoc** fieldDocs, int32_t scoreDocsLen, SortField** fields); + ~TopFieldDocs(); +}; + +CL_NS_END +#endif + diff --git a/3rdparty/clucene/src/CLucene/search/FieldSortedHitQueue.cpp b/3rdparty/clucene/src/CLucene/search/FieldSortedHitQueue.cpp new file mode 100644 index 000000000..04f45e931 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/FieldSortedHitQueue.cpp @@ -0,0 +1,212 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "FieldSortedHitQueue.h" +#include "FieldDocSortedHitQueue.h" +#include "Compare.h" + +CL_NS_USE(util) +CL_NS_USE(index) +CL_NS_DEF(search) + +FieldSortedHitQueue::hitqueueCacheType FieldSortedHitQueue::Comparators(false,true); + +FieldSortedHitQueue::FieldSortedHitQueue (IndexReader* reader, SortField** _fields, int32_t size): + fieldsLen(0), + maxscore(1.0f) +{ + while ( _fields[fieldsLen] != 0 ) + fieldsLen++; + + comparators = _CL_NEWARRAY(ScoreDocComparator*,fieldsLen+1); + SortField** tmp = _CL_NEWARRAY(SortField*,fieldsLen+1); + for (int32_t i=0; igetField(); + //todo: fields[i].getLocale(), not implemented + comparators[i] = getCachedComparator (reader, fieldname, _fields[i]->getType(), _fields[i]->getFactory()); + tmp[i] = _CLNEW SortField (fieldname, comparators[i]->sortType(), _fields[i]->getReverse()); + } + comparatorsLen = fieldsLen; + comparators[fieldsLen]=NULL; + tmp[fieldsLen] = NULL; + this->fields = tmp; + + initialize(size,true); +} + + +bool FieldSortedHitQueue::lessThan (FieldDoc* docA, FieldDoc* docB) { + // keep track of maximum score + if (docA->scoreDoc.score > maxscore) maxscore = docA->scoreDoc.score; + if (docB->scoreDoc.score > maxscore) maxscore = docB->scoreDoc.score; + + // run comparators + int32_t c = 0; + for ( int32_t i=0; c==0 && igetReverse()) ? comparators[i]->compare (&docB->scoreDoc, &docA->scoreDoc) : + comparators[i]->compare (&docA->scoreDoc, &docB->scoreDoc); + } + // avoid random sort order that could lead to duplicates (bug #31241): + if (c == 0) + return docA->scoreDoc.doc > docB->scoreDoc.doc; + return c > 0; +} + + +//static +ScoreDocComparator* FieldSortedHitQueue::comparatorString (IndexReader* reader, const TCHAR* field) { + //const TCHAR* field = CLStringIntern::intern(fieldname CL_FILELINE); + FieldCacheAuto* fa = FieldCache::DEFAULT->getStringIndex (reader, field); + //CLStringIntern::unintern(field); + + CND_PRECONDITION(fa->contentType==FieldCacheAuto::STRING_INDEX,"Content type is incorrect"); + fa->ownContents = false; + return _CLNEW ScoreDocComparators::String(fa->stringIndex, fa->contentLen); +} + +//static +ScoreDocComparator* FieldSortedHitQueue::comparatorInt (IndexReader* reader, const TCHAR* field){ + //const TCHAR* field = CLStringIntern::intern(fieldname CL_FILELINE); + FieldCacheAuto* fa = FieldCache::DEFAULT->getInts (reader, field); + //CLStringIntern::unintern(field); + + CND_PRECONDITION(fa->contentType==FieldCacheAuto::INT_ARRAY,"Content type is incorrect"); + return _CLNEW ScoreDocComparators::Int32(fa->intArray, fa->contentLen); + } + +//static + ScoreDocComparator* FieldSortedHitQueue::comparatorFloat (IndexReader* reader, const TCHAR* field) { + //const TCHAR* field = CLStringIntern::intern(fieldname CL_FILELINE); + FieldCacheAuto* fa = FieldCache::DEFAULT->getFloats (reader, field); + //CLStringIntern::unintern(field); + + CND_PRECONDITION(fa->contentType==FieldCacheAuto::FLOAT_ARRAY,"Content type is incorrect"); + return _CLNEW ScoreDocComparators::Float (fa->floatArray, fa->contentLen); + } +//static + ScoreDocComparator* FieldSortedHitQueue::comparatorAuto (IndexReader* reader, const TCHAR* field){ + //const TCHAR* field = CLStringIntern::intern(fieldname CL_FILELINE); + FieldCacheAuto* fa = FieldCache::DEFAULT->getAuto (reader, field); + //CLStringIntern::unintern(field); + + if (fa->contentType == FieldCacheAuto::STRING_INDEX ) { + return comparatorString (reader, field); + } else if (fa->contentType == FieldCacheAuto::INT_ARRAY) { + return comparatorInt (reader, field); + } else if (fa->contentType == FieldCacheAuto::FLOAT_ARRAY) { + return comparatorFloat (reader, field); + } else if (fa->contentType == FieldCacheAuto::STRING_ARRAY) { + return comparatorString (reader, field); + } else { + _CLTHROWA(CL_ERR_Runtime, "unknown data type in field"); //todo: rich error information: '"+field+"'"); + } + } + + + //todo: Locale locale, not implemented yet + ScoreDocComparator* FieldSortedHitQueue::getCachedComparator (IndexReader* reader, const TCHAR* fieldname, int32_t type, SortComparatorSource* factory){ + if (type == SortField::DOC) + return ScoreDocComparator::INDEXORDER; + if (type == SortField::DOCSCORE) + return ScoreDocComparator::RELEVANCE; + ScoreDocComparator* comparator = lookup (reader, fieldname, type, factory); + if (comparator == NULL) { + switch (type) { + case SortField::AUTO: + comparator = comparatorAuto (reader, fieldname); + break; + case SortField::INT: + comparator = comparatorInt (reader, fieldname); + break; + case SortField::FLOAT: + comparator = comparatorFloat (reader, fieldname); + break; + case SortField::STRING: + //if (locale != NULL) + // comparator = comparatorStringLocale (reader, fieldname, locale); + //else + comparator = comparatorString (reader, fieldname); + break; + case SortField::CUSTOM: + comparator = factory->newComparator (reader, fieldname); + break; + default: + _CLTHROWA(CL_ERR_Runtime,"unknown field type"); + //todo: extend error + //throw _CLNEW RuntimeException ("unknown field type: "+type); + } + store (reader, fieldname, type, factory, comparator); + } + return comparator; + } + + + FieldDoc* FieldSortedHitQueue::fillFields (FieldDoc* doc) const{ + int32_t n = comparatorsLen; + Comparable** fields = _CL_NEWARRAY(Comparable*,n+1); + for (int32_t i=0; isortValue(&doc->scoreDoc); + fields[n]=NULL; + doc->fields = fields; + if (maxscore > 1.0f) + doc->scoreDoc.score /= maxscore; // normalize scores + return doc; + } + + ScoreDocComparator* FieldSortedHitQueue::lookup (IndexReader* reader, const TCHAR* field, int32_t type, SortComparatorSource* factory) { + ScoreDocComparator* sdc = NULL; + FieldCacheImpl::FileEntry* entry = (factory != NULL) + ? _CLNEW FieldCacheImpl::FileEntry (field, factory) + : _CLNEW FieldCacheImpl::FileEntry (field, type); + + { + SCOPED_LOCK_MUTEX(Comparators.THIS_LOCK) + hitqueueCacheReaderType* readerCache = Comparators.get(reader); + if (readerCache == NULL){ + _CLDELETE(entry); + return NULL; + } + + sdc = readerCache->get (entry); + _CLDELETE(entry); + } + return sdc; + } + + void FieldSortedHitQueue::closeCallback(CL_NS(index)::IndexReader* reader, void*){ + SCOPED_LOCK_MUTEX(Comparators.THIS_LOCK) + Comparators.remove(reader); + } + + //static + void FieldSortedHitQueue::store (IndexReader* reader, const TCHAR* field, int32_t type, SortComparatorSource* factory, ScoreDocComparator* value) { + FieldCacheImpl::FileEntry* entry = (factory != NULL) + ? _CLNEW FieldCacheImpl::FileEntry (field, factory) + : _CLNEW FieldCacheImpl::FileEntry (field, type); + + { + SCOPED_LOCK_MUTEX(Comparators.THIS_LOCK) + hitqueueCacheReaderType* readerCache = Comparators.get(reader); + if (readerCache == NULL) { + readerCache = _CLNEW hitqueueCacheReaderType(true); + Comparators.put(reader,readerCache); + reader->addCloseCallback(FieldSortedHitQueue::closeCallback,NULL); + } + readerCache->put (entry, value); + //return NULL; //supposed to return previous value... + } + } + +FieldSortedHitQueue::~FieldSortedHitQueue(){ + _CLDELETE_ARRAY(comparators); + if ( fields != NULL ){ + for ( int i=0;fields[i]!=NULL;i++ ) + _CLDELETE(fields[i]); + _CLDELETE_ARRAY(fields); + } +} +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/FieldSortedHitQueue.h b/3rdparty/clucene/src/CLucene/search/FieldSortedHitQueue.h new file mode 100644 index 000000000..d7b16ce9e --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/FieldSortedHitQueue.h @@ -0,0 +1,216 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_FieldSortedHitQueue_ +#define _lucene_search_FieldSortedHitQueue_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "FieldCache.h" +#include "Sort.h" +#include "FieldDocSortedHitQueue.h" +#include "SearchHeader.h" +#include "FieldCacheImpl.h" +#include "CLucene/util/PriorityQueue.h" + +CL_NS_DEF(search) + + +/** + * Expert: A hit queue for sorting by hits by terms in more than one field. + * Uses FieldCache.DEFAULT for maintaining internal term lookup tables. + * + * @see Searchable#search(Query,Filter,int32_t,Sort) + * @see FieldCache + */ +class FieldSortedHitQueue: public CL_NS(util)::PriorityQueue > { + + ///the type that is stored in the field cache. can't use a typedef because + ///the decorated name would become too long + class hitqueueCacheReaderType: public CL_NS(util)::CLHashMap, + CL_NS(util)::Deletor::Object >{ + + public: + hitqueueCacheReaderType(bool deleteValue){ + setDeleteKey(true); + setDeleteValue(deleteValue); + } + ~hitqueueCacheReaderType(){ + clear(); + } + + }; + +public: //todo: remove this and below after close callback is implemented + //note: typename gets too long if using cacheReaderType as a typename + typedef CL_NS(util)::CLHashMap, + CL_NS(util)::Equals::Void, + CL_NS(util)::Deletor::Object, + CL_NS(util)::Deletor::Object > hitqueueCacheType; + + /** Internal cache of comparators. Similar to FieldCache, only + * caches comparators instead of term values. + */ + static hitqueueCacheType Comparators; +private: + + /** Returns a comparator if it is in the cache.*/ + static ScoreDocComparator* lookup (CL_NS(index)::IndexReader* reader, const TCHAR* field, int32_t type, SortComparatorSource* factory); + + /** Stores a comparator into the cache. + returns the valid ScoreDocComparator. + */ + static void store (CL_NS(index)::IndexReader* reader, const TCHAR* field, int32_t type, SortComparatorSource* factory, ScoreDocComparator* value); + + + //todo: Locale locale, not implemented yet + static ScoreDocComparator* getCachedComparator (CL_NS(index)::IndexReader* reader, + const TCHAR* fieldname, int32_t type, SortComparatorSource* factory); + + + /** + * Returns a comparator for sorting hits according to a field containing integers. + * @param reader Index to use. + * @param fieldname Field containg integer values. + * @return Comparator for sorting hits. + * @throws IOException If an error occurs reading the index. + */ + static ScoreDocComparator* comparatorInt (CL_NS(index)::IndexReader* reader, const TCHAR* fieldname); + + /** + * Returns a comparator for sorting hits according to a field containing floats. + * @param reader Index to use. + * @param fieldname Field containg float values. + * @return Comparator for sorting hits. + * @throws IOException If an error occurs reading the index. + */ + static ScoreDocComparator* comparatorFloat (CL_NS(index)::IndexReader* reader, const TCHAR* fieldname); + + /** + * Returns a comparator for sorting hits according to a field containing strings. + * @param reader Index to use. + * @param fieldname Field containg string values. + * @return Comparator for sorting hits. + * @throws IOException If an error occurs reading the index. + */ + static ScoreDocComparator* comparatorString (CL_NS(index)::IndexReader* reader, const TCHAR* fieldname); + + + //todo: + /** + * Returns a comparator for sorting hits according to a field containing strings. + * @param reader Index to use. + * @param fieldname Field containg string values. + * @return Comparator for sorting hits. + * @throws IOException If an error occurs reading the index. + + static ScoreDocComparator* comparatorStringLocale (IndexReader* reader, TCHAR* fieldname, Locale locale){ + Collator collator = Collator.getInstance (locale); + TCHAR* field = fieldname.intern(); + TCHAR** index = FieldCache.DEFAULT.getStrings (reader, field); + return _CLNEW ScoreDocComparator() { + + public int32_t compare (ScoreDoc i, ScoreDoc j) { + return collator.compare (index[i.doc], index[j.doc]); + } + + public Comparable sortValue (ScoreDoc i) { + return index[i.doc]; + } + + public int32_t sortType() { + return SortField.STRING; + } + }; + }*/ + + /** + * Returns a comparator for sorting hits according to values in the given field. + * The terms in the field are looked at to determine whether they contain integers, + * floats or strings. Once the type is determined, one of the other static methods + * in this class is called to get the comparator. + * @param reader Index to use. + * @param fieldname Field containg values. + * @return Comparator for sorting hits. + * @throws IOException If an error occurs reading the index. + */ + static ScoreDocComparator* comparatorAuto (CL_NS(index)::IndexReader* reader, const TCHAR* fieldname); + + +protected: + /** Stores a comparator corresponding to each field being sorted by */ + ScoreDocComparator** comparators; + int32_t comparatorsLen; + + /** Stores the sort criteria being used. */ + SortField** fields; + int32_t fieldsLen; + + /** Stores the maximum score value encountered, for normalizing. + * we only care about scores greater than 1.0 - if all the scores + * are less than 1.0, we don't have to normalize. */ + qreal maxscore; + + /** + * Returns whether a is less relevant than b. + * @param a ScoreDoc + * @param b ScoreDoc + * @return true if document a should be sorted after document b. + */ + bool lessThan (FieldDoc* docA, FieldDoc* docB); +public: + + /** + * Creates a hit queue sorted by the given list of fields. + * @param reader Index to use. + * @param fields Field names, in priority order (highest priority first). Cannot be null or empty. + * @param size The number of hits to retain. Must be greater than zero. + * @throws IOException + */ + FieldSortedHitQueue (CL_NS(index)::IndexReader* reader, SortField** fields, int32_t size); + + ~FieldSortedHitQueue(); + + /** + * Callback for when IndexReader closes. This causes + * any Comparators to be removed for the specified reader. + */ + static void closeCallback(CL_NS(index)::IndexReader* reader, void* param); + + /** + * Given a FieldDoc object, stores the values used + * to sort the given document. These values are not the raw + * values out of the index, but the internal representation + * of them. This is so the given search hit can be collated + * by a MultiSearcher with other search hits. + * @param doc The FieldDoc to store sort values into. + * @return The same FieldDoc passed in. + * @see Searchable#search(Query,Filter,int32_t,Sort) + */ + FieldDoc* fillFields (FieldDoc* doc) const; + + void setFields (SortField** fields){ + this->fields = fields; + } + + /** Returns the SortFields being used by this hit queue. */ + SortField** getFields() { + return fields; + } +}; + + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/Filter.h b/3rdparty/clucene/src/CLucene/search/Filter.h new file mode 100644 index 000000000..309c5a9d6 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/Filter.h @@ -0,0 +1,46 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_Filter_ +#define _lucene_search_Filter_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/index/IndexReader.h" +#include "CLucene/util/BitSet.h" + +CL_NS_DEF(search) + // Abstract base class providing a mechanism to restrict searches to a subset + // of an index. + class Filter: LUCENE_BASE { + public: + virtual ~Filter(){ + } + + virtual Filter* clone() const = 0; + + /** + * Returns a BitSet with true for documents which should be permitted in + * search results, and false for those that should not. + * MEMORY: read shouldDeleteBitSet + */ + virtual CL_NS(util)::BitSet* bits(CL_NS(index)::IndexReader* reader)=0; + + /** + * Because of the problem of cached bitsets with the CachingWrapperFilter, + * CLucene has no way of knowing whether to delete the bitset returned from bits(). + * To properly clean memory from bits(), pass the bitset to this function. The + * Filter should be deleted if this function returns true. + */ + virtual bool shouldDeleteBitSet(const CL_NS(util)::BitSet* bs) const{ return true; } + + //Creates a user-readable version of this query and returns it as as string + virtual TCHAR* toString()=0; + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/FilteredTermEnum.cpp b/3rdparty/clucene/src/CLucene/search/FilteredTermEnum.cpp new file mode 100644 index 000000000..f90ceeaaf --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/FilteredTermEnum.cpp @@ -0,0 +1,136 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" + +#include "FilteredTermEnum.h" + +CL_NS_USE(index) +CL_NS_DEF(search) + + + FilteredTermEnum::FilteredTermEnum(){ + //Func - Constructor + //Pre - true + //Post - Instance has been created + + currentTerm = NULL; + actualEnum = NULL; + } + + FilteredTermEnum::~FilteredTermEnum() { + //Func - Destructor + //Pre - true + //Post - The instance has been destroyed + + close(); + } + + int32_t FilteredTermEnum::docFreq() const { + //Func - Returns the docFreq of the current Term in the enumeration. + //Pre - next() must have been called at least once + //Post - if actualEnum is NULL result is -1 otherwise the frequencey is returned + + if (actualEnum == NULL){ + return -1; + } + return actualEnum->docFreq(); + } + + bool FilteredTermEnum::next() { + //Func - Increments the enumeration to the next element. + //Pre - true + //Post - Returns True if the enumeration has been moved to the next element otherwise false + + //The actual enumerator is not initialized! + if (actualEnum == NULL){ + return false; + } + + //Finalize the currentTerm and reset it to NULL + _CLDECDELETE( currentTerm ); + + //Iterate through the enumeration + while (currentTerm == NULL) { + if (endEnum()) + return false; + if (actualEnum->next()) { + //Order term not to return reference ownership here. */ + Term* term = actualEnum->term(false); + //Compare the retrieved term + if (termCompare(term)){ + //Matched so finalize the current + _CLDECDELETE(currentTerm); + //Get a reference to the matched term + currentTerm = _CL_POINTER(term); + return true; + } + }else + return false; + } + _CLDECDELETE(currentTerm); + currentTerm = NULL; + + return false; + } + + Term* FilteredTermEnum::term() { + //Func - Returns the current Term in the enumeration. + //Pre - next() must have been called at least once + // pointer is true or false + //Post - if pre(pointer) is true the reference counter of currentTerm is increased + // and current Term is returned otherwise currentTerm is only returned + + return _CL_POINTER(currentTerm); + } + Term* FilteredTermEnum::term(bool pointer) { + if ( pointer ) + return _CL_POINTER(currentTerm); + else + return currentTerm; + } + + void FilteredTermEnum::close(){ + //Func - Closes the enumeration to further activity, freeing resources. + //Pre - true + //Post - The Enumeration has been closed + + //Check if actualEnum is valid + if (actualEnum){ + //Close the enumeration + actualEnum->close(); + } + + //Destroy the enumeration + _CLDELETE(actualEnum); + + //Destroy currentTerm + _CLDECDELETE(currentTerm); + } + + void FilteredTermEnum::setEnum(TermEnum* actualEnum) { + //Func - Sets the actual Enumeration + //Pre - actualEnum != NULL + //Post - The instance has been created + + CND_PRECONDITION(actualEnum != NULL,"actualEnum is NULL"); + + _CLDELETE(this->actualEnum); + + this->actualEnum = actualEnum; + + // Find the first term that matches + //Ordered term not to return reference ownership here. + Term* term = actualEnum->term(false); + if (term != NULL && termCompare(term)){ + _CLDECDELETE(currentTerm); + currentTerm = _CL_POINTER(term); + }else{ + next(); + } + } + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/FilteredTermEnum.h b/3rdparty/clucene/src/CLucene/search/FilteredTermEnum.h new file mode 100644 index 000000000..035ae384e --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/FilteredTermEnum.h @@ -0,0 +1,61 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_FilteredTermEnum_ +#define _lucene_search_FilteredTermEnum_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/index/Term.h" +#include "CLucene/index/Terms.h" + +CL_NS_DEF(search) + //FilteredTermEnum is an abstract class for enumerating a subset of all terms. + // + //Term enumerations are always ordered by term->compareTo(). Each term in + //the enumeration is greater than all that precede it. + + class FilteredTermEnum: public CL_NS(index)::TermEnum { + public: + //Constructor + FilteredTermEnum(); + //Destructor + virtual ~FilteredTermEnum(); + + //Equality measure on the term + virtual qreal difference() = 0; + + //Returns the docFreq of the current Term in the enumeration. + int32_t docFreq() const ; + + //Increments the enumeration to the next element + bool next() ; + + //Returns a pointer to the current Term in the enumeration. + CL_NS(index)::Term* term(); + CL_NS(index)::Term* term(bool pointer); + + //Closes the enumeration to further activity, freeing resources. + void close(); + + protected: + //Equality compare on the term */ + virtual bool termCompare(CL_NS(index)::Term* term) = 0; + + //Indiciates the end of the enumeration has been reached + virtual bool endEnum() = 0; + + void setEnum(CL_NS(index)::TermEnum* actualEnum) ; + + private: + CL_NS(index)::Term* currentTerm; + CL_NS(index)::TermEnum* actualEnum; + + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/FuzzyQuery.cpp b/3rdparty/clucene/src/CLucene/search/FuzzyQuery.cpp new file mode 100644 index 000000000..e95d48da3 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/FuzzyQuery.cpp @@ -0,0 +1,357 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "FuzzyQuery.h" + +CL_NS_USE(index) +CL_NS_USE(util) +CL_NS_DEF(search) + + /** + * Constructor for enumeration of all terms from specified reader which share a prefix of + * length prefixLength with term and which have a fuzzy similarity > + * minSimilarity. + * + * @param reader Delivers terms. + * @param term Pattern term. + * @param minSimilarity Minimum required similarity for terms from the reader. Default value is 0.5f. + * @param prefixLength Length of required common prefix. Default value is 0. + * @throws IOException + */ + FuzzyTermEnum::FuzzyTermEnum(const IndexReader* reader, Term* term, qreal minSimilarity, size_t prefixLength): + distance(0), + _endEnum(false), + prefix(LUCENE_BLANK_STRING), + prefixLength(0), + minimumSimilarity(minSimilarity) + { + //Func - Constructor + //Pre - reader contains a valid reference to an IndexReader + // term != NULL + //Post - The instance has been created + + CND_PRECONDITION(term != NULL,"term is NULL"); + + scale_factor = 1.0f / (1.0f - minimumSimilarity); + searchTerm = _CL_POINTER(term); + + text = STRDUP_TtoT(term->text()); + textLen = term->textLength(); + + + //Initialize e to NULL + e = NULL; + eWidth = 0; + eHeight = 0; + + if(prefixLength > 0 && prefixLength < textLen){ + this->prefixLength = prefixLength; + + prefix = _CL_NEWARRAY(TCHAR,prefixLength+1); + _tcsncpy(prefix,text,prefixLength); + prefix[prefixLength]='\0'; + + textLen = prefixLength; + text[textLen]='\0'; + } + + + //Set the enumeration + Term* trm = _CLNEW Term(term, prefix); + setEnum(reader->terms(trm)); + _CLDECDELETE(trm); + } + + FuzzyTermEnum::~FuzzyTermEnum(){ + //Func - Destructor + //Pre - true + //Post - FuzzyTermEnum has been destroyed + + //Close the enumeration + close(); + } + + bool FuzzyTermEnum::endEnum() { + //Func - Returns the fact if the current term in the enumeration has reached the end + //Pre - true + //Post - The boolean value of endEnum has been returned + + return _endEnum; + } + + void FuzzyTermEnum::close(){ + //Func - Close the enumeration + //Pre - true + //Post - The enumeration has been closed + + FilteredTermEnum::close(); + + //Finalize the searchTerm + _CLDECDELETE(searchTerm); + //Destroy e + _CLDELETE_ARRAY(e); + + _CLDELETE_CARRAY(text); + + if ( prefix != LUCENE_BLANK_STRING ) + _CLDELETE_CARRAY(prefix); + } + + bool FuzzyTermEnum::termCompare(Term* term) { + //Func - Compares term with the searchTerm using the Levenshtein distance. + //Pre - term is NULL or term points to a Term + //Post - if pre(term) is NULL then false is returned otherwise + // if the distance of the current term in the enumeration is bigger than the FUZZY_THRESHOLD + // then true is returned + + if (term == NULL){ + return false; //Note that endEnum is not set to true! + } + + const TCHAR* termText = term->text(); + size_t termTextLen = term->textLength(); + + //Check if the field name of searchTerm of term match + //(we can use == because fields are interned) + if ( searchTerm->field() == term->field() && + (prefixLength==0 || _tcsncmp(termText,prefix,prefixLength)==0 )) { + + const TCHAR* target = termText+prefixLength; + size_t targetLen = termTextLen-prefixLength; + + //Calculate the Levenshtein distance + int32_t dist = editDistance(text, target, textLen, targetLen); + distance = 1 - ((qreal)dist / (qreal)min(textLen, targetLen)); + return (distance > minimumSimilarity); + } + _endEnum = true; + return false; + } + + qreal FuzzyTermEnum::difference() { + //Func - Returns the difference between the distance and the fuzzy threshold + // multiplied by the scale factor + //Pre - true + //Post - The difference is returned + + return (qreal)((distance - minimumSimilarity) * scale_factor ); + } + + + /** Finds and returns the smallest of three integers + precondition: Must define int32_t __t for temporary storage and result + */ + #define min3(a, b, c) __t = (a < b) ? a : b; __t = (__t < c) ? __t : c; + + int32_t FuzzyTermEnum::editDistance(const TCHAR* s, const TCHAR* t, const int32_t n, const int32_t m) { + //Func - Calculates the Levenshtein distance also known as edit distance is a measure of similiarity + // between two strings where the distance is measured as the number of character + // deletions, insertions or substitutions required to transform one string to + // the other string. + //Pre - s != NULL and contains the source string + // t != NULL and contains the target string + // n >= 0 and contains the length of the source string + // m >= 0 and containts the length of th target string + //Post - The distance has been returned + + CND_PRECONDITION(s != NULL, "s is NULL"); + CND_PRECONDITION(t != NULL, "t is NULL"); + CND_PRECONDITION(n >= 0," n is a negative number"); + CND_PRECONDITION(n >= 0," n is a negative number"); + + int32_t i; // iterates through s + int32_t j; // iterates through t + TCHAR s_i; // ith character of s + + if (n == 0) + return m; + if (m == 0) + return n; + + //Check if the array must be reallocated because it is too small or does not exist + if (e == NULL || eWidth <= n || eHeight <= m) { + //Delete e if possible + _CLDELETE_ARRAY(e); + //resize e + eWidth = max(eWidth, n+1); + eHeight = max(eHeight, m+1); + e = _CL_NEWARRAY(int32_t,eWidth*eHeight); + } + + CND_CONDITION(e != NULL,"e is NULL"); + + // init matrix e + for (i = 0; i <= n; i++){ + e[i + (0*eWidth)] = i; + } + for (j = 0; j <= m; j++){ + e[0 + (j*eWidth)] = j; + } + + int32_t __t; //temporary variable for min3 + + // start computing edit distance + for (i = 1; i <= n; i++) { + s_i = s[i - 1]; + for (j = 1; j <= m; j++) { + if (s_i != t[j-1]){ + min3(e[i + (j*eWidth) - 1], e[i + ((j-1)*eWidth)], e[i + ((j-1)*eWidth)-1]); + e[i + (j*eWidth)] = __t+1; + }else{ + min3(e[i + (j*eWidth) -1]+1, e[i + ((j-1)*eWidth)]+1, e[i + ((j-1)*eWidth)-1]); + e[i + (j*eWidth)] = __t; + } + } + } + + // we got the result! + return e[n + ((m)*eWidth)]; + } + + + /** + * Create a new FuzzyQuery that will match terms with a similarity + * of at least minimumSimilarity to term. + * If a prefixLength > 0 is specified, a common prefix + * of that length is also required. + * + * @param term the term to search for + * @param minimumSimilarity a value between 0 and 1 to set the required similarity + * between the query term and the matching terms. For example, for a + * minimumSimilarity of 0.5 a term of the same length + * as the query term is considered similar to the query term if the edit distance + * between both terms is less than length(term)*0.5 + * @param prefixLength length of common (non-fuzzy) prefix + * @throws IllegalArgumentException if minimumSimilarity is > 1 or < 0 + * or if prefixLength < 0 or > term.text().length(). + */ + FuzzyQuery::FuzzyQuery(Term* term, qreal minimumSimilarity, size_t prefixLength): + MultiTermQuery(term) + { + //Func - Constructor + //Pre - term != NULL + //Post - The instance has been created + + CND_PRECONDITION(term != NULL,"term is NULL"); + + if (minimumSimilarity > 1.0f) + _CLTHROWA(CL_ERR_IllegalArgument,"minimumSimilarity > 1"); + else if (minimumSimilarity < 0.0f) + _CLTHROWA(CL_ERR_IllegalArgument,"minimumSimilarity < 0"); + + this->minimumSimilarity = minimumSimilarity; + + if(prefixLength >= term->textLength()) + _CLTHROWA(CL_ERR_IllegalArgument,"prefixLength >= term.textLength()"); + this->prefixLength = prefixLength; + + } + + + qreal FuzzyQuery::defaultMinSimilarity = 0.5f; + + FuzzyQuery::~FuzzyQuery(){ + //Func - Destructor + //Pre - true + //Post - Instance has been destroyed + } + + TCHAR* FuzzyQuery::toString(const TCHAR* field) const{ + //Func - Returns the query string + //Pre - field != NULL + //Post - The query string has been returned + + CND_PRECONDITION(field != NULL,"field is NULL"); + + StringBuffer buffer; + const TCHAR* b = MultiTermQuery::toString(field); + + buffer.append ( b ); + _CLDELETE_CARRAY(b); + buffer.append( _T("~") ); + + buffer.appendFloat(minimumSimilarity,1); + + return buffer.toString(); + } + + const TCHAR* FuzzyQuery::getQueryName() const{ + //Func - Returns the name of the query + //Pre - true + //post - The string FuzzyQuery has been returned + + return getClassName(); + } + const TCHAR* FuzzyQuery::getClassName(){ + //Func - Returns the name of the query + //Pre - true + //post - The string FuzzyQuery has been returned + + return _T("FuzzyQuery"); + } + + + /** + * Returns the minimum similarity that is required for this query to match. + * @return float value between 0.0 and 1.0 + */ + qreal FuzzyQuery::getMinSimilarity() const { + return minimumSimilarity; + } + + FuzzyQuery::FuzzyQuery(const FuzzyQuery& clone): + MultiTermQuery(clone) + { + this->minimumSimilarity = clone.getMinSimilarity(); + this->prefixLength = clone.getPrefixLength(); + + //if(prefixLength < 0) + // _CLTHROWA(CL_ERR_IllegalArgument,"prefixLength < 0"); + //else + if(prefixLength >= clone.getTerm()->textLength()) + _CLTHROWA(CL_ERR_IllegalArgument,"prefixLength >= term.textLength()"); + + } + + Query* FuzzyQuery::clone() const{ + return _CLNEW FuzzyQuery(*this); + } + size_t FuzzyQuery::hashCode() const{ + //todo: we should give the query a seeding value... but + //need to do it for all hascode functions + size_t val = Similarity::floatToByte(getBoost()) ^ getTerm()->hashCode(); + val ^= Similarity::floatToByte(this->getMinSimilarity()); + val ^= this->getPrefixLength(); + return val; + } + bool FuzzyQuery::equals(Query* other) const{ + if (!(other->instanceOf(FuzzyQuery::getClassName()))) + return false; + + FuzzyQuery* fq = (FuzzyQuery*)other; + return (this->getBoost() == fq->getBoost()) + && this->getMinSimilarity() == fq->getMinSimilarity() + && this->getPrefixLength() == fq->getPrefixLength() + && getTerm()->equals(fq->getTerm()); + } + + /** + * Returns the prefix length, i.e. the number of characters at the start + * of a term that must be identical (not fuzzy) to the query term if the query + * is to match that term. + */ + size_t FuzzyQuery::getPrefixLength() const { + return prefixLength; + } + + FilteredTermEnum* FuzzyQuery::getEnum(IndexReader* reader){ + Term* term = getTerm(false); + FuzzyTermEnum* ret = _CLNEW FuzzyTermEnum(reader, term, minimumSimilarity, prefixLength); + return ret; + } + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/FuzzyQuery.h b/3rdparty/clucene/src/CLucene/search/FuzzyQuery.h new file mode 100644 index 000000000..e58637bb9 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/FuzzyQuery.h @@ -0,0 +1,156 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_FuzzyQuery_ +#define _lucene_search_FuzzyQuery_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/index/IndexReader.h" +#include "CLucene/index/Term.h" +#include "MultiTermQuery.h" + + +CL_NS_DEF(search) + + // class FuzzyQuery implements the fuzzy search query + class FuzzyQuery: public MultiTermQuery { + private: + qreal minimumSimilarity; + size_t prefixLength; + protected: + FuzzyQuery(const FuzzyQuery& clone); + public: + static qreal defaultMinSimilarity; + + /** + * Create a new FuzzyQuery that will match terms with a similarity + * of at least minimumSimilarity to term. + * If a prefixLength > 0 is specified, a common prefix + * of that length is also required. + * + * @param term the term to search for + * @param minimumSimilarity a value between 0 and 1 to set the required similarity + * between the query term and the matching terms. For example, for a + * minimumSimilarity of 0.5 a term of the same length + * as the query term is considered similar to the query term if the edit distance + * between both terms is less than length(term)*0.5 + * @param prefixLength length of common (non-fuzzy) prefix + * @throws IllegalArgumentException if minimumSimilarity is > 1 or < 0 + * or if prefixLength < 0 or > term.text().length(). + */ + FuzzyQuery(CL_NS(index)::Term* term, qreal minimumSimilarity=defaultMinSimilarity, size_t prefixLength=0); + //Destructor + ~FuzzyQuery(); + + TCHAR* toString(const TCHAR* field) const; + + //Returns the name "FuzzyQuery" + static const TCHAR* getClassName(); + const TCHAR* getQueryName() const; + + Query* clone() const; + bool equals(Query * other) const; + size_t hashCode() const; + + /** + * Returns the minimum similarity that is required for this query to match. + * @return float value between 0.0 and 1.0 + */ + qreal getMinSimilarity() const; + + /** + * Returns the prefix length, i.e. the number of characters at the start + * of a term that must be identical (not fuzzy) to the query term if the query + * is to match that term. + */ + size_t getPrefixLength() const; + + protected: + FilteredTermEnum* getEnum(CL_NS(index)::IndexReader* reader); + }; + + /** FuzzyTermEnum is a subclass of FilteredTermEnum for enumerating all + * terms that are similiar to the specified filter term. + * + * Term enumerations are always ordered by Term.compareTo(). Each term in + * the enumeration is greater than all that precede it. + */ + class FuzzyTermEnum: public FilteredTermEnum { + private: + qreal distance; + bool _endEnum; + + CL_NS(index)::Term* searchTerm; + TCHAR* text; + size_t textLen; + TCHAR* prefix; + size_t prefixLength; + qreal minimumSimilarity; + double scale_factor; + + + /** + * This static array saves us from the time required to create a new array + * everytime editDistance is called. + */ + int32_t* e; + int32_t eWidth; + int32_t eHeight; + + /****************************** + * Compute Levenshtein distance + ******************************/ + + /** + Levenshtein distance also known as edit distance is a measure of similiarity + between two strings where the distance is measured as the number of character + deletions, insertions or substitutions required to transform one string to + the other string. +

This method takes in four parameters; two strings and their respective + lengths to compute the Levenshtein distance between the two strings. + The result is returned as an integer. + */ + int32_t editDistance(const TCHAR* s, const TCHAR* t, const int32_t n, const int32_t m) ; + + protected: + /** + The termCompare method in FuzzyTermEnum uses Levenshtein distance to + calculate the distance between the given term and the comparing term. + */ + bool termCompare(CL_NS(index)::Term* term) ; + + ///Returns the fact if the current term in the enumeration has reached the end + bool endEnum(); + public: + + /** + * Empty prefix and minSimilarity of 0.5f are used. + * + * @param reader + * @param term + * @throws IOException + * @see #FuzzyTermEnum(IndexReader, Term, qreal, int32_t) + */ + FuzzyTermEnum(const CL_NS(index)::IndexReader* reader, CL_NS(index)::Term* term, qreal minSimilarity=FuzzyQuery::defaultMinSimilarity, size_t prefixLength=0); + /** Destructor */ + ~FuzzyTermEnum(); + /** Close the enumeration */ + void close(); + + /** Returns the difference between the distance and the fuzzy threshold + * multiplied by the scale factor + */ + qreal difference(); + + + const char* getObjectName(){ return FuzzyTermEnum::getClassName(); } + static const char* getClassName(){ return "FuzzyTermEnum"; } + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/HitQueue.cpp b/3rdparty/clucene/src/CLucene/search/HitQueue.cpp new file mode 100644 index 000000000..c9aecc6b4 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/HitQueue.cpp @@ -0,0 +1,107 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "HitQueue.h" + +CL_NS_DEF(search) + +void HitQueue::upHeap(){ + size_t i = _size; + ScoreDoc node = heap[i]; // save bottom node (WAS object) + int32_t j = ((uint32_t)i) >> 1; + while (j > 0 && lessThan(node,heap[j])) { + heap[i] = heap[j]; // shift parents down + i = j; + j = ((uint32_t)j) >> 1; + } + heap[i] = node; // install saved node +} +void HitQueue::downHeap(){ + size_t i = 1; + ScoreDoc node = heap[i]; // save top node + size_t j = i << 1; // find smaller child + size_t k = j + 1; + if (k <= _size && lessThan(heap[k], heap[j])) { + j = k; + } + while (j <= _size && lessThan(heap[j],node)) { + heap[i] = heap[j]; // shift up child + i = j; + j = i << 1; + k = j + 1; + if (k <= _size && lessThan(heap[k], heap[j])) { + j = k; + } + } + heap[i] = node; // install saved node +} + +void HitQueue::adjustTop(){ + downHeap(); +} +size_t HitQueue::size(){ + return _size; +} + +struct ScoreDoc& HitQueue::top(){ + if ( _size == 0 ) + _CLTHROWA(CL_ERR_IndexOutOfBounds, "Attempted to access empty hitqueue::top"); + return heap[1]; +} + +void HitQueue::put(struct ScoreDoc& element){ + if ( _size>=maxSize ) + _CLTHROWA(CL_ERR_IndexOutOfBounds,"add is out of bounds"); + + _size++; + heap[_size] = element; + upHeap(); +} + +ScoreDoc HitQueue::pop(){ + if (_size > 0) { + ScoreDoc result = heap[1]; // save first value + heap[1] = heap[_size]; // move last to first + + _size--; + downHeap(); // adjust heap + return result; + } else + _CLTHROWA(CL_ERR_IndexOutOfBounds, "Attempted to access empty hitqueue::top"); +} + +bool HitQueue::insert(struct ScoreDoc& element){ + if(_size < maxSize){ + put(element); + return true; + }else if(_size > 0 && !lessThan(element, heap[1])){ + heap[1] = element; + adjustTop(); + return true; + }else + return false; +} + +HitQueue::HitQueue(const int32_t maxSize){ + _size = 0; + this->maxSize = maxSize; + int32_t heapSize = maxSize + 1; + heap = _CL_NEWARRAY(ScoreDoc,heapSize); +} +HitQueue::~HitQueue(){ + _CLDELETE_ARRAY(heap); +} + +bool HitQueue::lessThan(struct ScoreDoc& hitA, struct ScoreDoc& hitB){ + if (hitA.score == hitB.score) + return hitA.doc > hitB.doc; + else + return hitA.score < hitB.score; +} + + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/HitQueue.h b/3rdparty/clucene/src/CLucene/search/HitQueue.h new file mode 100644 index 000000000..0bd196a7f --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/HitQueue.h @@ -0,0 +1,55 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_HitQueue_ +#define _lucene_search_HitQueue_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "SearchHeader.h" + +CL_NS_DEF(search) + +/** +* An optimised PriorityQueue which takes ScoreDoc structs. Some by-ref passing +* and memory related optimisations have been done. +*/ +class HitQueue: LUCENE_BASE { +private: + ScoreDoc* heap; + size_t _size; + size_t maxSize; + + void upHeap(); + void downHeap(); + +protected: + bool lessThan(struct ScoreDoc& hitA, struct ScoreDoc& hitB); + +public: + void adjustTop(); + struct ScoreDoc& top(); + void put(struct ScoreDoc& element); + ScoreDoc pop(); + /** + * Adds element to the PriorityQueue in log(size) time if either + * the PriorityQueue is not full, or not lessThan(element, top()). + * @param element + * @return true if element is added, false otherwise. + */ + bool insert(struct ScoreDoc& element); + /** + * Returns the number of elements currently stored in the PriorityQueue. + */ + size_t size(); + HitQueue(const int32_t maxSize); + ~HitQueue(); + +}; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/Hits.cpp b/3rdparty/clucene/src/CLucene/search/Hits.cpp new file mode 100644 index 000000000..38c489f44 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/Hits.cpp @@ -0,0 +1,174 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" + +#include "SearchHeader.h" +#include "CLucene/document/Document.h" +#include "CLucene/index/IndexReader.h" +#include "Filter.h" +#include "CLucene/search/SearchHeader.h" + +CL_NS_USE(document) +CL_NS_USE(util) +CL_NS_USE(index) + +CL_NS_DEF(search) + + HitDoc::HitDoc(const qreal s, const int32_t i) + { + //Func - Constructor + //Pre - true + //Post - The instance has been created + + next = NULL; + prev = NULL; + doc = NULL; + score = s; + id = i; + } + + HitDoc::~HitDoc(){ + //Func - Destructor + //Pre - true + //Post - The instance has been destroyed + + _CLDELETE(doc); + } + + + Hits::Hits(Searcher* s, Query* q, Filter* f, const Sort* _sort): + query(q), searcher(s), filter(f), sort(_sort) + { + //Func - Constructor + //Pre - s contains a valid reference to a searcher s + // q contains a valid reference to a Query + // f is NULL or contains a pointer to a filter + //Post - The instance has been created + + _length = 0; + first = NULL; + last = NULL; + numDocs = 0; + maxDocs = 200; + + //retrieve 100 initially + getMoreDocs(50); + } + + Hits::~Hits(){ + + } + int32_t Hits::length() const { + return _length; + } + + Document& Hits::doc(const int32_t n){ + HitDoc* hitDoc = getHitDoc(n); + + // Update LRU cache of documents + remove(hitDoc); // remove from list, if there + addToFront(hitDoc); // add to front of list + if (numDocs > maxDocs) { // if cache is full + HitDoc* oldLast = last; + remove(last); // flush last + + _CLDELETE( oldLast->doc ); + oldLast->doc = NULL; + } + + if (hitDoc->doc == NULL){ + hitDoc->doc = _CLNEW Document; + searcher->doc(hitDoc->id, hitDoc->doc); // cache miss: read document + } + + return *hitDoc->doc; + } + + int32_t Hits::id (const int32_t n){ + return getHitDoc(n)->id; + } + + qreal Hits::score(const int32_t n){ + return getHitDoc(n)->score; + } + + void Hits::getMoreDocs(const size_t m){ + size_t _min = m; + { + size_t nHits = hitDocs.size(); + if ( nHits > _min) + _min = nHits; + } + + size_t n = _min * 2; // double # retrieved + TopDocs* topDocs = NULL; + if ( sort==NULL ) + topDocs = (TopDocs*)((Searchable*)searcher)->_search(query, filter, n); + else + topDocs = (TopDocs*)((Searchable*)searcher)->_search(query, filter, n, sort); + _length = topDocs->totalHits; + ScoreDoc* scoreDocs = topDocs->scoreDocs; + int32_t scoreDocsLength = topDocs->scoreDocsLength; + + qreal scoreNorm = 1.0f; + //Check that scoreDocs is a valid pointer before using it + if (scoreDocs != NULL){ + if (_length > 0 && scoreDocs[0].score > 1.0f){ + scoreNorm = 1.0f / scoreDocs[0].score; + } + + int32_t end = scoreDocsLength < _length ? scoreDocsLength : _length; + for (int32_t i = hitDocs.size(); i < end; i++) { + hitDocs.push_back(_CLNEW HitDoc(scoreDocs[i].score*scoreNorm, scoreDocs[i].doc)); + } + } + + _CLDELETE(topDocs); + } + + HitDoc* Hits::getHitDoc(const size_t n){ + if (n >= _length){ + TCHAR buf[100]; + _sntprintf(buf, 100,_T("Not a valid hit number: %d"),n); + _CLTHROWT(CL_ERR_IndexOutOfBounds, buf ); + } + if (n >= hitDocs.size()) + getMoreDocs(n); + + return hitDocs[n]; + } + + void Hits::addToFront(HitDoc* hitDoc) { // insert at front of cache + if (first == NULL) + last = hitDoc; + else + first->prev = hitDoc; + + hitDoc->next = first; + first = hitDoc; + hitDoc->prev = NULL; + + numDocs++; + } + + void Hits::remove(const HitDoc* hitDoc) { // remove from cache + if (hitDoc->doc == NULL) // it's not in the list + return; // abort + + if (hitDoc->next == NULL) + last = hitDoc->prev; + else + hitDoc->next->prev = hitDoc->prev; + + if (hitDoc->prev == NULL) + first = hitDoc->next; + else + hitDoc->prev->next = hitDoc->next; + + numDocs--; + } +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/IndexSearcher.cpp b/3rdparty/clucene/src/CLucene/search/IndexSearcher.cpp new file mode 100644 index 000000000..c948cfa4b --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/IndexSearcher.cpp @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#include "CLucene/StdHeader.h" +#include "IndexSearcher.h" + +#include "SearchHeader.h" +#include "Scorer.h" +#include "FieldDocSortedHitQueue.h" +#include "CLucene/store/Directory.h" +#include "CLucene/document/Document.h" +#include "CLucene/index/IndexReader.h" +#include "CLucene/index/Term.h" +#include "CLucene/util/BitSet.h" +#include "FieldSortedHitQueue.h" + +CL_NS_USE(index) +CL_NS_USE(util) +CL_NS_USE(document) + +CL_NS_DEF(search) + +class SimpleTopDocsCollector : public HitCollector +{ +private: + qreal minScore; + const CL_NS(util)::BitSet* bits; + HitQueue* hq; + size_t nDocs; + int32_t* totalHits; + +public: + SimpleTopDocsCollector(const CL_NS(util)::BitSet* bs, HitQueue* hitQueue, + int32_t* totalhits, size_t ndocs, const qreal ms=-1.0f) + : minScore(ms), + bits(bs), + hq(hitQueue), + nDocs(ndocs), + totalHits(totalhits) {} + ~SimpleTopDocsCollector() {} + + void collect(const int32_t doc, const qreal score) + { + if (score > 0.0f // ignore zeroed buckets + && (bits == NULL || bits->get(doc))) { // skip docs not in bits + ++totalHits[0]; + if (hq->size() < nDocs || (minScore==-1.0f || score >= minScore)) { + ScoreDoc sd = {doc, score}; + hq->insert(sd); // update hit queue + if ( minScore != -1.0f ) + minScore = hq->top().score; // maintain minScore + } + } + } +}; + +class SortedTopDocsCollector : public HitCollector +{ +private: + const CL_NS(util)::BitSet* bits; + FieldSortedHitQueue* hq; + size_t nDocs; + int32_t* totalHits; +public: + SortedTopDocsCollector(const CL_NS(util)::BitSet* bs, + FieldSortedHitQueue* hitQueue, int32_t* totalhits, size_t _nDocs) + : bits(bs), + hq(hitQueue), + nDocs(_nDocs), + totalHits(totalhits) + { + } + ~SortedTopDocsCollector() {} + + void collect(const int32_t doc, const qreal score) + { + if (score > 0.0f && // ignore zeroed buckets + (bits==NULL || bits->get(doc))) { // skip docs not in bits + ++totalHits[0]; + // TODO: see jlucene way... with fields def??? + FieldDoc* fd = _CLNEW FieldDoc(doc, score); + if ( !hq->insert(fd) ) // update hit queue + _CLDELETE(fd); + } + } +}; + +class SimpleFilteredCollector : public HitCollector +{ +private: + CL_NS(util)::BitSet* bits; + HitCollector* results; +public: + SimpleFilteredCollector(CL_NS(util)::BitSet* bs, HitCollector* collector) + : bits(bs), + results(collector) {} + ~SimpleFilteredCollector() {} + +protected: + void collect(const int32_t doc, const qreal score) + { + // skip docs not in bits + if (bits->get(doc)) + results->collect(doc, score); + } +}; + + +IndexSearcher::IndexSearcher(const QString& path) +{ + //Func - Constructor + // Creates a searcher searching the index in the named directory. + //Pre - path != NULL + //Post - The instance has been created + + CND_PRECONDITION(!path.isEmpty(), "path is NULL"); + + reader = IndexReader::open(path); + readerOwner = true; +} + +IndexSearcher::IndexSearcher(CL_NS(store)::Directory* directory) +{ + //Func - Constructor + // Creates a searcher searching the index in the specified directory. + //Pre - path != NULL + //Post - The instance has been created + + CND_PRECONDITION(directory != NULL, "directory is NULL"); + + reader = IndexReader::open(directory); + readerOwner = true; +} + +IndexSearcher::IndexSearcher(IndexReader* r) +{ + //Func - Constructor + // Creates a searcher searching the index with the provide IndexReader + //Pre - path != NULL + //Post - The instance has been created + + reader = r; + readerOwner = false; +} + +IndexSearcher::~IndexSearcher() +{ + //Func - Destructor + //Pre - true + //Post - The instance has been destroyed + + close(); +} + +void IndexSearcher::close() +{ + //Func - Frees resources associated with this Searcher. + //Pre - true + //Post - The resources associated have been freed + if (readerOwner && reader){ + reader->close(); + _CLDELETE(reader); + } +} + +// inherit javadoc +int32_t IndexSearcher::docFreq(const Term* term) const +{ + //Func - + //Pre - reader != NULL + //Post - + + CND_PRECONDITION(reader != NULL, "reader is NULL"); + return reader->docFreq(term); +} + +// inherit javadoc +bool IndexSearcher::doc(int32_t i, CL_NS(document)::Document* d) +{ + //Func - Retrieves i-th document found + // For use by HitCollector implementations. + //Pre - reader != NULL + //Post - The i-th document has been returned + + CND_PRECONDITION(reader != NULL, "reader is NULL"); + return reader->document(i,d); +} + +// inherit javadoc +int32_t IndexSearcher::maxDoc() const +{ + //Func - Return total number of documents including the ones marked deleted + //Pre - reader != NULL + //Post - The total number of documents including the ones marked deleted + // has been returned + + CND_PRECONDITION(reader != NULL, "reader is NULL"); + return reader->maxDoc(); +} + +TopDocs* IndexSearcher::_search(Query* query, Filter* filter, const int32_t nDocs) +{ + //Func - + //Pre - reader != NULL + //Post - + + CND_PRECONDITION(reader != NULL, "reader is NULL"); + CND_PRECONDITION(query != NULL, "query is NULL"); + + Weight* weight = query->weight(this); + Scorer* scorer = weight->scorer(reader); + if (scorer == NULL){ + return _CLNEW TopDocs(0, NULL, 0); + } + + BitSet* bits = filter != NULL ? filter->bits(reader) : NULL; + HitQueue* hq = _CLNEW HitQueue(nDocs); + + //Check hq has been allocated properly + CND_CONDITION(hq != NULL, "Could not allocate memory for HitQueue hq"); + + int32_t* totalHits = _CL_NEWARRAY(int32_t,1); + totalHits[0] = 0; + + SimpleTopDocsCollector hitCol(bits,hq,totalHits,nDocs,0.0f); + scorer->score( &hitCol ); + _CLDELETE(scorer); + + int32_t scoreDocsLength = hq->size(); + + ScoreDoc* scoreDocs = _CL_NEWARRAY(ScoreDoc,scoreDocsLength); + + for (int32_t i = scoreDocsLength-1; i >= 0; --i) // put docs in array + scoreDocs[i] = hq->pop(); + + int32_t totalHitsInt = totalHits[0]; + + _CLDELETE(hq); + if ( bits != NULL && filter->shouldDeleteBitSet(bits) ) + _CLDELETE(bits); + _CLDELETE_ARRAY(totalHits); + Query* wq = weight->getQuery(); + if ( query != wq ) //query was re-written + _CLLDELETE(wq); + _CLDELETE(weight); + + return _CLNEW TopDocs(totalHitsInt, scoreDocs, scoreDocsLength); +} + +// inherit javadoc +TopFieldDocs* IndexSearcher::_search(Query* query, Filter* filter, + const int32_t nDocs, const Sort* sort) +{ + CND_PRECONDITION(reader != NULL, "reader is NULL"); + CND_PRECONDITION(query != NULL, "query is NULL"); + + Weight* weight = query->weight(this); + Scorer* scorer = weight->scorer(reader); + if (scorer == NULL) { + return _CLNEW TopFieldDocs(0, NULL, 0, NULL ); + } + + BitSet* bits = filter != NULL ? filter->bits(reader) : NULL; + FieldSortedHitQueue hq(reader, sort->getSort(), nDocs); + int32_t* totalHits = _CL_NEWARRAY(int32_t,1); + totalHits[0]=0; + + SortedTopDocsCollector hitCol(bits,&hq,totalHits,nDocs); + scorer->score(&hitCol); + _CLDELETE(scorer); + + int32_t hqLen = hq.size(); + FieldDoc** fieldDocs = _CL_NEWARRAY(FieldDoc*,hqLen); + for (int32_t i = hqLen-1; i >= 0; --i){ // put docs in array + fieldDocs[i] = hq.fillFields (hq.pop()); + } + + Query* wq = weight->getQuery(); + if ( query != wq ) //query was re-written + _CLLDELETE(wq); + _CLDELETE(weight); + + SortField** hqFields = hq.getFields(); + hq.setFields(NULL); //move ownership of memory over to TopFieldDocs + int32_t totalHits0 = totalHits[0]; + if ( bits != NULL && filter->shouldDeleteBitSet(bits) ) + _CLDELETE(bits); + _CLDELETE_ARRAY(totalHits); + return _CLNEW TopFieldDocs(totalHits0, fieldDocs, hqLen, hqFields ); +} + +void IndexSearcher::_search(Query* query, Filter* filter, HitCollector* results) +{ + //Func - _search an index and fetch the results + // Applications should only use this if they need all of the + // matching documents. The high-level search API (search(Query)) + // is usually more efficient, as it skips non-high-scoring hits. + //Pre - query is a valid reference to a query filter may or may not be NULL + // results is a valid reference to a HitCollector and used to store the results + //Post - filter if non-NULL, a bitset used to eliminate some documents + + CND_PRECONDITION(reader != NULL, "reader is NULL"); + CND_PRECONDITION(query != NULL, "query is NULL"); + + BitSet* bits = NULL; + SimpleFilteredCollector* fc = NULL; + + if (filter != NULL){ + bits = filter->bits(reader); + fc = _CLNEW SimpleFilteredCollector(bits, results); + } + + Weight* weight = query->weight(this); + Scorer* scorer = weight->scorer(reader); + if (scorer != NULL) { + if (fc == NULL){ + scorer->score(results); + }else{ + scorer->score((HitCollector*)fc); + } + _CLDELETE(scorer); + } + + _CLDELETE(fc); + _CLDELETE(weight); + if ( bits != NULL && filter->shouldDeleteBitSet(bits) ) + _CLDELETE(bits); +} + +Query* IndexSearcher::rewrite(Query* original) +{ + Query* query = original; + Query* last = original; + for (Query* rewrittenQuery = query->rewrite(reader); + rewrittenQuery != query; + rewrittenQuery = query->rewrite(reader)) { + query = rewrittenQuery; + if ( query != last && last != original) { + _CLDELETE(last); + } + last = query; + } + return query; +} + +void IndexSearcher::explain(Query* query, int32_t doc, Explanation* ret) +{ + Weight* weight = query->weight(this); + weight->explain(reader, doc, ret); + + Query* wq = weight->getQuery(); + if ( query != wq ) //query was re-written + _CLLDELETE(wq); + _CLDELETE(weight); +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/IndexSearcher.h b/3rdparty/clucene/src/CLucene/search/IndexSearcher.h new file mode 100644 index 000000000..307e0266d --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/IndexSearcher.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#ifndef _lucene_search_IndexSearcher_ +#define _lucene_search_IndexSearcher_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include + +#include "SearchHeader.h" +#include "CLucene/store/Directory.h" +#include "CLucene/document/Document.h" +#include "CLucene/index/IndexReader.h" +#include "CLucene/index/Term.h" +#include "CLucene/util/BitSet.h" +#include "HitQueue.h" +#include "FieldSortedHitQueue.h" + +CL_NS_DEF(search) +/** Implements search over a single IndexReader. +* +*

Applications usually need only call the inherited {@link search(Query*)} +* or {@link search(Query*,Filter*)} methods. +*/ +class IndexSearcher:public Searcher{ + CL_NS(index)::IndexReader* reader; + bool readerOwner; + +public: + /// Creates a searcher searching the index in the named directory. + IndexSearcher(const QString& path); + + /// Creates a searcher searching the index in the specified directory. + IndexSearcher(CL_NS(store)::Directory* directory); + + /// Creates a searcher searching the provided index. + IndexSearcher(CL_NS(index)::IndexReader* r); + + ~IndexSearcher(); + + /// Frees resources associated with this Searcher. + void close(); + + int32_t docFreq(const CL_NS(index)::Term* term) const; + + bool doc(int32_t i, CL_NS(document)::Document* document); + + int32_t maxDoc() const; + + TopDocs* _search(Query* query, Filter* filter, const int32_t nDocs); + TopFieldDocs* _search(Query* query, Filter* filter, const int32_t nDocs, + const Sort* sort); + + void _search(Query* query, Filter* filter, HitCollector* results); + + CL_NS(index)::IndexReader* getReader() { + return reader; } + + Query* rewrite(Query* original); + void explain(Query* query, int32_t doc, Explanation* ret); +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/search/MultiSearcher.cpp b/3rdparty/clucene/src/CLucene/search/MultiSearcher.cpp new file mode 100644 index 000000000..bed7f0d61 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/MultiSearcher.cpp @@ -0,0 +1,227 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "MultiSearcher.h" + +#include "SearchHeader.h" +#include "HitQueue.h" +#include "CLucene/document/Document.h" +#include "CLucene/index/Term.h" +#include "FieldDocSortedHitQueue.h" + +CL_NS_USE(index) +CL_NS_USE(util) +CL_NS_USE(document) + +CL_NS_DEF(search) + + /** Creates a searcher which searches searchers. */ + MultiSearcher::MultiSearcher(Searchable** _searchables): + _maxDoc(0) { + searchablesLen = 0; + while ( _searchables[searchablesLen] != NULL ) + ++searchablesLen; + + searchables=_CL_NEWARRAY(Searchable*,searchablesLen+1); + starts = _CL_NEWARRAY(int32_t,searchablesLen + 1); // build starts array + for (int32_t i = 0; i < searchablesLen; ++i) { + searchables[i]=_searchables[i]; + starts[i] = _maxDoc; + _maxDoc += searchables[i]->maxDoc(); // compute maxDocs + } + starts[searchablesLen] = _maxDoc; + } + + MultiSearcher::~MultiSearcher() { + _CLDELETE_ARRAY(searchables); + _CLDELETE_ARRAY(starts); + } + + + // inherit javadoc + void MultiSearcher::close() { + for (int32_t i = 0; i < searchablesLen; ++i){ + searchables[i]->close(); + searchables[i]=NULL; + } + } + + int32_t MultiSearcher::docFreq(const Term* term) const { + int32_t docFreq = 0; + for (int32_t i = 0; i < searchablesLen; ++i) + docFreq += searchables[i]->docFreq(term); + return docFreq; + } + + /** For use by {@link HitCollector} implementations. */ + bool MultiSearcher::doc(int32_t n, Document* d) { + int32_t i = subSearcher(n); // find searcher index + return searchables[i]->doc(n - starts[i], d); // dispatch to searcher + } + + int32_t MultiSearcher::searcherIndex(int32_t n) const{ + return subSearcher(n); + } + + /** Returns index of the searcher for document n in the array + * used to construct this searcher. */ + int32_t MultiSearcher::subSearcher(int32_t n) const{ + // replace w/ call to Arrays.binarySearch in Java 1.2 + int32_t lo = 0; // search starts array + int32_t hi = searchablesLen - 1; // for first element less + // than n, return its index + int32_t mid,midValue; + while (hi >= lo) { + mid = (lo + hi) >> 1; + midValue = starts[mid]; + if (n < midValue) + hi = mid - 1; + else if (n > midValue) + lo = mid + 1; + else{ // found a match + while (mid+1 < searchablesLen && starts[mid+1] == midValue) { + ++mid; // scan to last match + } + return mid; + } + } + return hi; + } + + /** Returns the document number of document n within its + * sub-index. */ + int32_t MultiSearcher::subDoc(int32_t n) const{ + return n - starts[subSearcher(n)]; + } + + int32_t MultiSearcher::maxDoc() const{ + return _maxDoc; + } + + TopDocs* MultiSearcher::_search(Query* query, Filter* filter, const int32_t nDocs) { + HitQueue* hq = _CLNEW HitQueue(nDocs); + int32_t totalHits = 0; + TopDocs* docs; + int32_t j; + ScoreDoc* scoreDocs; + for (int32_t i = 0; i < searchablesLen; i++) { // search each searcher + docs = searchables[i]->_search(query, filter, nDocs); + totalHits += docs->totalHits; // update totalHits + scoreDocs = docs->scoreDocs; + for ( j = 0; j scoreDocsLength; ++j) { // merge scoreDocs int_to hq + scoreDocs[j].doc += starts[i]; // convert doc + if ( !hq->insert(scoreDocs[j])) + break; // no more scores > minScore + } + + _CLDELETE(docs); + } + + int32_t scoreDocsLen = hq->size(); + scoreDocs = _CL_NEWARRAY(ScoreDoc, scoreDocsLen); + {//MSVC 6 scope fix + for (int32_t i = scoreDocsLen-1; i >= 0; --i) // put docs in array + scoreDocs[i] = hq->pop(); + } + + //cleanup + _CLDELETE(hq); + + return _CLNEW TopDocs(totalHits, scoreDocs, scoreDocsLen); + } + + /** Lower-level search API. + * + *

{@link HitCollector#collect(int32_t,qreal)} is called for every non-zero + * scoring document. + * + *

Applications should only use this if they need all of the + * matching documents. The high-level search API ({@link + * Searcher#search(Query)}) is usually more efficient, as it skips + * non-high-scoring hits. + * + * @param query to match documents + * @param filter if non-null, a bitset used to eliminate some documents + * @param results to receive hits + */ + void MultiSearcher::_search(Query* query, Filter* filter, HitCollector* results){ + for (int32_t i = 0; i < searchablesLen; ++i) { + /* DSR:CL_BUG: Old implementation leaked and was misconceived. We need + ** to have the original HitCollector ($results) collect *all* hits; + ** the MultiHitCollector instantiated below serves only to adjust + ** (forward by starts[i]) the docNo passed to $results. + ** Old implementation instead created a sort of linked list of + ** MultiHitCollectors that applied the adjustments in $starts + ** cumulatively (and was never deleted). */ + HitCollector *docNoAdjuster = _CLNEW MultiHitCollector(results, starts[i]); + searchables[i]->_search(query, filter, docNoAdjuster); + _CLDELETE(docNoAdjuster); + } + } + + TopFieldDocs* MultiSearcher::_search (Query* query, Filter* filter, const int32_t n, const Sort* sort){ + FieldDocSortedHitQueue* hq = NULL; + int32_t totalHits = 0; + TopFieldDocs* docs; + int32_t j; + FieldDoc** fieldDocs; + + for (int32_t i = 0; i < searchablesLen; ++i) { // search each searcher + docs = searchables[i]->_search (query, filter, n, sort); + if (hq == NULL){ + hq = _CLNEW FieldDocSortedHitQueue (docs->fields, n); + docs->fields = NULL; //hit queue takes fields memory + } + + totalHits += docs->totalHits; // update totalHits + fieldDocs = docs->fieldDocs; + for(j = 0;jscoreDocsLength;++j){ // merge scoreDocs into hq + fieldDocs[j]->scoreDoc.doc += starts[i]; // convert doc + if (!hq->insert (fieldDocs[j]) ) + break; // no more scores > minScore + } + for ( int32_t x=0;xsize(); + fieldDocs = _CL_NEWARRAY(FieldDoc*,hqlen); + for (j = hqlen - 1; j >= 0; j--) // put docs in array + fieldDocs[j] = hq->pop(); + + SortField** hqFields = hq->getFields(); + hq->setFields(NULL); //move ownership of memory over to TopFieldDocs + _CLDELETE(hq); + + return _CLNEW TopFieldDocs (totalHits, fieldDocs, hqlen, hqFields); + } + + Query* MultiSearcher::rewrite(Query* original) { + Query** queries = _CL_NEWARRAY(Query*,searchablesLen+1); + for (int32_t i = 0; i < searchablesLen; ++i) + queries[i] = searchables[i]->rewrite(original); + queries[searchablesLen]=NULL; + return original->combine(queries); + } + + void MultiSearcher::explain(Query* query, int32_t doc, Explanation* ret) { + int32_t i = subSearcher(doc); // find searcher index + searchables[i]->explain(query,doc-starts[i], ret); // dispatch to searcher + } + + MultiHitCollector::MultiHitCollector(HitCollector* _results, int32_t _start): + results(_results), + start(_start) { + } + + void MultiHitCollector::collect(const int32_t doc, const qreal score) { + results->collect(doc + start, score); + } + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/MultiSearcher.h b/3rdparty/clucene/src/CLucene/search/MultiSearcher.h new file mode 100644 index 000000000..1021fbbec --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/MultiSearcher.h @@ -0,0 +1,95 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_multisearcher +#define _lucene_search_multisearcher + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "SearchHeader.h" +#include "CLucene/document/Document.h" +#include "CLucene/index/Term.h" + +CL_NS_DEF(search) + + class MultiHitCollector: public HitCollector{ + private: + HitCollector* results; + int32_t start; + public: + MultiHitCollector(HitCollector* _results, int32_t _start); + void collect(const int32_t doc, const qreal score) ; + }; + + + /** Implements search over a set of Searchables. + * + *

Applications usually need only call the inherited {@link #search(Query)} + * or {@link #search(Query,Filter)} methods. + */ + class MultiSearcher: public Searcher { + private: + Searchable** searchables; + int32_t searchablesLen; + int32_t* starts; + int32_t _maxDoc; + protected: + int32_t* getStarts() { + return starts; + } + + public: + /** Creates a searcher which searches Searchables. */ + MultiSearcher(Searchable** searchables); + + ~MultiSearcher(); + + /** Frees resources associated with this Searcher. */ + void close() ; + + int32_t docFreq(const CL_NS(index)::Term* term) const ; + + /** For use by {@link HitCollector} implementations. */ + bool doc(int32_t n, CL_NS(document)::Document* document); + + /** For use by {@link HitCollector} implementations to identify the + * index of the sub-searcher that a particular hit came from. */ + int32_t searcherIndex(int32_t n) const; + + int32_t subSearcher(int32_t n) const; + + int32_t subDoc(int32_t n) const; + + int32_t maxDoc() const; + + TopDocs* _search(Query* query, Filter* filter, const int32_t nDocs) ; + + TopFieldDocs* _search (Query* query, Filter* filter, const int32_t n, const Sort* sort); + + /** Lower-level search API. + * + *

{@link HitCollector#collect(int32_t,qreal)} is called for every non-zero + * scoring document. + * + *

Applications should only use this if they need all of the + * matching documents. The high-level search API ({@link + * Searcher#search(Query)}) is usually more efficient, as it skips + * non-high-scoring hits. + * + * @param query to match documents + * @param filter if non-null, a bitset used to eliminate some documents + * @param results to receive hits + */ + void _search(Query* query, Filter* filter, HitCollector* results); + + Query* rewrite(Query* original); + void explain(Query* query, int32_t doc, Explanation* ret); + }; + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/MultiTermQuery.cpp b/3rdparty/clucene/src/CLucene/search/MultiTermQuery.cpp new file mode 100644 index 000000000..3bf8d7a26 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/MultiTermQuery.cpp @@ -0,0 +1,98 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "MultiTermQuery.h" + +CL_NS_USE(index) +CL_NS_USE(util) +CL_NS_DEF(search) + +/** Constructs a query for terms matching term. */ + + MultiTermQuery::MultiTermQuery(Term* t){ + //Func - Constructor + //Pre - t != NULL + //Post - The instance has been created + + CND_PRECONDITION(t != NULL, "t is NULL"); + + term = _CL_POINTER(t); + + } + MultiTermQuery::MultiTermQuery(const MultiTermQuery& clone): + Query(clone) + { + term = _CLNEW Term(clone.getTerm(false),clone.getTerm(false)->text()); + } + + MultiTermQuery::~MultiTermQuery(){ + //Func - Destructor + //Pre - true + //Post - The instance has been destroyed + + _CLDECDELETE(term); + } + + Term* MultiTermQuery::getTerm(bool pointer) const{ + if ( pointer ) + return _CL_POINTER(term); + else + return term; + } + + Query* MultiTermQuery::rewrite(IndexReader* reader) { + FilteredTermEnum* enumerator = getEnum(reader); + BooleanQuery* query = _CLNEW BooleanQuery(); + try { + do { + Term* t = enumerator->term(false); + if (t != NULL) { + TermQuery* tq = _CLNEW TermQuery(t); // found a match + tq->setBoost(getBoost() * enumerator->difference()); // set the boost + query->add(tq,true, false, false); // add to q + } + } while (enumerator->next()); + } _CLFINALLY ( enumerator->close(); _CLDELETE(enumerator) ); + + //if we only added one clause and the clause is not prohibited then + //we can just return the query + if (query->getClauseCount() == 1) { // optimize 1-clause queries + BooleanClause* c=0; + query->getClauses(&c); + + if (!c->prohibited) { // just return clause + c->deleteQuery=false; + Query* ret = c->query; + + _CLDELETE(query); + return ret; + } + } + return query; + } + + Query* MultiTermQuery::combine(Query** queries) { + return Query::mergeBooleanQueries(queries); + } + + /** Prints a user-readable version of this query. */ + TCHAR* MultiTermQuery::toString(const TCHAR* field) const{ + StringBuffer buffer; + + if ( field==NULL || _tcscmp(term->field(),field)!=0 ) { + buffer.append(term->field()); + buffer.append( _T(":")); + } + buffer.append(term->text()); + if (getBoost() != 1.0f) { + buffer.appendChar ( '^' ); + buffer.appendFloat( getBoost(),1); + } + return buffer.toString(); + } + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/MultiTermQuery.h b/3rdparty/clucene/src/CLucene/search/MultiTermQuery.h new file mode 100644 index 000000000..d37645359 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/MultiTermQuery.h @@ -0,0 +1,62 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_MultiTermQuery_ +#define _lucene_search_MultiTermQuery_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/util/StringBuffer.h" +#include "CLucene/index/IndexReader.h" +#include "CLucene/index/Term.h" +#include "CLucene/index/Terms.h" +#include "FilteredTermEnum.h" +#include "SearchHeader.h" +#include "BooleanQuery.h" +#include "TermQuery.h" + +CL_NS_DEF(search) + /** + * A {@link Query} that matches documents containing a subset of terms provided + * by a {@link FilteredTermEnum} enumeration. + *

+ * MultiTermQuery is not designed to be used by itself. + *
+ * The reason being that it is not intialized with a {@link FilteredTermEnum} + * enumeration. A {@link FilteredTermEnum} enumeration needs to be provided. + *

+ * For example, {@link WildcardQuery} and {@link FuzzyQuery} extend + * MultiTermQuery to provide {@link WildcardTermEnum} and + * {@link FuzzyTermEnum}, respectively. + */ + class MultiTermQuery: public Query { + private: + CL_NS(index)::Term* term; + protected: + MultiTermQuery(const MultiTermQuery& clone); + + /** Construct the enumeration to be used, expanding the pattern term. */ + virtual FilteredTermEnum* getEnum(CL_NS(index)::IndexReader* reader) = 0; + public: + /** Constructs a query for terms matching term. */ + MultiTermQuery(CL_NS(index)::Term* t); + + virtual ~MultiTermQuery(); + + /** Returns the pattern term. */ + CL_NS(index)::Term* getTerm(bool pointer=true) const; + + Query* combine(Query** queries); + + /** Prints a user-readable version of this query. */ + TCHAR* toString(const TCHAR* field) const; + + Query* rewrite(CL_NS(index)::IndexReader* reader); + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/PhrasePositions.cpp b/3rdparty/clucene/src/CLucene/search/PhrasePositions.cpp new file mode 100644 index 000000000..7611056e7 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/PhrasePositions.cpp @@ -0,0 +1,116 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "PhrasePositions.h" + +#include "CLucene/index/Terms.h" + +CL_NS_USE(index) +CL_NS_DEF(search) + + PhrasePositions::PhrasePositions(TermPositions* Tp, const int32_t OffSet){ + //Func - Constructor + //Pre - t != NULL + // OffSet != NULL + //Post - The instance has been created + + CND_PRECONDITION(Tp != NULL,"Tp is NULL"); + CND_PRECONDITION(OffSet >= 0 ,"OffSet is a negative number"); + + tp = Tp; + offset = OffSet; + position = 0; + count = 0; + doc = 0; + + _next = NULL; + } + + PhrasePositions::~PhrasePositions(){ + //Func - Destructor + //Pre - true + //Post - The instance has been deleted + + //delete next Phrase position and by doing that + //all PhrasePositions in the list + _CLDELETE(_next); + + //Check if tp is valid + if ( tp != NULL ){ + //Close TermPositions tp + tp->close(); + _CLDELETE(tp); + } + } + + bool PhrasePositions::next(){ + //Func - Increments to next doc + //Pre - tp != NULL + //Post - if there was no next then doc = INT_MAX otherwise + // doc contains the current document number + + CND_PRECONDITION(tp != NULL,"tp is NULL"); + + //Move to the next in TermPositions tp + if (!tp->next()) { + //There is no next so close the stream + tp->close(); + //delete tp and reset tp to NULL + _CLVDELETE(tp); //todo: not a clucene object... should be + //Assign Doc sentinel value + doc = INT_MAX; + return false; + }else{ + doc = tp->doc(); + position = 0; + return true; + } + } + bool PhrasePositions::skipTo(int32_t target){ + if (!tp->skipTo(target)) { + tp->close(); // close stream + doc = LUCENE_INT32_MAX_SHOULDBE; // sentinel value + return false; + } + doc = tp->doc(); + position = 0; + return true; + } + void PhrasePositions::firstPosition(){ + //Func - Read the first TermPosition + //Pre - tp != NULL + //Post - + + CND_PRECONDITION(tp != NULL,"tp is NULL"); + + //read first pos + count = tp->freq(); + //Move to the next TermPosition + nextPosition(); + } + + bool PhrasePositions::nextPosition(){ + //Func - Move to the next position + //Pre - tp != NULL + //Post - + + CND_PRECONDITION(tp != NULL,"tp is NULL"); + + if (count-- > 0) { + //read subsequent pos's + position = tp->nextPosition() - offset; + + //Check position always bigger than or equal to 0 + //bvk: todo, bug??? position < 0 occurs, cant figure out why, + //old version does it too and will fail the "SearchTest" test + //CND_CONDITION(position >= 0, "position has become a negative number"); + return true; + }else{ + return false; + } + } +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/PhrasePositions.h b/3rdparty/clucene/src/CLucene/search/PhrasePositions.h new file mode 100644 index 000000000..b6c8437b9 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/PhrasePositions.h @@ -0,0 +1,41 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_PhrasePositions_ +#define _lucene_search_PhrasePositions_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/index/Terms.h" + +CL_NS_DEF(search) + + class PhrasePositions:LUCENE_BASE { + public: + int32_t doc; // current doc + int32_t position; // position in doc + int32_t count; // remaining pos in this doc + int32_t offset; // position in phrase + CL_NS(index)::TermPositions* tp; // stream of positions + PhrasePositions* _next; // used to make lists + + + //Constructor + PhrasePositions(CL_NS(index)::TermPositions* Tp, const int32_t o); + //Destructor + ~PhrasePositions(); + + bool next(); + bool skipTo(int32_t target); + + void firstPosition(); + + bool nextPosition(); + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/PhraseQuery.cpp b/3rdparty/clucene/src/CLucene/search/PhraseQuery.cpp new file mode 100644 index 000000000..899cb3cfe --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/PhraseQuery.cpp @@ -0,0 +1,463 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "PhraseQuery.h" + +#include "SearchHeader.h" +#include "Scorer.h" +#include "BooleanQuery.h" +#include "TermQuery.h" + +#include "CLucene/index/Term.h" +#include "CLucene/index/Terms.h" +#include "CLucene/index/IndexReader.h" + +#include "CLucene/util/StringBuffer.h" +#include "CLucene/util/VoidList.h" +#include "CLucene/util/Arrays.h" + +#include "ExactPhraseScorer.h" +#include "SloppyPhraseScorer.h" + +CL_NS_USE(index) +CL_NS_USE(util) +CL_NS_DEF(search) + + PhraseQuery::PhraseQuery(): + terms(false) + { + //Func - Constructor + //Pre - true + //Post - An empty PhraseQuery has been created + + slop = 0; + + field = NULL; + } + PhraseQuery::PhraseQuery(const PhraseQuery& clone): + Query(clone), terms(false) + { + slop = clone.slop; + field = clone.field; + int32_t size=clone.positions.size(); + { //msvc6 scope fix + for ( int32_t i=0;ipositions.push_back( n ); + } + } + size=clone.terms.size(); + { //msvc6 scope fix + for ( int32_t i=0;iterms.push_back( _CL_POINTER(clone.terms[i])); + } + } + } + Query* PhraseQuery::clone() const{ + return _CLNEW PhraseQuery(*this); + } + bool PhraseQuery::equals(CL_NS(search)::Query *other) const{ + if (!(other->instanceOf(PhraseQuery::getClassName()))) + return false; + + PhraseQuery* pq = (PhraseQuery*)other; + bool ret = (this->getBoost() == pq->getBoost()) + && (this->slop == pq->slop); + + if ( ret ){ + CLListEquals, + const CL_NS(util)::CLVector > comp; + ret = comp.equals(&this->terms,&pq->terms); + } + + if ( ret ){ + CLListEquals, + const CL_NS(util)::CLVector > comp; + ret = comp.equals(&this->positions,&pq->positions); + } + return ret; + } + + + PhraseQuery::~PhraseQuery(){ + //Func - Destructor + //Pre - true + //Post 0 The instance has been destroyed + + //Iterate through all the terms + for (uint32_t i = 0; i < terms.size(); i++){ + _CLLDECDELETE(terms[i]); + } + positions.clear(); + } + + size_t PhraseQuery::hashCode() const { + //todo: do cachedHashCode, and invalidate on add/remove clause + size_t ret = Similarity::floatToByte(getBoost()) ^ Similarity::floatToByte(slop); + + { //msvc6 scope fix + for ( int32_t i=0;terms.size();i++ ) + ret = 31 * ret + terms[i]->hashCode(); + } + { //msvc6 scope fix + for ( int32_t i=0;positions.size();i++ ) + ret = 31 * ret + positions[i]; + } + return ret; + } + + const TCHAR* PhraseQuery::getClassName(){ + return _T("PhraseQuery"); + } + const TCHAR* PhraseQuery::getQueryName() const{ + //Func - Returns the string "PhraseQuery" + //Pre - true + //Post - The string "PhraseQuery" has been returned + return getClassName(); + } + + + /** + * Adds a term to the end of the query phrase. + * The relative position of the term is the one immediately after the last term added. + */ + void PhraseQuery::add(Term* term) { + CND_PRECONDITION(term != NULL,"term is NULL"); + + int32_t position = 0; + + if(positions.size() > 0) + position = (positions[positions.size()-1]) + 1; + + add(term, position); + } + + void PhraseQuery::add(Term* term, int32_t position) { + //Func - Adds a term to the end of the query phrase. + //Pre - term != NULL + //Post - The term has been added if its field matches the field of the PhraseQuery + // and true is returned otherwise false is returned + CND_PRECONDITION(term != NULL,"term is NULL"); + + if (terms.size() == 0) + field = term->field(); + else{ + //Check if the field of the _CLNEW term matches the field of the PhraseQuery + //can use != because fields are interned + if ( term->field() != field){ + //return false; + TCHAR buf[200]; + _sntprintf(buf,200,_T("All phrase terms must be in the same field: %s"),term->field()); + _CLTHROWT(CL_ERR_IllegalArgument,buf); + } + } + //Store the _CLNEW term + terms.push_back(_CL_POINTER(term)); + + positions.push_back(position); + } + + void PhraseQuery::getPositions(Array& result) const{ + result.length = positions.size(); + result.values = _CL_NEWARRAY(int32_t,result.length); + for(int32_t i = 0; i < result.length; i++){ + result.values[i] = positions[i]; + } + } + int32_t* PhraseQuery::getPositions() const{ + CND_WARNING(false,"getPositions() is deprecated") + + Array arr; + getPositions(arr); + return arr.values; + } + + Weight* PhraseQuery::_createWeight(Searcher* searcher) { + if (terms.size() == 1) { // optimize one-term case + Term* term = terms[0]; + Query* termQuery = _CLNEW TermQuery(term); + termQuery->setBoost(getBoost()); + Weight* ret = termQuery->_createWeight(searcher); + _CLDELETE(termQuery); + return ret; + } + return _CLNEW PhraseWeight(searcher,this); + } + + + Term** PhraseQuery::getTerms() const{ + //Func - added by search highlighter + //Pre - + //Post - + + //Let size contain the number of terms + int32_t size = terms.size(); + Term** ret = _CL_NEWARRAY(Term*,size+1); + + CND_CONDITION(ret != NULL,"Could not allocated memory for ret"); + + //Iterate through terms and copy each pointer to ret + for ( int32_t i=0;itext() ); + //Check if i is at the end of terms + if (i != terms.size()-1){ + buffer.append(_T(" ")); + } + } + + buffer.append( _T("\"") ); + + if (slop != 0) { + buffer.append(_T("~")); + buffer.appendFloat(slop,0); + } + + //Check if there is an other boost factor than 1.0 + if (getBoost() != 1.0f) { + buffer.append(_T("^")); + buffer.appendFloat( getBoost(),1 ); + } + + //return the query string + return buffer.toString(); + } + + + + + + + + + PhraseQuery::PhraseWeight::PhraseWeight(Searcher* searcher, PhraseQuery* _this) { + this->_this=_this; + this->value = 0; + this->idf = 0; + this->queryNorm = 0; + this->queryWeight = 0; + this->searcher = searcher; + } + + TCHAR* PhraseQuery::PhraseWeight::toString() { + return STRDUP_TtoT(_T("weight(PhraseQuery)")); + } + PhraseQuery::PhraseWeight::~PhraseWeight(){ + } + + + Query* PhraseQuery::PhraseWeight::getQuery() { return _this; } + qreal PhraseQuery::PhraseWeight::getValue() { return value; } + + qreal PhraseQuery::PhraseWeight::sumOfSquaredWeights(){ + idf = _this->getSimilarity(searcher)->idf(&_this->terms, searcher); + queryWeight = idf * _this->getBoost(); // compute query weight + return queryWeight * queryWeight; // square it + } + + void PhraseQuery::PhraseWeight::normalize(qreal queryNorm) { + this->queryNorm = queryNorm; + queryWeight *= queryNorm; // normalize query weight + value = queryWeight * idf; // idf for document + } + + Scorer* PhraseQuery::PhraseWeight::scorer(IndexReader* reader) { + //Func - + //Pre - + //Post - + + //Get the length of terms + int32_t tpsLength = _this->terms.size(); + + //optimize zero-term case + if (tpsLength == 0) + return NULL; + + TermPositions** tps = _CL_NEWARRAY(TermPositions*,tpsLength+1); + + //Check if tps has been allocated properly + CND_CONDITION(tps != NULL,"Could not allocate memory for tps"); + + TermPositions* p = NULL; + + //Iterate through all terms + int32_t size = _this->terms.size(); + for (int32_t i = 0; i < size; i++) { + //Get the termPostitions for the i-th term + p = reader->termPositions(_this->terms[i]); + + //Check if p is valid + if (p == NULL) { + //Delete previous retrieved termPositions + while (--i >= 0){ + _CLVDELETE(tps[i]); //todo: not a clucene object... should be + } + _CLDELETE_ARRAY(tps); + return NULL; + } + + //Store p at i in tps + tps[i] = p; + } + tps[tpsLength] = NULL; + + Scorer* ret = NULL; + + Array positions; + _this->getPositions(positions); + int32_t slop = _this->getSlop(); + if ( slop != 0) + // optimize exact case + //todo: need to pass these: this, tps, + ret = _CLNEW SloppyPhraseScorer(this,tps,positions.values, + _this->getSimilarity(searcher), + slop, reader->norms(_this->field)); + else + ret = _CLNEW ExactPhraseScorer(this, tps, positions.values, + _this->getSimilarity(searcher), + reader->norms(_this->field)); + positions.deleteArray(); + + CND_CONDITION(ret != NULL,"Could not allocate memory for ret"); + + //tps can be deleted safely. SloppyPhraseScorer or ExactPhraseScorer will take care + //of its values + + _CLDELETE_ARRAY(tps); + return ret; + } + + void PhraseQuery::PhraseWeight::explain(IndexReader* reader, int32_t doc, Explanation* result){ + TCHAR descbuf[LUCENE_SEARCH_EXPLANATION_DESC_LEN+1]; + TCHAR* tmp; + + tmp = getQuery()->toString(); + _sntprintf(descbuf,LUCENE_SEARCH_EXPLANATION_DESC_LEN,_T("weight(%s in %d), product of:"), + tmp,doc); + _CLDELETE_CARRAY(tmp); + result->setDescription(descbuf); + + StringBuffer docFreqs; + StringBuffer query; + query.appendChar('\"'); + for (uint32_t i = 0; i < _this->terms.size(); i++) { + if (i != 0) { + docFreqs.appendChar(' '); + query.appendChar(' '); + } + + Term* term = _this->terms[i]; + + docFreqs.append(term->text()); + docFreqs.appendChar('='); + docFreqs.appendInt(searcher->docFreq(term)); + + query.append(term->text()); + } + query.appendChar('\"'); + + _sntprintf(descbuf,LUCENE_SEARCH_EXPLANATION_DESC_LEN, + _T("idf(%s: %s)"),_this->field,docFreqs.getBuffer()); + Explanation* idfExpl = _CLNEW Explanation(idf, descbuf); + + // explain query weight + Explanation* queryExpl = _CLNEW Explanation; + tmp = getQuery()->toString(); + _sntprintf(descbuf,LUCENE_SEARCH_EXPLANATION_DESC_LEN, + _T("queryWeight(%s), product of:"),tmp); + _CLDELETE_CARRAY(tmp); + queryExpl->setDescription(descbuf); + + Explanation* boostExpl = _CLNEW Explanation(_this->getBoost(), _T("boost")); + if (_this->getBoost() != 1.0f) + queryExpl->addDetail(boostExpl); + queryExpl->addDetail(idfExpl); + + Explanation* queryNormExpl = _CLNEW Explanation(queryNorm,_T("queryNorm")); + queryExpl->addDetail(queryNormExpl); + + queryExpl->setValue(boostExpl->getValue() * + idfExpl->getValue() * + queryNormExpl->getValue()); + + result->addDetail(queryExpl); + + // explain field weight + Explanation* fieldExpl = _CLNEW Explanation; + _sntprintf(descbuf,LUCENE_SEARCH_EXPLANATION_DESC_LEN, + _T("fieldWeight(%s:%s in %d), product of:"), + _this->field,query.getBuffer(),doc); + fieldExpl->setDescription(descbuf); + + + Explanation* tfExpl = _CLNEW Explanation; + scorer(reader)->explain(doc, tfExpl); + fieldExpl->addDetail(tfExpl); + fieldExpl->addDetail(idfExpl); + + Explanation* fieldNormExpl = _CLNEW Explanation(); + uint8_t* fieldNorms = reader->norms(_this->field); + qreal fieldNorm = + fieldNorms!=NULL ? Similarity::decodeNorm(fieldNorms[doc]) : 0.0f; + fieldNormExpl->setValue(fieldNorm); + + + _sntprintf(descbuf,LUCENE_SEARCH_EXPLANATION_DESC_LEN, + _T("fieldNorm(field=%s, doc=%d)"),_this->field,doc); + fieldNormExpl->setDescription(descbuf); + fieldExpl->addDetail(fieldNormExpl); + + fieldExpl->setValue(tfExpl->getValue() * + idfExpl->getValue() * + fieldNormExpl->getValue()); + + result->addDetail(fieldExpl); + + // combine them + result->setValue(queryExpl->getValue() * fieldExpl->getValue()); + + if (queryExpl->getValue() == 1.0f){ + result->set(*fieldExpl); + _CLDELETE(fieldExpl); + } + } + + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/PhraseQuery.h b/3rdparty/clucene/src/CLucene/search/PhraseQuery.h new file mode 100644 index 000000000..6b3255822 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/PhraseQuery.h @@ -0,0 +1,127 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_PhraseQuery_ +#define _lucene_search_PhraseQuery_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "SearchHeader.h" +#include "Scorer.h" +#include "BooleanQuery.h" +#include "TermQuery.h" + +#include "CLucene/index/Term.h" +#include "CLucene/index/Terms.h" +#include "CLucene/index/IndexReader.h" + +#include "CLucene/util/StringBuffer.h" +#include "CLucene/util/VoidList.h" + +#include "ExactPhraseScorer.h" +#include "SloppyPhraseScorer.h" + +CL_NS_DEF(search) + // A Query that matches documents containing a particular sequence of terms. + // This may be combined with other terms with a {@link BooleanQuery}. + class PhraseQuery: public Query { + private: + CL_NS(util)::CLVector positions; + int32_t slop; + + const TCHAR* field; + CL_NS(util)::CLVector terms; + + + class PhraseWeight: public Weight { + private: + Searcher* searcher; + qreal value; + qreal idf; + qreal queryNorm; + qreal queryWeight; + PhraseQuery* _this; + public: + PhraseWeight(Searcher* searcher, PhraseQuery* _this); + ~PhraseWeight(); + TCHAR* toString(); + + Query* getQuery(); + qreal getValue(); + + qreal sumOfSquaredWeights(); + void normalize(qreal queryNorm); + Scorer* scorer(CL_NS(index)::IndexReader* reader); + void explain(CL_NS(index)::IndexReader* reader, int32_t doc, Explanation* ret); + TCHAR* toString(TCHAR* f); + bool equals(PhraseWeight* o); + }; + friend class PhraseWeight; + protected: + Weight* _createWeight(Searcher* searcher); + PhraseQuery(const PhraseQuery& clone); + public: + //Constructor + PhraseQuery(); + + //Destructor + ~PhraseQuery(); + + //Returns the string "PhraseQuery" + const TCHAR* getQueryName() const; + static const TCHAR* getClassName(); + + //Sets the number of other words permitted between words in query phrase. + //If zero, then this is an exact phrase search. For larger values this works + //like a WITHIN or NEAR operator. + // + //The slop is in fact an edit-distance, where the units correspond to + //moves of terms in the query phrase out of position. For example, to switch + //the order of two words requires two moves (the first move places the words + //atop one another), so to permit re-orderings of phrases, the slop must be + //at least two. + // + //More exact matches are scored higher than sloppier matches, thus search + //results are sorted by exactness. + // + //The slop is zero by default, requiring exact matches. + void setSlop(const int32_t s) { slop = s; } + + //Returns the slop. See setSlop(). + int32_t getSlop() const { return slop; } + + //Adds a term to the end of the query phrase. + void add(CL_NS(index)::Term* term); + void add(CL_NS(index)::Term* term, int32_t position); + + + + //Returns the sum of squared weights + qreal sumOfSquaredWeights(Searcher* searcher); + + //Normalizes the Weight + void normalize(const qreal norm); + + Scorer* scorer(CL_NS(index)::IndexReader* reader); + + //added by search highlighter + CL_NS(index)::Term** getTerms() const; + _CL_DEPRECATED( deleteDocuments ) int32_t* getPositions() const; ///@deprecated. use getPositions(Array& result) + void getPositions(Array& result) const; + const TCHAR* getFieldName() const{ return field; } + + //Prints a user-readable version of this query. + TCHAR* toString(const TCHAR* f) const; + + Query* clone() const; + bool equals(CL_NS(search)::Query *) const; + + size_t hashCode() const; + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/PhraseQueue.h b/3rdparty/clucene/src/CLucene/search/PhraseQueue.h new file mode 100644 index 000000000..c0682fcaf --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/PhraseQueue.h @@ -0,0 +1,36 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_PriorityQueue_ +#define _lucene_search_PriorityQueue_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/util/PriorityQueue.h" +#include "PhrasePositions.h" + +CL_NS_DEF(search) + class PhraseQueue: public CL_NS(util)::PriorityQueue > { + public: + PhraseQueue(const int32_t size) { + initialize(size,false); + } + ~PhraseQueue(){ + } + + protected: + bool lessThan(PhrasePositions* pp1, PhrasePositions* pp2) { + if (pp1->doc == pp2->doc) + return pp1->position < pp2->position; + else + return pp1->doc < pp2->doc; + } + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/PhraseScorer.cpp b/3rdparty/clucene/src/CLucene/search/PhraseScorer.cpp new file mode 100644 index 000000000..b2da2316a --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/PhraseScorer.cpp @@ -0,0 +1,225 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "PhraseScorer.h" + +#include "PhraseQueue.h" +#include "PhrasePositions.h" +#include "Scorer.h" +#include "Similarity.h" + +CL_NS_USE(index) +CL_NS_USE(util) +CL_NS_DEF(search) + + + PhraseScorer::PhraseScorer(Weight* weight, TermPositions** tps, + int32_t* positions, Similarity* similarity, uint8_t* norms): + Scorer(similarity) + { + //Func - Constructor + //Pre - tps != NULL and is an array of TermPositions + // tpsLength >= 0 + // n != NULL + //Post - The instance has been created + + CND_PRECONDITION(tps != NULL,"tps is NULL"); + + //norms are only used if phraseFreq returns more than 0.0 + //phraseFreq should only return more than 0.0 if norms != NULL + //CND_PRECONDITION(n != NULL,"n is NULL"); + + firstTime = true; + more = true; + this->norms = norms; + this->weight = weight; + this->value = weight->getValue(); + + //reset internal pointers + first = NULL; + last = NULL; + + //use pq to build a sorted list of PhrasePositions + int32_t i = 0; + while(tps[i] != NULL){ + PhrasePositions *pp = _CLNEW PhrasePositions(tps[i], positions[i]); + CND_CONDITION(pp != NULL,"Could not allocate memory for pp"); + + //Store PhrasePos into the PhrasePos pq + if (last != NULL) { // add next to end of list + last->_next = pp; + } else + first = pp; + last = pp; + + i++; + } + + pq = _CLNEW PhraseQueue(i); //i==tps.length + CND_CONDITION(pq != NULL,"Could not allocate memory for pq"); + } + + PhraseScorer::~PhraseScorer() { + //Func - Destructor + //Pre - true + //Post - The instance has been destroyed + + //The PhraseQueue pq (which is a PriorityQueue) pq is actually empty at present, the elements + //having been transferred by pqToList() to the linked list starting with + //first. The nodes of that linked list are deleted by the destructor of + //first, rather than the destructor of pq. + _CLDELETE(first); + _CLDELETE(pq); + } + + bool PhraseScorer::next(){ + if (firstTime) { + init(); + firstTime = false; + } else if (more) { + more = last->next(); // trigger further scanning + } + return doNext(); + } + + // next without initial increment + bool PhraseScorer::doNext() { + while (more) { + while (more && first->doc < last->doc) { // find doc w/ all the terms + more = first->skipTo(last->doc); // skip first upto last + firstToLast(); // and move it to the end + } + + if (more) { + // found a doc with all of the terms + freq = phraseFreq(); // check for phrase + if (freq == 0.0f) // no match + more = last->next(); // trigger further scanning + else + return true; // found a match + } + } + return false; // no more matches + } + + qreal PhraseScorer::score(){ + //System.out.println("scoring " + first.doc); + qreal raw = getSimilarity()->tf(freq) * value; // raw score + return raw * Similarity::decodeNorm(norms[first->doc]); // normalize + } + + bool PhraseScorer::skipTo(int32_t target) { + for (PhrasePositions* pp = first; more && pp != NULL; pp = pp->_next) { + more = pp->skipTo(target); + } + if (more) + sort(); // re-sort + return doNext(); + } + + void PhraseScorer::init() { + for (PhrasePositions* pp = first; more && pp != NULL; pp = pp->_next) + more = pp->next(); + if(more) + sort(); + } + + void PhraseScorer::sort() { + pq->clear(); + for (PhrasePositions* pp = first; pp != NULL; pp = pp->_next) + pq->put(pp); + pqToList(); + } + + + + void PhraseScorer::pqToList(){ + //Func - Transfers the PhrasePositions from the PhraseQueue pq to + // the PhrasePositions list with first as its first element + //Pre - pq != NULL + // first = NULL + // last = NULL + //Post - All PhrasePositions have been transfered to the list + // of PhrasePositions of which the first element is pointed to by first + // and the last element is pointed to by last + + CND_PRECONDITION(pq != NULL,"pq is NULL"); + + last = first = NULL; + + PhrasePositions* PhrasePos = NULL; + + //As long pq is not empty + while (pq->top() != NULL){ + //Pop a PhrasePositions instance + PhrasePos = pq->pop(); + + // add next to end of list + if (last != NULL) { + last->_next = PhrasePos; + } else { + first = PhrasePos; + } + + //Let last point to the new last PhrasePositions instance just added + last = PhrasePos; + //Reset the next of last to NULL + last->_next = NULL; + } + + //Check to see that pq is empty now + CND_CONDITION(pq->size()==0, "pq is not empty while it should be"); + } + + void PhraseScorer::firstToLast(){ + //Func - Moves first to the end of the list + //Pre - first is NULL or points to an PhrasePositions Instance + // last is NULL or points to an PhrasePositions Instance + // first and last both are NULL or both are not NULL + //Post - The first element has become the last element in the list + + CND_PRECONDITION(((first==NULL && last==NULL) ||(first !=NULL && last != NULL)), + "Either first or last is NULL but not both"); + + //Check if first and last are valid pointers + if(first && last){ + last->_next = first; + last = first; + first = first->_next; + last->_next = NULL; + } + } + + + void PhraseScorer::explain(int32_t _doc, Explanation* tfExplanation) { + while (next() && doc() < _doc){ + } + + qreal phraseFreq = (doc() == _doc) ? freq : 0.0f; + tfExplanation->setValue(getSimilarity()->tf(phraseFreq)); + + StringBuffer buf; + buf.append(_T("tf(phraseFreq=")); + buf.appendFloat(phraseFreq,2); + buf.append(_T(")")); + tfExplanation->setDescription(buf.getBuffer()); + } + + TCHAR* PhraseScorer::toString() { + StringBuffer buf; + buf.append(_T("scorer(")); + + TCHAR* tmp = weight->toString(); + buf.append(tmp); + _CLDELETE_CARRAY(tmp); + + buf.append(_T(")")); + + return buf.toString(); + } + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/PhraseScorer.h b/3rdparty/clucene/src/CLucene/search/PhraseScorer.h new file mode 100644 index 000000000..89f7a1fbb --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/PhraseScorer.h @@ -0,0 +1,65 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_PhraseScorer_ +#define _lucene_search_PhraseScorer_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "PhraseQueue.h" +#include "PhrasePositions.h" +#include "Scorer.h" +#include "Similarity.h" + +CL_NS_DEF(search) + + class PhraseScorer: public Scorer { + private: + Weight* weight; + qreal freq; + bool firstTime; + bool more; + + protected: + uint8_t* norms; + qreal value; + + PhraseQueue* pq; //is used to order the list point to by first and last + PhrasePositions* first; //Points to the first in the list of PhrasePositions + PhrasePositions* last; //Points to the last in the list of PhrasePositions + + public: + //Constructor + PhraseScorer(Weight* weight, CL_NS(index)::TermPositions** tps, + int32_t* positions, Similarity* similarity, uint8_t* norms); + virtual ~PhraseScorer(); + + int32_t doc() const { return first->doc; } + bool next(); + qreal score(); + bool skipTo(int32_t target); + + + void explain(int32_t doc, Explanation* ret); + TCHAR* toString(); + protected: + virtual qreal phraseFreq() =0; + + //Transfers the PhrasePositions from the PhraseQueue pq to + //the PhrasePositions list with first as its first element + void pqToList(); + + //Moves first to the end of the list + void firstToLast(); + private: + bool doNext(); + void init(); + void sort(); + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/PrefixQuery.cpp b/3rdparty/clucene/src/CLucene/search/PrefixQuery.cpp new file mode 100644 index 000000000..6bb27d1ca --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/PrefixQuery.cpp @@ -0,0 +1,273 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "PrefixQuery.h" +#include "CLucene/util/BitSet.h" + +CL_NS_USE(util) +CL_NS_USE(index) +CL_NS_DEF(search) + + PrefixQuery::PrefixQuery(Term* Prefix){ + //Func - Constructor. + // Constructs a query for terms starting with prefix + //Pre - Prefix != NULL + //Post - The instance has been created + + //Get a pointer to Prefix + prefix = _CL_POINTER(Prefix); + } + + PrefixQuery::PrefixQuery(const PrefixQuery& clone):Query(clone){ + prefix = _CL_POINTER(clone.prefix); + } + Query* PrefixQuery::clone() const{ + return _CLNEW PrefixQuery(*this); + } + + Term* PrefixQuery::getPrefix(bool pointer){ + if ( pointer ) + return _CL_POINTER(prefix); + else + return prefix; + } + + PrefixQuery::~PrefixQuery(){ + //Func - Destructor + //Pre - true + //Post - The instance has been destroyed. + + //Delete prefix by finalizing it + _CLDECDELETE(prefix); + } + + + /** Returns a hash code value for this object.*/ + size_t PrefixQuery::hashCode() const { + return Similarity::floatToByte(getBoost()) ^ prefix->hashCode(); + } + + const TCHAR* PrefixQuery::getQueryName()const{ + //Func - Returns the name "PrefixQuery" + //Pre - true + //Post - The string "PrefixQuery" has been returned + + return getClassName(); + } + const TCHAR* PrefixQuery::getClassName(){ + //Func - Returns the name "PrefixQuery" + //Pre - true + //Post - The string "PrefixQuery" has been returned + + return _T("PrefixQuery"); + } + + bool PrefixQuery::equals(Query * other) const{ + if (!(other->instanceOf(PrefixQuery::getClassName()))) + return false; + + PrefixQuery* rq = (PrefixQuery*)other; + bool ret = (this->getBoost() == rq->getBoost()) + && (this->prefix->equals(rq->prefix)); + + return ret; + } + + Query* PrefixQuery::rewrite(IndexReader* reader){ + BooleanQuery* query = _CLNEW BooleanQuery(); + TermEnum* enumerator = reader->terms(prefix); + Term* lastTerm = NULL; + try { + const TCHAR* prefixText = prefix->text(); + const TCHAR* prefixField = prefix->field(); + const TCHAR* tmp; + size_t i; + int32_t prefixLen = prefix->textLength(); + do { + lastTerm = enumerator->term(); + if (lastTerm != NULL && lastTerm->field() == prefixField ){ + + //now see if term->text() starts with prefixText + int32_t termLen = lastTerm->textLength(); + if ( prefixLen>termLen ) + break; //the prefix is longer than the term, can't be matched + + tmp = lastTerm->text(); + + //check for prefix match in reverse, since most change will be at the end + for ( i=prefixLen-1;i!=-1;--i ){ + if ( tmp[i] != prefixText[i] ){ + tmp=NULL;//signals inequality + break; + } + } + if ( tmp == NULL ) + break; + + TermQuery* tq = _CLNEW TermQuery(lastTerm); // found a match + tq->setBoost(getBoost()); // set the boost + query->add(tq,true,false, false); // add to query + } else + break; + _CLDECDELETE(lastTerm); + } while (enumerator->next()); + }_CLFINALLY( + enumerator->close(); + _CLDELETE(enumerator); + _CLDECDELETE(lastTerm); + ); + _CLDECDELETE(lastTerm); + + + //if we only added one clause and the clause is not prohibited then + //we can just return the query + if (query->getClauseCount() == 1) { // optimize 1-clause queries + BooleanClause* c=0; + query->getClauses(&c); + + if (!c->prohibited) { // just return clause + c->deleteQuery=false; + Query* ret = c->query; + + _CLDELETE(query); + return ret; + } + } + + return query; + } + + Query* PrefixQuery::combine(Query** queries) { + return Query::mergeBooleanQueries(queries); + } + + TCHAR* PrefixQuery::toString(const TCHAR* field) const{ + //Func - Creates a user-readable version of this query and returns it as as string + //Pre - field != NULL + //Post - a user-readable version of this query has been returned as as string + + //Instantiate a stringbuffer buffer to store the readable version temporarily + CL_NS(util)::StringBuffer buffer; + //check if field equal to the field of prefix + if( field==NULL || _tcscmp(prefix->field(),field) != 0 ) { + //Append the field of prefix to the buffer + buffer.append(prefix->field()); + //Append a colon + buffer.append(_T(":") ); + } + //Append the text of the prefix + buffer.append(prefix->text()); + //Append a wildchar character + buffer.append(_T("*")); + //if the boost factor is not eaqual to 1 + if (getBoost() != 1.0f) { + //Append ^ + buffer.append(_T("^")); + //Append the boost factor + buffer.appendFloat( getBoost(),1); + } + //Convert StringBuffer buffer to TCHAR block and return it + return buffer.toString(); + } + + + + + + + + +PrefixFilter::PrefixFilter( Term* prefix ) +{ + this->prefix = _CL_POINTER(prefix); +} + +PrefixFilter::~PrefixFilter() +{ + _CLDECDELETE(prefix); +} + +PrefixFilter::PrefixFilter( const PrefixFilter& copy ) : + prefix( _CL_POINTER(copy.prefix) ) +{ +} + +Filter* PrefixFilter::clone() const { + return _CLNEW PrefixFilter(*this ); +} + +TCHAR* PrefixFilter::toString() +{ + //Instantiate a stringbuffer buffer to store the readable version temporarily + CL_NS(util)::StringBuffer buffer; + //check if field equal to the field of prefix + if( prefix->field() != NULL ) { + //Append the field of prefix to the buffer + buffer.append(prefix->field()); + //Append a colon + buffer.append(_T(":") ); + } + //Append the text of the prefix + buffer.append(prefix->text()); + buffer.append(_T("*")); + + //Convert StringBuffer buffer to TCHAR block and return it + return buffer.toString(); +} + +/** Returns a BitSet with true for documents which should be permitted in +search results, and false for those that should not. */ +BitSet* PrefixFilter::bits( IndexReader* reader ) +{ + BitSet* bts = _CLNEW BitSet( reader->maxDoc() ); + TermEnum* enumerator = reader->terms(prefix); + TermDocs* docs = reader->termDocs(); + const TCHAR* prefixText = prefix->text(); + const TCHAR* prefixField = prefix->field(); + const TCHAR* tmp; + size_t i; + int32_t prefixLen = prefix->textLength(); + Term* lastTerm = NULL; + + try{ + do{ + lastTerm = enumerator->term(false); + if (lastTerm != NULL && lastTerm->field() == prefixField ){ + //now see if term->text() starts with prefixText + int32_t termLen = lastTerm->textLength(); + if ( prefixLen>termLen ) + break; //the prefix is longer than the term, can't be matched + + tmp = lastTerm->text(); + + //check for prefix match in reverse, since most change will be at the end + for ( i=prefixLen-1;i!=-1;--i ){ + if ( tmp[i] != prefixText[i] ){ + tmp=NULL;//signals inequality + break; + } + } + if ( tmp == NULL ) + break; + + docs->seek(enumerator); + while (docs->next()) { + bts->set(docs->doc()); + } + } + }while(enumerator->next()); + } _CLFINALLY( + docs->close(); + _CLDELETE(docs); + enumerator->close(); + _CLDELETE(enumerator); + ) + + return bts; +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/PrefixQuery.h b/3rdparty/clucene/src/CLucene/search/PrefixQuery.h new file mode 100644 index 000000000..8e3f41352 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/PrefixQuery.h @@ -0,0 +1,75 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_PrefixQuery +#define _lucene_search_PrefixQuery +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/index/Term.h" +#include "CLucene/index/Terms.h" +#include "CLucene/index/IndexReader.h" +#include "SearchHeader.h" +#include "BooleanQuery.h" +#include "TermQuery.h" +#include "CLucene/util/StringBuffer.h" + +CL_NS_DEF(search) + //PrefixQuery is a Query that matches documents containing terms with a specified prefix. + + class PrefixQuery: public Query { + private: + CL_NS(index)::Term* prefix; + protected: + PrefixQuery(const PrefixQuery& clone); + public: + + //Constructor. Constructs a query for terms starting with prefix + PrefixQuery(CL_NS(index)::Term* Prefix); + + //Destructor + ~PrefixQuery(); + + //Returns the name "PrefixQuery" + const TCHAR* getQueryName() const; + static const TCHAR* getClassName(); + + /** Returns the prefix of this query. */ + CL_NS(index)::Term* getPrefix(bool pointer=true); + + Query* combine(Query** queries); + Query* rewrite(CL_NS(index)::IndexReader* reader); + Query* clone() const; + bool equals(Query * other) const; + + //Creates a user-readable version of this query and returns it as as string + TCHAR* toString(const TCHAR* field) const; + + size_t hashCode() const; + }; + + + class PrefixFilter: public Filter + { + private: + CL_NS(index)::Term* prefix; + protected: + PrefixFilter( const PrefixFilter& copy ); + + public: + PrefixFilter(CL_NS(index)::Term* prefix); + ~PrefixFilter(); + + /** Returns a BitSet with true for documents which should be permitted in + search results, and false for those that should not. */ + CL_NS(util)::BitSet* bits( CL_NS(index)::IndexReader* reader ); + + Filter* clone() const; + TCHAR* toString(); + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/QueryFilter.cpp b/3rdparty/clucene/src/CLucene/search/QueryFilter.cpp new file mode 100644 index 000000000..2dbe2d7cd --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/QueryFilter.cpp @@ -0,0 +1,73 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "QueryFilter.h" +#include "IndexSearcher.h" + +CL_NS_DEF(search) +CL_NS_USE(util) +CL_NS_USE(index) + + +QueryFilter::QueryFilter( const Query* query ) +{ + this->query = query->clone(); +} + + +QueryFilter::~QueryFilter() +{ + _CLDELETE( query ); +} + + +QueryFilter::QueryFilter( const QueryFilter& copy ) +{ + this->query = copy.query->clone(); +} + + +Filter* QueryFilter::clone() const { + return _CLNEW QueryFilter(*this ); +} + + +TCHAR* QueryFilter::toString() +{ + TCHAR* qt = query->toString(); + size_t len = _tcslen(qt) + 14; + TCHAR* ret = _CL_NEWARRAY( TCHAR, len ); + ret[0] = 0; + _sntprintf( ret, len, _T("QueryFilter(%s)"), qt ); + _CLDELETE_CARRAY(qt); + return ret; +} + + +/** Returns a BitSet with true for documents which should be permitted in +search results, and false for those that should not. */ +BitSet* QueryFilter::bits( IndexReader* reader ) +{ + BitSet* bits = _CLNEW BitSet(reader->maxDoc()); + + IndexSearcher s(reader); + QFHitCollector hc(bits); + s._search(query, NULL, &hc); + return bits; +} + + +QueryFilter::QFHitCollector::QFHitCollector(CL_NS(util)::BitSet* bits){ + this->bits = bits; +} + +void QueryFilter::QFHitCollector::collect(const int32_t doc, const qreal score) { + bits->set(doc); // set bit for hit +} + + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/QueryFilter.h b/3rdparty/clucene/src/CLucene/search/QueryFilter.h new file mode 100644 index 000000000..8d423b2f7 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/QueryFilter.h @@ -0,0 +1,44 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_QueryFilter_ +#define _lucene_search_QueryFilter_ + +#include "CLucene/util/BitSet.h" +#include "CLucene/index/IndexReader.h" +#include "SearchHeader.h" +#include "CachingWrapperFilter.h" + +CL_NS_DEF(search) + +class QueryFilter: public Filter +{ +private: + Query* query; + + class QFHitCollector: public HitCollector{ + CL_NS(util)::BitSet* bits; + public: + QFHitCollector(CL_NS(util)::BitSet* bits); + void collect(const int32_t doc, const qreal score); + }; + +protected: + QueryFilter( const QueryFilter& copy ); +public: + QueryFilter( const Query* query ); + + ~QueryFilter(); + + CL_NS(util)::BitSet* bits( CL_NS(index)::IndexReader* reader ); + + Filter *clone() const; + + TCHAR *toString(); +}; + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/RangeFilter.cpp b/3rdparty/clucene/src/CLucene/search/RangeFilter.cpp new file mode 100644 index 000000000..66ee5ce55 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/RangeFilter.cpp @@ -0,0 +1,150 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "RangeFilter.h" + +CL_NS_DEF(search) +CL_NS_USE(index) +CL_NS_USE(util) +CL_NS_USE(document) + + +RangeFilter::RangeFilter( const TCHAR* fieldName, const TCHAR* lowerTerm, const TCHAR* upperTerm, bool includeLower, bool includeUpper ) +{ + this->field = STRDUP_TtoT(fieldName); + if ( lowerTerm != NULL ) + this->lowerValue = STRDUP_TtoT(lowerTerm); + else + this->lowerValue = NULL; + if ( upperTerm != NULL ) + this->upperValue = STRDUP_TtoT(upperTerm); + else + this->upperValue = NULL; + this->includeLower = includeLower; + this->includeUpper = includeUpper; +} + + +/** + * Constructs a filter for field fieldName matching + * less than or equal to upperTerm. + */ +RangeFilter* RangeFilter::Less( TCHAR* fieldName, TCHAR* upperTerm ) { + return new RangeFilter( fieldName, NULL, upperTerm, false, true ); +} + + +/** +* Constructs a filter for field fieldName matching +* more than or equal to lowerTerm. +*/ +RangeFilter* RangeFilter::More( TCHAR* fieldName, TCHAR* lowerTerm ) { + return new RangeFilter( fieldName, lowerTerm, NULL, true, false ); +} + + +RangeFilter::~RangeFilter() +{ + _CLDELETE_CARRAY( lowerValue ); + _CLDELETE_CARRAY( field ); + _CLDELETE_CARRAY( upperValue ); +} + + +RangeFilter::RangeFilter( const RangeFilter& copy ) : + field( STRDUP_TtoT(copy.field) ), + lowerValue( STRDUP_TtoT(copy.lowerValue) ), + upperValue( STRDUP_TtoT(copy.upperValue) ), + includeLower( copy.includeLower ), + includeUpper( copy.includeUpper ) +{ +} + + +Filter* RangeFilter::clone() const { + return _CLNEW RangeFilter(*this ); +} + + +TCHAR* RangeFilter::toString() +{ + size_t len = (field ? _tcslen(field) : 0) + (lowerValue ? _tcslen(lowerValue) : 0) + (upperValue ? _tcslen(upperValue) : 0) + 8; + TCHAR* ret = _CL_NEWARRAY( TCHAR, len ); + ret[0] = 0; + _sntprintf( ret, len, _T("%s: [%s-%s]"), field, (lowerValue?lowerValue:_T("")), (upperValue?upperValue:_T("")) ); + + return ret; +} + + +/** Returns a BitSet with true for documents which should be permitted in +search results, and false for those that should not. */ +BitSet* RangeFilter::bits( IndexReader* reader ) +{ + BitSet* bts = _CLNEW BitSet( reader->maxDoc() ); + Term* term = NULL; + + Term* t = _CLNEW Term( field, (lowerValue ? lowerValue : _T("")), false ); + TermEnum* enumerator = reader->terms( t ); // get enumeration of all terms after lowerValue + _CLDECDELETE( t ); + + if( enumerator->term(false) == NULL ) { + _CLDELETE( enumerator ); + return bts; + } + + bool checkLower = false; + if( !includeLower ) // make adjustments to set to exclusive + checkLower = true; + + TermDocs* termDocs = reader->termDocs(); + + try + { + do + { + term = enumerator->term(); + + if( term == NULL || _tcscmp(term->field(), field) ) + break; + + if( !checkLower || lowerValue == NULL || _tcscmp(term->text(), lowerValue) > 0 ) + { + checkLower = false; + if( upperValue != NULL ) + { + int compare = _tcscmp( upperValue, term->text() ); + + /* if beyond the upper term, or is exclusive and + * this is equal to the upper term, break out */ + if( (compare < 0) || (!includeUpper && compare == 0) ) + break; + } + + termDocs->seek( enumerator->term(false) ); + while( termDocs->next() ) { + bts->set( termDocs->doc() ); + } + } + + _CLDECDELETE( term ); + } + while( enumerator->next() ); + } + _CLFINALLY + ( + _CLDECDELETE( term ); + termDocs->close(); + _CLVDELETE( termDocs ); + enumerator->close(); + _CLDELETE( enumerator ); + ); + + return bts; +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/RangeFilter.h b/3rdparty/clucene/src/CLucene/search/RangeFilter.h new file mode 100644 index 000000000..0865e356f --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/RangeFilter.h @@ -0,0 +1,51 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ + +#ifndef _lucene_search_RangeFilter_ +#define _lucene_search_RangeFilter_ + +#include "CLucene/document/DateField.h" +#include "CLucene/index/Term.h" +#include "CLucene/index/Terms.h" +#include "CLucene/index/IndexReader.h" +#include "CLucene/util/BitSet.h" +#include "CLucene/search/Filter.h" + +CL_NS_DEF(search) + +class RangeFilter: public Filter +{ +private: + const TCHAR* field; + TCHAR* lowerValue; + TCHAR* upperValue; + bool includeLower; + bool includeUpper; + +protected: + RangeFilter( const RangeFilter& copy ); + +public: + RangeFilter( const TCHAR* fieldName, const TCHAR* lowerValue, const TCHAR* upperValue, bool includeLower, bool includeUpper ); + + static RangeFilter* Less( TCHAR* fieldName, TCHAR* upperTerm ); + + static RangeFilter* More( TCHAR* fieldName, TCHAR* lowerTerm ); + + ~RangeFilter(); + + /** Returns a BitSet with true for documents which should be permitted in + search results, and false for those that should not. */ + CL_NS(util)::BitSet* bits( CL_NS(index)::IndexReader* reader ); + + Filter* clone() const; + + TCHAR* toString(); +}; + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/RangeQuery.cpp b/3rdparty/clucene/src/CLucene/search/RangeQuery.cpp new file mode 100644 index 000000000..4fc242089 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/RangeQuery.cpp @@ -0,0 +1,204 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "RangeQuery.h" + +#include "SearchHeader.h" +#include "Scorer.h" +#include "BooleanQuery.h" +#include "TermQuery.h" + +#include "CLucene/index/Term.h" +#include "CLucene/index/Terms.h" +#include "CLucene/index/IndexReader.h" +#include "CLucene/util/StringBuffer.h" + + +CL_NS_USE(index) +CL_NS_USE(util) +CL_NS_DEF(search) + + RangeQuery::RangeQuery(Term* lowerTerm, Term* upperTerm, const bool Inclusive){ + //Func - Constructor + //Pre - (LowerTerm != NULL OR UpperTerm != NULL) AND + // if LowerTerm and UpperTerm are valid pointer then the fieldnames must be the same + //Post - The instance has been created + + if (lowerTerm == NULL && upperTerm == NULL) + { + _CLTHROWA(CL_ERR_IllegalArgument,"At least one term must be non-null"); + } + if (lowerTerm != NULL && upperTerm != NULL && lowerTerm->field() != upperTerm->field()) + { + _CLTHROWA(CL_ERR_IllegalArgument,"Both terms must be for the same field"); + } + + // if we have a lowerTerm, start there. otherwise, start at beginning + if (lowerTerm != NULL) { + this->lowerTerm = _CL_POINTER(lowerTerm); + } + else { + this->lowerTerm = _CLNEW Term(upperTerm, LUCENE_BLANK_STRING); + } + this->upperTerm = (upperTerm != NULL ? _CL_POINTER(upperTerm) : NULL); + this->inclusive = Inclusive; + } + RangeQuery::RangeQuery(const RangeQuery& clone): + Query(clone){ + this->inclusive = clone.inclusive; + this->upperTerm = (clone.upperTerm != NULL ? _CL_POINTER(clone.upperTerm) : NULL ); + this->lowerTerm = (clone.lowerTerm != NULL ? _CL_POINTER(clone.lowerTerm) : NULL ); + } + Query* RangeQuery::clone() const{ + return _CLNEW RangeQuery(*this); + } + + RangeQuery::~RangeQuery() { + //Func - Destructor + //Pre - true + //Post - The instance has been destroyed + + _CLDECDELETE(lowerTerm); + _CLDECDELETE(upperTerm); + } + + /** Returns a hash code value for this object.*/ + size_t RangeQuery::hashCode() const { + return Similarity::floatToByte(getBoost()) ^ + (lowerTerm != NULL ? lowerTerm->hashCode() : 0) ^ + (upperTerm != NULL ? upperTerm->hashCode() : 0) ^ + (this->inclusive ? 1 : 0); + } + + const TCHAR* RangeQuery::getQueryName() const{ + return getClassName(); + } + const TCHAR* RangeQuery::getClassName(){ + return _T("RangeQuery"); + } + + Query* RangeQuery::combine(Query** queries) { + return Query::mergeBooleanQueries(queries); + } + + bool RangeQuery::equals(Query * other) const{ + if (!(other->instanceOf(RangeQuery::getClassName()))) + return false; + + RangeQuery* rq = (RangeQuery*)other; + bool ret = (this->getBoost() == rq->getBoost()) + && (this->isInclusive() == rq->isInclusive()) + && (this->getLowerTerm()->equals(rq->getLowerTerm())) + && (this->getUpperTerm()->equals(rq->getUpperTerm())); + + return ret; + } + + + /** + * FIXME: Describe rewrite method here. + * + * @param reader an IndexReader value + * @return a Query value + * @exception IOException if an error occurs + */ + Query* RangeQuery::rewrite(IndexReader* reader){ + + BooleanQuery* query = _CLNEW BooleanQuery; + TermEnum* enumerator = reader->terms(lowerTerm); + Term* lastTerm = NULL; + try { + bool checkLower = false; + if (!inclusive) // make adjustments to set to exclusive + checkLower = true; + + const TCHAR* testField = getField(); + do { + lastTerm = enumerator->term(); + if (lastTerm != NULL && lastTerm->field() == testField ) { + if (!checkLower || _tcscmp(lastTerm->text(),lowerTerm->text()) > 0) { + checkLower = false; + if (upperTerm != NULL) { + int compare = _tcscmp(upperTerm->text(),lastTerm->text()); + /* if beyond the upper term, or is exclusive and + * this is equal to the upper term, break out */ + if ((compare < 0) || (!inclusive && compare == 0)) + break; + } + TermQuery* tq = _CLNEW TermQuery(lastTerm); // found a match + tq->setBoost(getBoost()); // set the boost + query->add(tq, true, false, false); // add to query + } + }else { + break; + } + _CLDECDELETE(lastTerm); + } + while (enumerator->next()); + }catch(...){ + _CLDECDELETE(lastTerm); //always need to delete this + _CLDELETE(query); //in case of error, delete the query + enumerator->close(); + _CLDELETE(enumerator); + throw; //rethrow + } + _CLDECDELETE(lastTerm); //always need to delete this + enumerator->close(); + _CLDELETE(enumerator); + + return query; + } + + /** Prints a user-readable version of this query. */ + TCHAR* RangeQuery::toString(const TCHAR* field) const + { + StringBuffer buffer; + if ( field==NULL || _tcscmp(getField(),field)!=0 ) + { + buffer.append( getField() ); + buffer.append( _T(":")); + } + buffer.append(inclusive ? _T("[") : _T("{")); + buffer.append(lowerTerm != NULL ? lowerTerm->text() : _T("NULL")); + buffer.append(_T(" TO ")); + buffer.append(upperTerm != NULL ? upperTerm->text() : _T("NULL")); + buffer.append(inclusive ? _T("]") : _T("}")); + if (getBoost() != 1.0f) + { + buffer.append( _T("^")); + buffer.appendFloat( getBoost(),1 ); + } + return buffer.toString(); + } + + + const TCHAR* RangeQuery::getField() const + { + return (lowerTerm != NULL ? lowerTerm->field() : upperTerm->field()); + } + + /** Returns the lower term of this range query */ + Term* RangeQuery::getLowerTerm(bool pointer) const { + if ( pointer ) + return _CL_POINTER(lowerTerm); + else + return lowerTerm; + } + + /** Returns the upper term of this range query */ + Term* RangeQuery::getUpperTerm(bool pointer) const { + if ( pointer ) + return _CL_POINTER(upperTerm); + else + return upperTerm; + } + + /** Returns true if the range query is inclusive */ + bool RangeQuery::isInclusive() const { return inclusive; } + + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/RangeQuery.h b/3rdparty/clucene/src/CLucene/search/RangeQuery.h new file mode 100644 index 000000000..9a7733c33 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/RangeQuery.h @@ -0,0 +1,71 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_RangeQuery_ +#define _lucene_search_RangeQuery_ +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "SearchHeader.h" +#include "Scorer.h" +#include "TermQuery.h" + +#include "CLucene/index/Term.h" +#include "CLucene/index/Terms.h" + +#include "CLucene/util/StringBuffer.h" + + +CL_NS_DEF(search) + /** Constructs a query selecting all terms greater than + * lowerTerm but less than upperTerm. + * There must be at least one term and either term may be null, + * in which case there is no bound on that side, but if there are + * two terms, both terms must be for the same field. + */ + class RangeQuery: public Query + { + private: + CL_NS(index)::Term* lowerTerm; + CL_NS(index)::Term* upperTerm; + bool inclusive; + protected: + RangeQuery(const RangeQuery& clone); + + public: + // Constructs a query selecting all terms greater than + // lowerTerm but less than upperTerm. + // There must be at least one term and either term may be NULL-- + // in which case there is no bound on that side, but if there are + // two term, both terms must be for the same field. + RangeQuery(CL_NS(index)::Term* LowerTerm, CL_NS(index)::Term* UpperTerm, const bool Inclusive); + ~RangeQuery(); + + const TCHAR* getQueryName() const; + static const TCHAR* getClassName(); + + Query* rewrite(CL_NS(index)::IndexReader* reader); + + Query* combine(Query** queries); + + // Prints a user-readable version of this query. + TCHAR* toString(const TCHAR* field) const; + + Query* clone() const; + + bool equals(Query * other) const; + + CL_NS(index)::Term* getLowerTerm(bool pointer=true) const; + CL_NS(index)::Term* getUpperTerm(bool pointer=true) const; + bool isInclusive() const; + const TCHAR* getField() const; + + size_t hashCode() const; + }; + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/Scorer.h b/3rdparty/clucene/src/CLucene/search/Scorer.h new file mode 100644 index 000000000..0d1d4355a --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/Scorer.h @@ -0,0 +1,80 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_Scorer_ +#define _lucene_search_Scorer_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "Similarity.h" +#include "SearchHeader.h" +#include "Explanation.h" + +CL_NS_DEF(search) + /** Expert: Implements scoring for a class of queries. */ +class Scorer: LUCENE_BASE { + private: + Similarity* similarity; + protected: + /** Constructs a Scorer. */ + Scorer(Similarity* similarity) { + this->similarity = similarity; + } + public: + virtual ~Scorer(){ + } + + /** Returns the Similarity implementation used by this scorer. */ + Similarity* getSimilarity() const{ + return this->similarity; + } + + /** Scores all documents and passes them to a collector. */ + void score(HitCollector* hc) { + while (next()) { + hc->collect(doc(), score()); + } + } + + /** Advance to the next document matching the query. Returns true iff there + * is another match. */ + virtual bool next() = 0; + + /** Returns the current document number. Initially invalid, until {@link + * #next()} is called the first time. */ + virtual int32_t doc() const = 0; + + /** Returns the score of the current document. Initially invalid, until + * {@link #next()} is called the first time. */ + virtual qreal score() = 0; + + /** Skips to the first match beyond the current whose document number is + * greater than or equal to target.

Returns true iff there is such + * a match.

Behaves as if written:

+         *   boolean skipTo(int32_t target) {
+         *     do {
+         *       if (!next())
+         * 	     return false;
+         *     } while (target > doc());
+         *     return true;
+         *   }
+         * 
+ * Most implementations are considerably more efficient than that. + */ + virtual bool skipTo(int32_t target) = 0; + + /** Returns an explanation of the score for doc. */ + virtual void explain(int32_t doc, Explanation* ret) = 0; + + + /** Returns an string which explains the object */ + virtual TCHAR* toString() = 0; + + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/SearchHeader.cpp b/3rdparty/clucene/src/CLucene/search/SearchHeader.cpp new file mode 100644 index 000000000..56e4ad585 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/SearchHeader.cpp @@ -0,0 +1,141 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "SearchHeader.h" +#include "BooleanQuery.h" +#include "FieldDocSortedHitQueue.h" + +CL_NS_USE(index) +CL_NS_DEF(search) + +CL_NS(document)::Document* Searchable::doc(const int32_t i){ + CL_NS(document)::Document* ret = _CLNEW CL_NS(document)::Document; + if (!doc(i,ret) ) + _CLDELETE(ret); + return ret; +} + +//static +Query* Query::mergeBooleanQueries(Query** queries) { + CL_NS(util)::CLVector allClauses; + int32_t i = 0; + while ( queries[i] != NULL ){ + BooleanQuery* bq = (BooleanQuery*)queries[i]; + + int32_t size = bq->getClauseCount(); + BooleanClause** clauses = _CL_NEWARRAY(BooleanClause*, size); + bq->getClauses(clauses); + + for (int32_t j = 0;j::iterator itr = allClauses.begin(); + while (itr != allClauses.end() ) { + result->add(*itr); + } + return result; +} + +Query::Query(const Query& clone):boost(clone.boost){ + //constructor +} +Weight* Query::_createWeight(Searcher* searcher){ + _CLTHROWA(CL_ERR_UnsupportedOperation,"UnsupportedOperationException: Query::_createWeight"); +} + +Query::Query(): + boost(1.0f) +{ + //constructor +} +Query::~Query(){ +} + +/** Expert: called to re-write queries into primitive queries. */ +Query* Query::rewrite(CL_NS(index)::IndexReader* reader){ + return this; +} + +Query* Query::combine(Query** queries){ + _CLTHROWA(CL_ERR_UnsupportedOperation,"UnsupportedOperationException: Query::combine"); +} +Similarity* Query::getSimilarity(Searcher* searcher) { + return searcher->getSimilarity(); +} +bool Query::instanceOf(const TCHAR* other) const{ + const TCHAR* t = getQueryName(); + if ( t==other || _tcscmp( t, other )==0 ) + return true; + else + return false; +} +TCHAR* Query::toString() const{ + return toString(LUCENE_BLANK_STRING); +} + +void Query::setBoost(qreal b) { boost = b; } + +qreal Query::getBoost() const { return boost; } + +Weight* Query::weight(Searcher* searcher){ + Query* query = searcher->rewrite(this); + Weight* weight = query->_createWeight(searcher); + qreal sum = weight->sumOfSquaredWeights(); + qreal norm = getSimilarity(searcher)->queryNorm(sum); + weight->normalize(norm); + return weight; +} + +TopFieldDocs::TopFieldDocs (int32_t totalHits, FieldDoc** fieldDocs, int32_t scoreDocsLen, SortField** fields): + TopDocs (totalHits, NULL, scoreDocsLen) +{ + this->fields = fields; + this->fieldDocs = fieldDocs; + this->scoreDocs = _CL_NEWARRAY(ScoreDoc,scoreDocsLen); + for (int32_t i=0;iscoreDocs[i] = this->fieldDocs[i]->scoreDoc; +} +TopFieldDocs::~TopFieldDocs(){ + if ( fieldDocs ){ + for (int32_t i=0;i= 0 +//Post - The instance has been created + +} + +TopDocs::~TopDocs(){ +//Func - Destructor +//Pre - true +//Post - The instance has been destroyed + + _CLDELETE_ARRAY(scoreDocs); +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/SearchHeader.h b/3rdparty/clucene/src/CLucene/search/SearchHeader.h new file mode 100644 index 000000000..4a896a5c5 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/SearchHeader.h @@ -0,0 +1,456 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_SearchHeader_ +#define _lucene_search_SearchHeader_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/index/IndexReader.h" +#include "CLucene/index/Term.h" +#include "Filter.h" +#include "CLucene/document/Document.h" +#include "Sort.h" +#include "CLucene/util/VoidList.h" +#include "Explanation.h" +#include "Similarity.h" + +CL_NS_DEF(search) + + //predefine classes + class Scorer; + class Query; + class Hits; + class Sort; + class FieldDoc; + class TopFieldDocs; + + /** Expert: Returned by low-level search implementations. + * @see TopDocs */ + struct ScoreDoc { + /** Expert: A hit document's number. + * @see Searcher#doc(int32_t) + */ + int32_t doc; + + /** Expert: The score of this document for the query. */ + qreal score; + }; + + /** Expert: Returned by low-level search implementations. + * @see Searcher#search(Query,Filter,int32_t) */ + class TopDocs:LUCENE_BASE { + public: + /** Expert: The total number of hits for the query. + * @see Hits#length() + */ + int32_t totalHits; + + /** Expert: The top hits for the query. */ + ScoreDoc* scoreDocs; + int32_t scoreDocsLength; + + /** Expert: Constructs a TopDocs. TopDocs takes ownership of the ScoreDoc array*/ + TopDocs(const int32_t th, ScoreDoc* sds, int32_t scoreDocsLength); + ~TopDocs(); + }; + + // Lower-level search API. + // @see Searcher#search(Query,HitCollector) + class HitCollector: LUCENE_BASE { + public: + /** Called once for every non-zero scoring document, with the document number + * and its score. + * + *

If, for example, an application wished to collect all of the hits for a + * query in a BitSet, then it might:

+      *   Searcher searcher = new IndexSearcher(indexReader);
+      *   final BitSet bits = new BitSet(indexReader.maxDoc());
+      *   searcher.search(query, new HitCollector() {
+      *       public void collect(int32_t doc, float score) {
+      *         bits.set(doc);
+      *       }
+      *     });
+      * 
+ * + *

Note: This is called in an inner search loop. For good search + * performance, implementations of this method should not call + * {@link Searcher#doc(int32_t)} or + * {@link IndexReader#document(int32_t)} on every + * document number encountered. Doing so can slow searches by an order + * of magnitude or more. + *

Note: The score passed to this method is a raw score. + * In other words, the score will not necessarily be a float whose value is + * between 0 and 1. + */ + virtual void collect(const int32_t doc, const qreal score) = 0; + virtual ~HitCollector(){} + }; + + /** Expert: Calculate query weights and build query scorers. + * + *

A Weight is constructed by a query, given a Searcher ({@link + * Query#_createWeight(Searcher)}). The {@link #sumOfSquaredWeights()} method + * is then called on the top-level query to compute the query normalization + * factor (@link Similarity#queryNorm(qreal)}). This factor is then passed to + * {@link #normalize(qreal)}. At this point the weighting is complete and a + * scorer may be constructed by calling {@link #scorer(IndexReader)}. + */ + class Weight: LUCENE_BASE { + public: + virtual ~Weight(){ + }; + + /** The query that this concerns. */ + virtual Query* getQuery() = 0; + + /** The weight for this query. */ + virtual qreal getValue() = 0; + + /** The sum of squared weights of contained query clauses. */ + virtual qreal sumOfSquaredWeights() = 0; + + /** Assigns the query normalization factor to this. */ + virtual void normalize(qreal norm) = 0; + + /** Constructs a scorer for this. */ + virtual Scorer* scorer(CL_NS(index)::IndexReader* reader) = 0; + + /** An explanation of the score computation for the named document. */ + virtual void explain(CL_NS(index)::IndexReader* reader, int32_t doc, Explanation* ret) = 0; + + virtual TCHAR* toString(){ + return STRDUP_TtoT(_T("Weight")); + } + }; + + class HitDoc:LUCENE_BASE { + public: + qreal score; + int32_t id; + CL_NS(document)::Document* doc; + + HitDoc* next; // in doubly-linked cache + HitDoc* prev; // in doubly-linked cache + + HitDoc(const qreal s, const int32_t i); + ~HitDoc(); + }; + + + + // A ranked list of documents, used to hold search results. + class Hits:LUCENE_BASE { + private: + Query* query; + Searcher* searcher; + Filter* filter; + const Sort* sort; + + size_t _length; // the total number of hits + CL_NS(util)::CLVector > hitDocs; // cache of hits retrieved + + HitDoc* first; // head of LRU cache + HitDoc* last; // tail of LRU cache + int32_t numDocs; // number cached + int32_t maxDocs; // max to cache + + public: + Hits(Searcher* s, Query* q, Filter* f, const Sort* sort=NULL); + ~Hits(); + + /** Returns the total number of hits available in this set. */ + int32_t length() const; + + /** Returns the stored fields of the nth document in this set. +

Documents are cached, so that repeated requests for the same element may + return the same Document object. + * + * @memory Memory belongs to the hits object. Don't delete the return value. + */ + CL_NS(document)::Document& doc(const int32_t n); + + /** Returns the id for the nth document in this set. */ + int32_t id (const int32_t n); + + /** Returns the score for the nth document in this set. */ + qreal score(const int32_t n); + + private: + // Tries to add new documents to hitDocs. + // Ensures that the hit numbered _min has been retrieved. + void getMoreDocs(const size_t _min); + + HitDoc* getHitDoc(const size_t n); + + void addToFront(HitDoc* hitDoc); + + void remove(const HitDoc* hitDoc); + + }; + + /** The interface for search implementations. + * + *

Implementations provide search over a single index, over multiple + * indices, and over indices on remote servers. + */ + class Searchable: LUCENE_BASE { + public: + virtual ~Searchable(){ + } + + /** Lower-level search API. + * + *

{@link HitCollector#collect(int32_t,qreal)} is called for every non-zero + * scoring document. + * + *

Applications should only use this if they need all of the + * matching documents. The high-level search API ({@link + * Searcher#search(Query*)}) is usually more efficient, as it skips + * non-high-scoring hits. + * + * @param query to match documents + * @param filter if non-null, a bitset used to eliminate some documents + * @param results to receive hits + */ + virtual void _search(Query* query, Filter* filter, HitCollector* results) = 0; + + /** Frees resources associated with this Searcher. + * Be careful not to call this method while you are still using objects + * like {@link Hits}. + */ + virtual void close() = 0; + + /** Expert: Returns the number of documents containing term. + * Called by search code to compute term weights. + * @see IndexReader#docFreq(Term). + */ + virtual int32_t docFreq(const CL_NS(index)::Term* term) const = 0; + + /** Expert: Returns one greater than the largest possible document number. + * Called by search code to compute term weights. + * @see IndexReader#maxDoc(). + */ + virtual int32_t maxDoc() const = 0; + + /** Expert: Low-level search implementation. Finds the top n + * hits for query, applying filter if non-null. + * + *

Called by {@link Hits}. + * + *

Applications should usually call {@link Searcher#search(Query*)} or + * {@link Searcher#search(Query*,Filter*)} instead. + */ + virtual TopDocs* _search(Query* query, Filter* filter, const int32_t n) = 0; + + /** Expert: Returns the stored fields of document i. + * Called by {@link HitCollector} implementations. + * @see IndexReader#document(int32_t). + */ + virtual bool doc(int32_t i, CL_NS(document)::Document* d) = 0; + _CL_DEPRECATED( doc(i, document) ) CL_NS(document)::Document* doc(const int32_t i); + + /** Expert: called to re-write queries into primitive queries. */ + virtual Query* rewrite(Query* query) = 0; + + /** Returns an Explanation that describes how doc scored against + * query. + * + *

This is intended to be used in developing Similarity implementations, + * and, for good performance, should not be displayed with every hit. + * Computing an explanation is as expensive as executing the query over the + * entire index. + */ + virtual void explain(Query* query, int32_t doc, Explanation* ret) = 0; + + /** Expert: Low-level search implementation with arbitrary sorting. Finds + * the top n hits for query, applying + * filter if non-null, and sorting the hits by the criteria in + * sort. + * + *

Applications should usually call {@link + * Searcher#search(Query,Filter,Sort)} instead. + */ + virtual TopFieldDocs* _search(Query* query, Filter* filter, const int32_t n, const Sort* sort) = 0; + }; + + + + /** An abstract base class for search implementations. + * Implements some common utility methods. + */ + class Searcher:public Searchable { + private: + /** The Similarity implementation used by this searcher. */ + Similarity* similarity; + + public: + Searcher(){ + similarity = Similarity::getDefault(); + } + virtual ~Searcher(){ + } + + // Returns the documents matching query. + Hits* search(Query* query) { + return search(query, (Filter*)NULL ); + } + + // Returns the documents matching query and + // filter. + Hits* search(Query* query, Filter* filter) { + return _CLNEW Hits(this, query, filter); + } + + /** Returns documents matching query sorted by + * sort. + */ + Hits* search(Query* query, const Sort* sort){ + return _CLNEW Hits(this, query, NULL, sort); + } + + /** Returns documents matching query and filter, + * sorted by sort. + */ + Hits* search(Query* query, Filter* filter, const Sort* sort){ + return _CLNEW Hits(this, query, filter, sort); + } + + /** Lower-level search API. + * + *

{@link HitCollector#collect(int32_t ,qreal)} is called for every non-zero + * scoring document. + * + *

Applications should only use this if they need all of the + * matching documents. The high-level search API ({@link + * Searcher#search(Query*)}) is usually more efficient, as it skips + * non-high-scoring hits. + *

Note: The score passed to this method is a raw score. + * In other words, the score will not necessarily be a float whose value is + * between 0 and 1. + */ + void _search(Query* query, HitCollector* results) { + Searchable::_search(query, NULL, results); + } + + /** Expert: Set the Similarity implementation used by this Searcher. + * + * @see Similarity#setDefault(Similarity) + */ + void setSimilarity(Similarity* similarity) { + this->similarity = similarity; + } + + /** Expert: Return the Similarity implementation used by this Searcher. + * + *

This defaults to the current value of {@link Similarity#getDefault()}. + */ + Similarity* getSimilarity(){ + return this->similarity; + } + }; + + /** The abstract base class for queries. +

Instantiable subclasses are: +

    +
  • {@link TermQuery} +
  • {@link MultiTermQuery} +
  • {@link BooleanQuery} +
  • {@link WildcardQuery} +
  • {@link PhraseQuery} +
  • {@link PrefixQuery} +
  • {@link PhrasePrefixQuery} +
  • {@link FuzzyQuery} +
  • {@link RangeQuery} +
  • {@link spans.SpanQuery} +
+

A parser for queries is contained in: +

    +
  • {@link queryParser.QueryParser QueryParser} +
+ */ + class Query :LUCENE_BASE { + private: + // query boost factor + qreal boost; + protected: + Query(const Query& clone); + public: + Query(); + virtual ~Query(); + + /** Sets the boost for this query clause to b. Documents + * matching this clause will (in addition to the normal weightings) have + * their score multiplied by b. + */ + void setBoost(qreal b); + + /** Gets the boost for this clause. Documents matching + * this clause will (in addition to the normal weightings) have their score + * multiplied by b. The boost is 1.0 by default. + */ + qreal getBoost() const; + + /** Expert: Constructs an initializes a Weight for a top-level query. */ + Weight* weight(Searcher* searcher); + + /** Expert: called to re-write queries into primitive queries. */ + virtual Query* rewrite(CL_NS(index)::IndexReader* reader); + + /** Expert: called when re-writing queries under MultiSearcher. + * + *

Only implemented by derived queries, with no + * {@link #_createWeight(Searcher)} implementatation. + */ + virtual Query* combine(Query** queries); + + /** Expert: merges the clauses of a set of BooleanQuery's into a single + * BooleanQuery. + * + *

A utility for use by {@link #combine(Query[])} implementations. + */ + static Query* mergeBooleanQueries(Query** queries); + + /** Expert: Returns the Similarity implementation to be used for this query. + * Subclasses may override this method to specify their own Similarity + * implementation, perhaps one that delegates through that of the Searcher. + * By default the Searcher's Similarity implementation is returned.*/ + Similarity* getSimilarity(Searcher* searcher); + + /** Returns a clone of this query. */ + virtual Query* clone() const = 0; + virtual const TCHAR* getQueryName() const = 0; + bool instanceOf(const TCHAR* other) const; + + /** Prints a query to a string, with field as the default field + * for terms.

The representation used is one that is readable by + * {@link queryParser.QueryParser QueryParser} + * (although, if the query was created by the parser, the printed + * representation may not be exactly what was parsed). + */ + virtual TCHAR* toString(const TCHAR* field) const = 0; + + virtual bool equals(Query* other) const = 0; + virtual size_t hashCode() const = 0; + + /** Prints a query to a string. */ + TCHAR* toString() const; + + + /** Expert: Constructs an appropriate Weight implementation for this query. + * + *

Only implemented by primitive queries, which re-write to themselves. + * This is an Internal function + */ + virtual Weight* _createWeight(Searcher* searcher); + + }; + + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/Similarity.cpp b/3rdparty/clucene/src/CLucene/search/Similarity.cpp new file mode 100644 index 000000000..d33a036e4 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/Similarity.cpp @@ -0,0 +1,233 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "Similarity.h" + +#include "CLucene/index/Term.h" +#include "SearchHeader.h" + +CL_NS_USE(index) +CL_NS_DEF(search) + +#ifdef _CL_HAVE_NO_FLOAT_BYTE + #if defined(_LUCENE_PRAGMA_WARNINGS) + #pragma message ("==================Using fallback float<->byte encodings!!!==================") + #else + #warning "==================Using fallback float<->byte encodings!!!==================" + #endif + + //if the autoconf figured out that we can't do the conversions properly, then + //we fall back on the old, inaccurate way of doing things. + qreal NORM_TABLE[] = { + 0.0,5.820766E-10,6.9849193E-10,8.1490725E-10,9.313226E-10,1.1641532E-9,1.3969839E-9, + 1.6298145E-9,1.8626451E-9,2.3283064E-9,2.7939677E-9,3.259629E-9,3.7252903E-9, + 4.656613E-9,5.5879354E-9,6.519258E-9,7.4505806E-9,9.313226E-9,1.1175871E-8,1.3038516E-8, + 1.4901161E-8,1.8626451E-8,2.2351742E-8,2.6077032E-8,2.9802322E-8,3.7252903E-8,4.4703484E-8, + 5.2154064E-8,5.9604645E-8,7.4505806E-8,8.940697E-8,1.0430813E-7,1.1920929E-7,1.4901161E-7, + 1.7881393E-7,2.0861626E-7,2.3841858E-7,2.9802322E-7,3.5762787E-7,4.172325E-7,4.7683716E-7, + 5.9604645E-7,7.1525574E-7,8.34465E-7,9.536743E-7,1.1920929E-6,1.4305115E-6,1.66893E-6, + 1.9073486E-6,2.3841858E-6,2.861023E-6,3.33786E-6,3.8146973E-6,4.7683716E-6,5.722046E-6, + 6.67572E-6,7.6293945E-6,9.536743E-6,1.1444092E-5,1.335144E-5,1.5258789E-5,1.9073486E-5, + 2.2888184E-5,2.670288E-5,3.0517578E-5,3.8146973E-5,4.5776367E-5,5.340576E-5,6.1035156E-5, + 7.6293945E-5,9.1552734E-5,1.0681152E-4,1.2207031E-4,1.5258789E-4,1.8310547E-4,2.1362305E-4, + 2.4414062E-4,3.0517578E-4,3.6621094E-4,4.272461E-4,4.8828125E-4,6.1035156E-4,7.324219E-4, + 8.544922E-4,9.765625E-4,0.0012207031,0.0014648438,0.0017089844,0.001953125,0.0024414062, + 0.0029296875,0.0034179688,0.00390625,0.0048828125,0.005859375,0.0068359375, + 0.0078125,0.009765625,0.01171875,0.013671875,0.015625,0.01953125,0.0234375, + 0.02734375,0.03125,0.0390625,0.046875,0.0546875,0.0625,0.078125,0.09375,0.109375, + 0.125,0.15625,0.1875,0.21875,0.25,0.3125,0.375,0.4375,0.5,0.625,0.75, + 0.875,1.0,1.25,1.5,1.75,2,2.5,3,3.5,4.0,5.0,6.0,7.0,8.0,10.0,12.0,14.0,16.0,20.0,24.0,28.0,32.0,40.0,48.0,56.0, + 64.0,80.0,96.0,112.0,128.0,160.0,192.0,224.0,256.0,320.0,384.0,448.0,512.0,640.0,768.0,896.0,1024.0,1280.0,1536.0,1792.0, + 2048.0,2560.0,3072.0,3584.0,4096.0,5120.0,6144.0,7168.0,8192.0,10240.0,12288.0,14336.0,16384.0,20480.0,24576.0, + 28672.0,32768.0,40960.0,49152.0,57344.0,65536.0,81920.0,98304.0,114688.0,131072.0,163840.0,196608.0, + 229376.0,262144.0,327680.0,393216.0,458752.0,524288.0,655360.0,786432.0,917504.0,1048576.0,1310720.0, + 1572864.0,1835008.0,2097152.0,2621440.0,3145728.0,3670016.0,4194304.0,5242880.0,6291456.0,7340032.0, + 8388608.0,10485760.0,12582912.0,14680064.0,16777216.0,20971520.0,25165824.0,29360128.0,33554432.0, + 41943040.0,50331648.0,58720256.0,67108864.0,83886080.0,100663296.0,117440512.0,134217728.0, + 167772160.0,201326592.0,234881024.0,268435456.0,335544320.0,402653184.0,469762048.0,536870912.0, + 671088640.0,805306368.0,939524096.0,1073741824.0,1342177280.0,1610612736.0,1879048192.0, + 2147483648.0,2684354560.0,3221225472.0,3758096384.0,4294967296.0,5368709120.0,6442450944.0,7516192768.0 + }; + + qreal Similarity::byteToFloat(uint8_t b) { + return NORM_TABLE[b]; + } + + uint8_t Similarity::floatToByte(qreal f) { + return Similarity::encodeNorm(f); + } + +#else + + /** Cache of decoded bytes. */ + qreal NORM_TABLE[256]; + bool NORM_TABLE_initd=false; + + //float to bits conversion utilities... + union clvalue { + int32_t i; + float f; //must use a float type, else types dont match up + }; + + int32_t floatToIntBits(qreal value) + { + clvalue u; + int32_t e, f; + u.f = (float)value; + e = u.i & 0x7f800000; + f = u.i & 0x007fffff; + + if (e == 0x7f800000 && f != 0) + u.i = 0x7fc00000; + + return u.i; + } + + qreal intBitsToFloat(int32_t bits) + { + clvalue u; + u.i = bits; + return u.f; + } + + + qreal Similarity::byteToFloat(uint8_t b) { + if (b == 0) // zero is a special case + return 0.0f; + int32_t mantissa = b & 7; + int32_t exponent = (b >> 3) & 31; + int32_t bits = ((exponent+(63-15)) << 24) | (mantissa << 21); + return intBitsToFloat(bits); + } + + uint8_t Similarity::floatToByte(qreal f) { + if (f < 0.0f) // round negatives up to zero + f = 0.0f; + + if (f == 0.0f) // zero is a special case + return 0; + + int32_t bits = floatToIntBits(f); // parse qreal into parts + int32_t mantissa = (bits & 0xffffff) >> 21; + int32_t exponent = (((bits >> 24) & 0x7f) - 63) + 15; + + if (exponent > 31) { // overflow: use max value + exponent = 31; + mantissa = 7; + } + + if (exponent < 0) { // underflow: use min value + exponent = 0; + mantissa = 1; + } + + return (uint8_t)((exponent << 3) | mantissa); // pack into a uint8_t + } +#endif + + /** The Similarity implementation used by default. */ + Similarity* _defaultImpl=NULL; + + void Similarity::setDefault(Similarity* similarity) { + _defaultImpl = similarity; + } + + Similarity* Similarity::getDefault() { + if ( _defaultImpl == NULL ){ + _defaultImpl = _CLNEW DefaultSimilarity(); + } + return _defaultImpl; + } + + qreal Similarity::decodeNorm(uint8_t b) { +#ifndef _CL_HAVE_NO_FLOAT_BYTE + if ( !NORM_TABLE_initd ){ + for (int i = 0; i < 256; i++) + NORM_TABLE[i] = byteToFloat(i); + NORM_TABLE_initd=true; + } +#endif + return NORM_TABLE[b]; + } + + uint8_t Similarity::encodeNorm(qreal f) { +#ifdef _CL_HAVE_NO_FLOAT_BYTE + int32_t i=0; + if ( f <= 0 ) + return 0; + + while ( i<256 && f > NORM_TABLE[i] ){ + i++; + } + if ( i == 0 ) + return 0; + else if ( i == 255 && f>NORM_TABLE[255] ) + return 255; + else + return i; +#else + return floatToByte(f); +#endif + } + + + qreal Similarity::idf(Term* term, Searcher* searcher) { + return idf(searcher->docFreq(term), searcher->maxDoc()); + } + + + qreal Similarity::idf(CL_NS(util)::CLVector* terms, Searcher* searcher) { + qreal _idf = 0.0f; + for (CL_NS(util)::CLVector::iterator i = terms->begin(); i != terms->end(); i++ ) { + _idf += idf((Term*)*i, searcher); + } + return _idf; + } + + Similarity::~Similarity(){ + } + + + + + DefaultSimilarity::DefaultSimilarity(){ + } + DefaultSimilarity::~DefaultSimilarity(){ + } + + qreal DefaultSimilarity::lengthNorm(const TCHAR* fieldName, int32_t numTerms) { + if ( numTerms == 0 ) //prevent div by zero + return 0; + qreal ret = (qreal)(1.0 / sqrt((qreal)numTerms)); + return ret; + } + + qreal DefaultSimilarity::queryNorm(qreal sumOfSquaredWeights) { + if ( sumOfSquaredWeights == 0 ) //prevent div by zero + return 0.0f; + qreal ret = (qreal)(1.0 / sqrt(sumOfSquaredWeights)); + return ret; + } + + qreal DefaultSimilarity::tf(qreal freq) { + return sqrt(freq); + } + + qreal DefaultSimilarity::sloppyFreq(int32_t distance) { + return 1.0f / (distance + 1); + } + + qreal DefaultSimilarity::idf(int32_t docFreq, int32_t numDocs) { + return (qreal)(log(numDocs/(qreal)(docFreq+1)) + 1.0); + } + + qreal DefaultSimilarity::coord(int32_t overlap, int32_t maxOverlap) { + if ( maxOverlap == 0 ) + return 0.0f; + return overlap / (qreal)maxOverlap; + } +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/Similarity.h b/3rdparty/clucene/src/CLucene/search/Similarity.h new file mode 100644 index 000000000..426af6952 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/Similarity.h @@ -0,0 +1,268 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_Similarity_ +#define _lucene_search_Similarity_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/index/Term.h" + +CL_NS_DEF(search) + +class Searcher;//save including the searchheader.h +class DefaultSimilarity; + +/** Expert: Scoring API. +*

Subclasses implement search scoring. +* +*

The score of query q for document d is defined +* in terms of these methods as follows: +* +* +* +* +* +* +* +* +* +* +* +*
score(q,d) =
+* Σ +* {@link #tf(int32_t) tf}(t in d) * +* {@link #idf(Term,Searcher) idf}(t) * +* {@link Field#getBoost getBoost}(t.field in d) * +* {@link #lengthNorm(TCHAR*,int32_t) lengthNorm}(t.field in d) +*  * +* {@link #coord(int32_t,int32_t) coord}(q,d) * +* {@link #queryNorm(qreal) queryNorm}(q) +*
+* t in q +*
+* +* @see #setDefault(Similarity) +* @see IndexWriter#setSimilarity(Similarity) +* @see Searcher#setSimilarity(Similarity) +*/ +class Similarity:LUCENE_BASE { +public: + virtual ~Similarity(); + + /** Set the default Similarity implementation used by indexing and search + * code. + * + * @see Searcher#setSimilarity(Similarity) + * @see IndexWriter#setSimilarity(Similarity) + */ + static void setDefault(Similarity* similarity); + + /** Return the default Similarity implementation used by indexing and search + * code. + * + *

This is initially an instance of {@link DefaultSimilarity}. + * + * @see Searcher#setSimilarity(Similarity) + * @see IndexWriter#setSimilarity(Similarity) + */ + static Similarity* getDefault(); + + /** Encodes a normalization factor for storage in an index. + * + *

The encoding uses a five-bit exponent and three-bit mantissa, thus + * representing values from around 7x10^9 to 2x10^-9 with about one + * significant decimal digit of accuracy. Zero is also represented. + * Negative numbers are rounded up to zero. Values too large to represent + * are rounded down to the largest representable value. Positive values too + * small to represent are rounded up to the smallest positive representable + * value. + * + * @see Field#setBoost(qreal) + */ + static uint8_t encodeNorm(qreal f); + + /** Decodes a normalization factor stored in an index. + * @see #encodeNorm(qreal) + */ + static qreal decodeNorm(uint8_t b); + + static uint8_t floatToByte(qreal f); + static qreal byteToFloat(uint8_t b); + + /** Computes a score factor for a phrase. + * + *

The default implementation sums the {@link #idf(Term,Searcher)} factor + * for each term in the phrase. + * + * @param terms the terms in the phrase + * @param searcher the document collection being searched + * @return a score factor for the phrase + */ + qreal idf(CL_NS(util)::CLVector* terms, Searcher* searcher); + //qreal idf(Term** terms, Searcher* searcher); + + + /** Computes a score factor for a simple term. + * + *

The default implementation is:

+   *   return idf(searcher.docFreq(term), searcher.maxDoc());
+   * 
+ * + * Note that {@link Searcher#maxDoc()} is used instead of + * {@link IndexReader#numDocs()} because it is proportional to + * {@link Searcher#docFreq(Term)} , i.e., when one is inaccurate, + * so is the other, and in the same direction. + * + * @param term the term in question + * @param searcher the document collection being searched + * @return a score factor for the term + */ + qreal idf(CL_NS(index)::Term* term, Searcher* searcher); + + + /** Computes a score factor based on a term or phrase's frequency in a + * document. This value is multiplied by the {@link #idf(Term, Searcher)} + * factor for each term in the query and these products are then summed to + * form the initial score for a document. + * + *

Terms and phrases repeated in a document indicate the topic of the + * document, so implementations of this method usually return larger values + * when freq is large, and smaller values when freq + * is small. + * + *

The default implementation calls {@link #tf(qreal)}. + * + * @param freq the frequency of a term within a document + * @return a score factor based on a term's within-document frequency + */ + inline qreal tf(int32_t freq){ return tf((qreal)freq); } + + /** Computes the normalization value for a field given the total number of + * terms contained in a field. These values, together with field boosts, are + * stored in an index and multipled into scores for hits on each field by the + * search code. + * + *

Matches in longer fields are less precise, so implemenations of this + * method usually return smaller values when numTokens is large, + * and larger values when numTokens is small. + * + *

That these values are computed under {@link + * IndexWriter#addDocument(Document)} and stored then using + * {#encodeNorm(qreal)}. Thus they have limited precision, and documents + * must be re-indexed if this method is altered. + * + * @param fieldName the name of the field + * @param numTokens the total number of tokens contained in fields named + * fieldName of doc. + * @return a normalization factor for hits on this field of this document + * + * @see Field#setBoost(qreal) + */ + virtual qreal lengthNorm(const TCHAR* fieldName, int32_t numTokens) = 0; + + /** Computes the normalization value for a query given the sum of the squared + * weights of each of the query terms. This value is then multipled into the + * weight of each query term. + * + *

This does not affect ranking, but rather just attempts to make scores + * from different queries comparable. + * + * @param sumOfSquaredWeights the sum of the squares of query term weights + * @return a normalization factor for query weights + */ + virtual qreal queryNorm(qreal sumOfSquaredWeights) = 0; + + /** Computes the amount of a sloppy phrase match, based on an edit distance. + * This value is summed for each sloppy phrase match in a document to form + * the frequency that is passed to {@link #tf(qreal)}. + * + *

A phrase match with a small edit distance to a document passage more + * closely matches the document, so implementations of this method usually + * return larger values when the edit distance is small and smaller values + * when it is large. + * + * @see PhraseQuery#setSlop(int32_t) + * @param distance the edit distance of this sloppy phrase match + * @return the frequency increment for this match + */ + virtual qreal sloppyFreq(int32_t distance) = 0; + + /** Computes a score factor based on a term or phrase's frequency in a + * document. This value is multiplied by the {@link #idf(Term, Searcher)} + * factor for each term in the query and these products are then summed to + * form the initial score for a document. + * + *

Terms and phrases repeated in a document indicate the topic of the + * document, so implemenations of this method usually return larger values + * when freq is large, and smaller values when freq + * is small. + * + * @param freq the frequency of a term within a document + * @return a score factor based on a term's within-document frequency + */ + virtual qreal tf(qreal freq) = 0; + + /** Computes a score factor based on a term's document frequency (the number + * of documents which contain the term). This value is multiplied by the + * {@link #tf(int32_t)} factor for each term in the query and these products are + * then summed to form the initial score for a document. + * + *

Terms that occur in fewer documents are better indicators of topic, so + * implemenations of this method usually return larger values for rare terms, + * and smaller values for common terms. + * + * @param docFreq the number of documents which contain the term + * @param numDocs the total number of documents in the collection + * @return a score factor based on the term's document frequency + */ + virtual qreal idf(int32_t docFreq, int32_t numDocs) = 0; + + /** Computes a score factor based on the fraction of all query terms that a + * document contains. This value is multiplied into scores. + * + *

The presence of a large portion of the query terms indicates a better + * match with the query, so implemenations of this method usually return + * larger values when the ratio between these parameters is large and smaller + * values when the ratio between them is small. + * + * @param overlap the number of query terms matched in the document + * @param maxOverlap the total number of terms in the query + * @return a score factor based on term overlap with the query + */ + virtual qreal coord(int32_t overlap, int32_t maxOverlap) = 0; +}; + + +/** Expert: Default scoring implementation. */ +class DefaultSimilarity: public Similarity { +public: + DefaultSimilarity(); + ~DefaultSimilarity(); + + /** Implemented as 1/sqrt(numTerms). */ + qreal lengthNorm(const TCHAR* fieldName, int32_t numTerms); + + /** Implemented as 1/sqrt(sumOfSquaredWeights). */ + qreal queryNorm(qreal sumOfSquaredWeights); + + /** Implemented as sqrt(freq). */ + inline qreal tf(qreal freq); + + /** Implemented as 1 / (distance + 1). */ + qreal sloppyFreq(int32_t distance); + + /** Implemented as log(numDocs/(docFreq+1)) + 1. */ + qreal idf(int32_t docFreq, int32_t numDocs); + + /** Implemented as overlap / maxOverlap. */ + qreal coord(int32_t overlap, int32_t maxOverlap); +}; + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/SloppyPhraseScorer.cpp b/3rdparty/clucene/src/CLucene/search/SloppyPhraseScorer.cpp new file mode 100644 index 000000000..b7683b018 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/SloppyPhraseScorer.cpp @@ -0,0 +1,106 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "SloppyPhraseScorer.h" + +#include "PhraseScorer.h" +#include "CLucene/index/Terms.h" + +CL_NS_USE(index) +CL_NS_DEF(search) + + SloppyPhraseScorer::SloppyPhraseScorer(Weight* weight, CL_NS(index)::TermPositions** tps, + int32_t* positions, Similarity* similarity, + int32_t slop, uint8_t* norms): + PhraseScorer(weight,tps,positions,similarity,norms){ + //Func - Constructor + //Pre - tps != NULL + // tpsLength >= 0 + // n != NULL + //Post - Instance has been created + + CND_PRECONDITION(tps != NULL, "tps is NULL"); + //CND_PRECONDITION(n != NULL, _T("n is NULL")) = checked in PhraseScorer; + + this->slop = slop; + } + + qreal SloppyPhraseScorer::phraseFreq() { + //Func - Returns the freqency of the phrase + //Pre - first != NULL + // last != NULL + // pq != NULL + //Post - The frequency of the phrase has been returned + + CND_PRECONDITION(first != NULL,"first is NULL"); + CND_PRECONDITION(last != NULL,"last is NULL"); + CND_PRECONDITION(pq != NULL,"pq is NULL"); + + //Clear the PhraseQueue pq; + pq->clear(); + + int32_t end = 0; + + //declare iterator + PhrasePositions* pp = NULL; + + // build pq from list + + //Sort the list of PhrasePositions using pq + for (pp = first; pp != NULL; pp = pp->_next) { + //Read the first TermPosition of the current PhrasePositions pp + pp->firstPosition(); + //Check if the position of the pp is bigger than end + if (pp->position > end){ + end = pp->position; + } + //Store the current PhrasePositions pp into the PhraseQueue pp + pq->put(pp); + } + + qreal freq = 0.0f; + + bool done = false; + + do { + //Pop a PhrasePositions pp from the PhraseQueue pp + pp = pq->pop(); + //Get start position + int32_t start = pp->position; + //Get next position + int32_t next = pq->top()->position; + + for (int32_t pos = start; pos <= next; pos = pp->position) { + //advance pp to min window + start = pos; + + if (!pp->nextPosition()) { + //ran out of a term -- done + done = true; + break; + } + } + + //Calculate matchLength + int32_t matchLength = end - start; + //Check if matchLength is smaller than slop + if (matchLength <= slop){ + // penalize longer matches + freq += 1.0 / (matchLength + 1); + } + + if (pp->position > end){ + end = pp->position; + } + + //restore pq + pq->put(pp); + }while (!done); + + return freq; + } +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/SloppyPhraseScorer.h b/3rdparty/clucene/src/CLucene/search/SloppyPhraseScorer.h new file mode 100644 index 000000000..31516e393 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/SloppyPhraseScorer.h @@ -0,0 +1,34 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_SloppyPhraseScorer_ +#define _lucene_search_SloppyPhraseScorer_ +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "PhraseScorer.h" +#include "CLucene/index/Terms.h" + + +CL_NS_DEF(search) + class SloppyPhraseScorer: public PhraseScorer { + private: + int32_t slop; + + public: + SloppyPhraseScorer(Weight* weight, CL_NS(index)::TermPositions** tps, + int32_t* positions, Similarity* similarity, + int32_t slop, uint8_t* norms); + ~SloppyPhraseScorer(){ + } + + protected: + qreal phraseFreq(); + }; +CL_NS_END +#endif + diff --git a/3rdparty/clucene/src/CLucene/search/Sort.cpp b/3rdparty/clucene/src/CLucene/search/Sort.cpp new file mode 100644 index 000000000..5a17a784d --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/Sort.cpp @@ -0,0 +1,345 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "Sort.h" +#include "Compare.h" + +CL_NS_USE(util) +CL_NS_DEF(search) + + + + /** Represents sorting by document score (relevancy). */ + SortField* SortField::FIELD_SCORE = _CLNEW SortField (NULL, DOCSCORE,false); + + /** Represents sorting by document number (index order). */ + SortField* SortField::FIELD_DOC = _CLNEW SortField (NULL, DOC,false); + + + /** Represents sorting by computed relevance. Using this sort criteria + * returns the same results as calling {@link Searcher#search(Query) Searcher#search()} + * without a sort criteria, only with slightly more overhead. */ + Sort* Sort::RELEVANCE = _CLNEW Sort(); + + /** Represents sorting by index order. */ + Sort* Sort::INDEXORDER = _CLNEW Sort (SortField::FIELD_DOC); + + + + + /** Creates a sort by terms in the given field where the type of term value + * is determined dynamically ({@link #AUTO AUTO}). + * @param field Name of field to sort by, cannot be null. + */ + SortField::SortField (const TCHAR* field) { + this->type = AUTO; + this->reverse = false; + this->field = CLStringIntern::intern(field CL_FILELINE); + this->factory = NULL; + } + + /** Creates a sort, possibly in reverse, by terms in the given field where + * the type of term value is determined dynamically ({@link #AUTO AUTO}). + * @param field Name of field to sort by, cannot be null. + * @param reverse True if natural order should be reversed. + + SortField::SortField (const TCHAR* field, bool reverse) { + this->field = CLStringIntern::intern(field CL_FILELINE); + this->reverse = reverse; + this->type = AUTO; + this->factory = NULL; + }*/ + + + /** Creates a sort, possibly in reverse, by terms in the given field with the + * type of term values explicitly given. + * @param field Name of field to sort by. Can be null if + * type is SCORE or DOC. + * @param type Type of values in the terms. + * @param reverse True if natural order should be reversed (default=false). + */ + SortField::SortField (const TCHAR* field, int32_t type, bool reverse) { + this->field = (field != NULL) ? CLStringIntern::intern(field CL_FILELINE) : field; + this->type = type; + this->reverse = reverse; + this->factory = NULL; + } + + SortField::SortField(const SortField& clone){ + this->field = (clone.field != NULL) ? CLStringIntern::intern(clone.field CL_FILELINE) : clone.field; + this->type = clone.type; + this->reverse = clone.reverse; + this->factory = clone.factory; + } + SortField* SortField::clone() const{ + return _CLNEW SortField(*this); + } + + /** Creates a sort by terms in the given field sorted + * according to the given locale. + * @param field Name of field to sort by, cannot be null. + * @param locale Locale of values in the field. + */ + /*SortField::SortField (TCHAR* field, Locale* locale) { + this->field = (field != NULL) ? CLStringIntern::intern(field): field; + this->type = STRING; + this->locale = locale; + }*/ + + /** Creates a sort, possibly in reverse, by terms in the given field sorted + * according to the given locale. + * @param field Name of field to sort by, cannot be null. + * @param locale Locale of values in the field. + */ + /*SortField::SortField (TCHAR* field, Locale* locale, bool reverse) { + this->field = (field != NULL) ? CLStringIntern::intern(field): field; + this->type = STRING; + this->locale = locale; + this->reverse = reverse; + }*/ + + + /** Creates a sort, possibly in reverse, with a custom comparison function. + * @param field Name of field to sort by; cannot be null. + * @param comparator Returns a comparator for sorting hits. + * @param reverse True if natural order should be reversed (default=false). + */ + SortField::SortField (const TCHAR* field, SortComparatorSource* comparator, bool reverse) { + this->field = (field != NULL) ? CLStringIntern::intern(field CL_FILELINE): field; + this->type = CUSTOM; + this->reverse = reverse; + this->factory = comparator; + } + + SortField::~SortField(){ + CLStringIntern::unintern(field); + } + + TCHAR* SortField::toString() const { + CL_NS(util)::StringBuffer buffer; + switch (type) { + case DOCSCORE: buffer.append(_T("")); + break; + + case DOC: buffer.append(_T("")); + break; + + case CUSTOM: buffer.append (_T("getName()); + buffer.append(_T(">")); + break; + + default: buffer.append( _T("\"")); + buffer.append( field ); + buffer.append( _T("\"") ); + break; + } + + //if (locale != null) buffer.append ("("+locale+")"); todo: + if (reverse) buffer.appendChar('!'); + + return buffer.toString(); + } + + + + + + + + + + + + + + /** Sorts by computed relevance. This is the same sort criteria as + * calling {@link Searcher#search(Query) Searcher#search()} without a sort criteria, only with + * slightly more overhead. */ + Sort::Sort() { + fields=NULL; + SortField** fields=_CL_NEWARRAY(SortField*,3); + fields[0]=SortField::FIELD_SCORE; + fields[1]=SortField::FIELD_DOC; + fields[2]=NULL; + setSort (fields); + _CLDELETE_ARRAY(fields); + } + + Sort::~Sort(){ + clear(); + } + void Sort::clear(){ + if ( fields != NULL ){ + int32_t i=0; + while ( fields[i] != NULL ){ + if ( fields[i] != SortField::FIELD_SCORE && + fields[i] != SortField::FIELD_DOC ){ + _CLDELETE(fields[i]); + } + i++; + } + _CLDELETE_ARRAY(fields); + } + } + + /** Sorts possibly in reverse by the terms in field then by + * index order (document number). The type of value in field is determined + * automatically. + * @see SortField#AUTO + */ + Sort::Sort (const TCHAR* field, bool reverse) { + this->fields=NULL; + setSort (field, reverse); + } + + + /** Sorts in succession by the terms in each field. + * The type of value in field is determined + * automatically. + * @see SortField#AUTO + */ + Sort::Sort (const TCHAR** fields) { + this->fields=NULL; + setSort (fields); + } + + + /** Sorts by the criteria in the given SortField. */ + Sort::Sort (SortField* field) { + this->fields=NULL; + setSort (field); + } + + + /** Sorts in succession by the criteria in each SortField. */ + Sort::Sort (SortField** fields) { + this->fields=NULL; + setSort (fields); + } + + + /** Sets the sort to the terms in field possibly in reverse, + * then by index order (document number). */ + void Sort::setSort (const TCHAR* field, bool reverse) { + clear(); + fields = _CL_NEWARRAY(SortField*,3); + fields[0] = _CLNEW SortField (field, SortField::AUTO, reverse); + fields[1] = SortField::FIELD_DOC; + fields[2] = NULL; + } + + + /** Sets the sort to the terms in each field in succession. */ + void Sort::setSort (const TCHAR** fieldnames) { + clear(); + + int32_t n = 0; + while ( fieldnames[n] != NULL ) + n++; + + fields = _CL_NEWARRAY(SortField*,n+1); + for (int32_t i = 0; i < n; ++i) { + fields[i] = _CLNEW SortField (fieldnames[i], SortField::AUTO,false); + } + fields[n]=NULL; + } + + + /** Sets the sort to the given criteria. */ + void Sort::setSort (SortField* field) { + clear(); + + this->fields = _CL_NEWARRAY(SortField*,2); + this->fields[0] = field; + this->fields[1] = NULL; + } + + + /** Sets the sort to the given criteria in succession. */ + void Sort::setSort (SortField** fields) { + clear(); + + int n=0; + while ( fields[n] != NULL ) + n++; + this->fields = _CL_NEWARRAY(SortField*,n+1); + for (int i=0;ifields[i]=fields[i]; + } + + TCHAR* Sort::toString() const { + CL_NS(util)::StringBuffer buffer; + + int32_t i = 0; + while ( fields[i] != NULL ){ + if (i>0) + buffer.appendChar(','); + + const TCHAR* p = fields[i]->toString(); + buffer.append(p); + _CLDELETE_CARRAY(p); + + i++; + } + + return buffer.toString(); + } + + + + + + ScoreDocComparator* ScoreDocComparator::INDEXORDER = _CLNEW ScoreDocComparators::IndexOrder; + ScoreDocComparator* ScoreDocComparator::RELEVANCE = _CLNEW ScoreDocComparators::Relevance; + + ScoreDocComparator::~ScoreDocComparator(){ + } + + +class ScoreDocComparatorImpl: public ScoreDocComparator{ + Comparable** cachedValues; + FieldCacheAuto* fca; + int32_t cachedValuesLen; +public: + ScoreDocComparatorImpl(FieldCacheAuto* fca){ + this->fca = fca; + if ( fca->contentType != FieldCacheAuto::COMPARABLE_ARRAY ) + _CLTHROWA(CL_ERR_InvalidCast,"Invalid field cache auto type"); + this->cachedValues = fca->comparableArray; + this->cachedValuesLen = fca->contentLen; + } + ~ScoreDocComparatorImpl(){ + } + int32_t compare (struct ScoreDoc* i, struct ScoreDoc* j){ + CND_PRECONDITION(i->doc >= 0 && i->doc < cachedValuesLen, "i->doc out of range") + CND_PRECONDITION(j->doc >= 0 && j->doc < cachedValuesLen, "j->doc out of range") + return cachedValues[i->doc]->compareTo (cachedValues[j->doc]); + } + + CL_NS(util)::Comparable* sortValue (struct ScoreDoc* i){ + CND_PRECONDITION(i->doc >= 0 && i->doc < cachedValuesLen, "i->doc out of range") + return cachedValues[i->doc]; + } + + int32_t sortType(){ + return SortField::CUSTOM; + } +}; + +ScoreDocComparator* SortComparator::newComparator (CL_NS(index)::IndexReader* reader, const TCHAR* fieldname){ + return _CLNEW ScoreDocComparatorImpl(FieldCache::DEFAULT->getCustom (reader, fieldname, this)); +} +SortComparator::SortComparator(){ +} +SortComparator::~SortComparator(){ +} + + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/Sort.h b/3rdparty/clucene/src/CLucene/search/Sort.h new file mode 100644 index 000000000..cfe96d56c --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/Sort.h @@ -0,0 +1,356 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_Sort_ +#define _lucene_search_Sort_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/index/IndexReader.h" +#include "SearchHeader.h" + +CL_NS_DEF(search) + + class SortField; //predefine + class Sort; + +/** + * Expert: Compares two ScoreDoc objects for sorting. + * + */ + class ScoreDocComparator:LUCENE_BASE { + protected: + ScoreDocComparator(){} + public: + virtual ~ScoreDocComparator(); +// CL_NS(util)::Comparable** cachedValues; +// ScoreDocComparator(CL_NS(util)::Comparable** cachedValues); + + /** + * Compares two ScoreDoc objects and returns a result indicating their + * sort order. + * @param i First ScoreDoc + * @param j Second ScoreDoc + * @return -1 if i should come before j
1 if i should come after j
0 if they are equal + * @see java.util.Comparator + */ + virtual int32_t compare (struct ScoreDoc* i, struct ScoreDoc* j) = 0; + + /** + * Returns the value used to sort the given document. The + * object returned must implement the java.io.Serializable + * interface. This is used by multisearchers to determine how to collate results from their searchers. + * @see FieldDoc + * @param i Document + * @return Serializable object + */ + virtual CL_NS(util)::Comparable* sortValue (struct ScoreDoc* i) = 0; + + + /** + * Returns the type of sort. Should return SortField.SCORE, SortField.DOC, SortField.STRING, SortField.INTEGER, + * SortField::FLOAT or SortField.CUSTOM. It is not valid to return SortField.AUTO. + * This is used by multisearchers to determine how to collate results from their searchers. + * @return One of the constants in SortField. + * @see SortField + */ + virtual int32_t sortType() = 0; + + /** Special comparator for sorting hits according to computed relevance (document score). */ + static ScoreDocComparator* RELEVANCE; + + /** Special comparator for sorting hits according to index order (document number). */ + static ScoreDocComparator* INDEXORDER; + }; + +/** + * Expert: returns a comparator for sorting ScoreDocs. + * + */ +class SortComparatorSource:LUCENE_BASE { +public: + virtual ~SortComparatorSource(){ + } + + /** + * return a reference to a string describing the name of the comparator + * this is used in the explanation + */ + virtual TCHAR* getName() = 0; + + virtual size_t hashCode() = 0; + + /** + * Creates a comparator for the field in the given index. + * @param reader Index to create comparator for. + * @param fieldname Field to create comparator for. + * @return Comparator of ScoreDoc objects. + * @throws IOException If an error occurs reading the index. + */ + virtual ScoreDocComparator* newComparator (CL_NS(index)::IndexReader* reader, const TCHAR* fieldname) = 0; +}; + + +/** + * Abstract base class for sorting hits returned by a Query. + * + *

This class should only be used if the other SortField + * types (SCORE, DOC, STRING, INT, FLOAT) do not provide an + * adequate sorting. It maintains an internal cache of values which + * could be quite large. The cache is an array of Comparable, + * one for each document in the index. There is a distinct + * Comparable for each unique term in the field - if + * some documents have the same term in the field, the cache + * array will have entries which reference the same Comparable. + * + */ +class SortComparator: public SortComparatorSource { +public: + virtual ScoreDocComparator* newComparator (CL_NS(index)::IndexReader* reader, const TCHAR* fieldname); + + SortComparator(); + virtual ~SortComparator(); + + /** + * Returns an object which, when sorted according to natural order, + * will order the Term values in the correct order. + *

For example, if the Terms contained integer values, this method + * would return new Integer(termtext). Note that this + * might not always be the most efficient implementation - for this + * particular example, a better implementation might be to make a + * ScoreDocLookupComparator that uses an internal lookup table of int. + * @param termtext The textual value of the term. + * @return An object representing termtext that sorts + * according to the natural order of termtext. + * @see Comparable + * @see ScoreDocComparator + */ + virtual CL_NS(util)::Comparable* getComparable (const TCHAR* termtext) = 0; + +}; + + +/** + * Stores information about how to sort documents by terms in an individual + * field. Fields must be indexed in order to sort by them. + * + */ +class SortField:LUCENE_BASE { +private: + const TCHAR* field; + int32_t type; // defaults to determining type dynamically + //Locale* locale; // defaults to "natural order" (no Locale) + bool reverse; // defaults to natural order + SortComparatorSource* factory; + +protected: + SortField (const SortField& clone); +public: + virtual ~SortField(); + + /** Sort by document score (relevancy). Sort values are Float and higher + * values are at the front. + * PORTING: this is the same as SCORE in java, it had to be renamed because + * SCORE is a system macro on some platforms (AIX). + */ + LUCENE_STATIC_CONSTANT(int32_t, DOCSCORE=0); + + /** Sort by document number (index order). Sort values are Integer and lower + * values are at the front. */ + LUCENE_STATIC_CONSTANT(int32_t, DOC=1); + + /** Guess type of sort based on field contents. A regular expression is used + * to look at the first term indexed for the field and determine if it + * represents an integer number, a floating point number, or just arbitrary + * string characters. */ + LUCENE_STATIC_CONSTANT(int32_t, AUTO=2); + + /** Sort using term values as Strings. Sort values are String and lower + * values are at the front. */ + LUCENE_STATIC_CONSTANT(int32_t, STRING=3); + + /** Sort using term values as encoded Integers. Sort values are Integer and + * lower values are at the front. */ + LUCENE_STATIC_CONSTANT(int32_t, INT=4); + + /** Sort using term values as encoded Floats. Sort values are Float and + * lower values are at the front. */ + LUCENE_STATIC_CONSTANT(int32_t, FLOAT=5); + + /** Sort using a custom Comparator. Sort values are any Comparable and + * sorting is done according to natural order. */ + LUCENE_STATIC_CONSTANT(int32_t, CUSTOM=9); + + // IMPLEMENTATION NOTE: the FieldCache.STRING_INDEX is in the same "namespace" + // as the above static int values. Any new values must not have the same value + // as FieldCache.STRING_INDEX. + + /** Represents sorting by document score (relevancy). */ + static SortField* FIELD_SCORE; + + /** Represents sorting by document number (index order). */ + static SortField* FIELD_DOC; + + SortField (const TCHAR* field); + //SortField (const TCHAR* field, bool reverse); + //todo: we cannot make reverse use default field of =false. + //because bool and int are the same type in c, overloading is not possible + SortField (const TCHAR* field, int32_t type, bool reverse); + + /* + SortField (TCHAR* field, Locale* locale) { + SortField (TCHAR* field, Locale* locale, bool reverse);*/ + + SortField (const TCHAR* field, SortComparatorSource* comparator, bool reverse=false); + + /** Returns the name of the field. Could return null + * if the sort is by SCORE or DOC. + * @return Name of field, possibly null. + */ + const TCHAR* getField() const { return field; } + + SortField* clone() const; + + /** Returns the type of contents in the field. + * @return One of the constants SCORE, DOC, AUTO, STRING, INT or FLOAT. + */ + int32_t getType() const { return type; } + + /** Returns the Locale by which term values are interpreted. + * May return null if no Locale was specified. + * @return Locale, or null. + */ + /*Locale getLocale() { + return locale; + }*/ + + /** Returns whether the sort should be reversed. + * @return True if natural order should be reversed. + */ + bool getReverse() const { return reverse; } + + SortComparatorSource* getFactory() const { return factory; } + + TCHAR* toString() const; +}; + + + +/** + * Encapsulates sort criteria for returned hits. + * + *

The fields used to determine sort order must be carefully chosen. + * Documents must contain a single term in such a field, + * and the value of the term should indicate the document's relative position in + * a given sort order. The field must be indexed, but should not be tokenized, + * and does not need to be stored (unless you happen to want it back with the + * rest of your document data). In other words: + * + *

document.add (new Field ("byNumber", Integer.toString(x), false, true, false)); + *
+ * + *

Valid Types of Values

+ * + *

There are three possible kinds of term values which may be put into + * sorting fields: Integers, Floats, or Strings. Unless + * {@link SortField SortField} objects are specified, the type of value + * in the field is determined by parsing the first term in the field. + * + *

Integer term values should contain only digits and an optional + * preceeding negative sign. Values must be base 10 and in the range + * Integer.MIN_VALUE and Integer.MAX_VALUE inclusive. + * Documents which should appear first in the sort + * should have low value integers, later documents high values + * (i.e. the documents should be numbered 1..n where + * 1 is the first and n the last). + * + *

Float term values should conform to values accepted by + * {@link Float Float.valueOf(String)} (except that NaN + * and Infinity are not supported). + * Documents which should appear first in the sort + * should have low values, later documents high values. + * + *

String term values can contain any valid String, but should + * not be tokenized. The values are sorted according to their + * {@link Comparable natural order}. Note that using this type + * of term value has higher memory requirements than the other + * two types. + * + *

Object Reuse

+ * + *

One of these objects can be + * used multiple times and the sort order changed between usages. + * + *

This class is thread safe. + * + *

Memory Usage

+ * + *

Sorting uses of caches of term values maintained by the + * internal HitQueue(s). The cache is static and contains an integer + * or float array of length IndexReader.maxDoc() for each field + * name for which a sort is performed. In other words, the size of the + * cache in bytes is: + * + *

4 * IndexReader.maxDoc() * (# of different fields actually used to sort) + * + *

For String fields, the cache is larger: in addition to the + * above array, the value of every term in the field is kept in memory. + * If there are many unique terms in the field, this could + * be quite large. + * + *

Note that the size of the cache is not affected by how many + * fields are in the index and might be used to sort - only by + * the ones actually used to sort a result set. + * + *

The cache is cleared each time a new IndexReader is + * passed in, or if the value returned by maxDoc() + * changes for the current IndexReader. This class is not set up to + * be able to efficiently sort hits from more than one index + * simultaneously. + * + */ +class Sort:LUCENE_BASE { + // internal representation of the sort criteria + SortField** fields; + void clear(); +public: + ~Sort(); + + /** Represents sorting by computed relevance. Using this sort criteria + * returns the same results as calling {@link Searcher#search(Query) Searcher#search()} + * without a sort criteria, only with slightly more overhead. */ + static Sort* RELEVANCE; + + /** Represents sorting by index order. */ + static Sort* INDEXORDER; + + Sort(); + Sort (const TCHAR* field, bool reverse=false); + Sort (const TCHAR** fields); + Sort (SortField* field); + Sort (SortField** fields); + void setSort (const TCHAR* field, bool reverse=false); + void setSort (const TCHAR** fieldnames); + void setSort (SortField* field); + void setSort (SortField** fields); + + TCHAR* toString() const; + + /** + * Representation of the sort criteria. + * @return a pointer to the of SortField array used in this sort criteria + */ + SortField** getSort() const{ return fields; } +}; + + + + + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/TermQuery.cpp b/3rdparty/clucene/src/CLucene/search/TermQuery.cpp new file mode 100644 index 000000000..a04c20fec --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/TermQuery.cpp @@ -0,0 +1,213 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "TermQuery.h" + +#include "SearchHeader.h" +#include "Scorer.h" +#include "CLucene/index/Term.h" +#include "TermScorer.h" +#include "CLucene/index/IndexReader.h" +#include "CLucene/util/StringBuffer.h" +#include "CLucene/index/Terms.h" + +CL_NS_USE(index) +CL_NS_DEF(search) + + + /** Constructs a query for the term t. */ + TermQuery::TermQuery(Term* t): + term( _CL_POINTER(t) ) + { + } + TermQuery::TermQuery(const TermQuery& clone): + Query(clone){ + this->term=_CL_POINTER(clone.term); + } + TermQuery::~TermQuery(){ + _CLDECDELETE(term); + } + + Query* TermQuery::clone() const{ + return _CLNEW TermQuery(*this); + } + + const TCHAR* TermQuery::getClassName(){ + return _T("TermQuery"); + } + const TCHAR* TermQuery::getQueryName() const{ + return getClassName(); + } + size_t TermQuery::hashCode() const { + return Similarity::floatToByte(getBoost()) ^ term->hashCode(); + } + + + //added by search highlighter + Term* TermQuery::getTerm(bool pointer) const + { + if ( pointer ) + return _CL_POINTER(term); + else + return term; + } + + + /** Prints a user-readable version of this query. */ + TCHAR* TermQuery::toString(const TCHAR* field) const{ + CL_NS(util)::StringBuffer buffer; + if ( field==NULL || _tcscmp(term->field(),field)!= 0 ) { + buffer.append(term->field()); + buffer.append(_T(":")); + } + buffer.append(term->text()); + if (getBoost() != 1.0f) { + buffer.append(_T("^")); + buffer.appendFloat( getBoost(),1 ); + } + return buffer.toString(); + } + + /** Returns true iff o is equal to this. */ + bool TermQuery::equals(Query* other) const { + if (!(other->instanceOf(TermQuery::getClassName()))) + return false; + + TermQuery* tq = (TermQuery*)other; + return (this->getBoost() == tq->getBoost()) + && this->term->equals(tq->term); + } + + + TermQuery::TermWeight::TermWeight(Searcher* searcher, TermQuery* _this, Term* _term) { + this->_this = _this; + this->_term = _term; + this->searcher = searcher; + value=0; + idf=0; + queryNorm=0; + queryWeight=0; + } + TermQuery::TermWeight::~TermWeight(){ + } + + //return a *new* string describing this object + TCHAR* TermQuery::TermWeight::toString() { + int32_t size=_tcslen(_this->getQueryName()) + 10; + TCHAR* tmp = _CL_NEWARRAY(TCHAR, size);//_tcslen(weight()) + _sntprintf(tmp,size,_T("weight(%s)"),_this->getQueryName()); + return tmp; + } + + qreal TermQuery::TermWeight::sumOfSquaredWeights() { + idf = _this->getSimilarity(searcher)->idf(_term, searcher); // compute idf + queryWeight = idf * _this->getBoost(); // compute query weight + return queryWeight * queryWeight; // square it + } + + void TermQuery::TermWeight::normalize(qreal queryNorm) { + this->queryNorm = queryNorm; + queryWeight *= queryNorm; // normalize query weight + value = queryWeight * idf; // idf for document + } + + Scorer* TermQuery::TermWeight::scorer(IndexReader* reader) { + TermDocs* termDocs = reader->termDocs(_term); + + if (termDocs == NULL) + return NULL; + + return _CLNEW TermScorer(this, termDocs, _this->getSimilarity(searcher), + reader->norms(_term->field())); + } + + void TermQuery::TermWeight::explain(IndexReader* reader, int32_t doc, Explanation* result){ + TCHAR buf[LUCENE_SEARCH_EXPLANATION_DESC_LEN]; + TCHAR* tmp; + + tmp = getQuery()->toString(); + _sntprintf(buf,LUCENE_SEARCH_EXPLANATION_DESC_LEN, + _T("weight(%s in %d), product of:"),tmp,doc); + _CLDELETE_CARRAY(tmp); + result->setDescription(buf); + + _sntprintf(buf,LUCENE_SEARCH_EXPLANATION_DESC_LEN, + _T("idf(docFreq=%d)"), searcher->docFreq(_term) ); + Explanation* idfExpl = _CLNEW Explanation(idf, buf); + + // explain query weight + Explanation* queryExpl = _CLNEW Explanation(); + tmp = getQuery()->toString(); + _sntprintf(buf,LUCENE_SEARCH_EXPLANATION_DESC_LEN, + _T("queryWeight(%s), product of:"), tmp); + _CLDELETE_CARRAY(tmp); + queryExpl->setDescription(buf); + + Explanation* boostExpl = _CLNEW Explanation(_this->getBoost(), _T("boost")); + if (_this->getBoost() != 1.0f) + queryExpl->addDetail(boostExpl); + else + _CLDELETE(boostExpl); + + queryExpl->addDetail(idfExpl->clone()); + + Explanation* queryNormExpl = _CLNEW Explanation(queryNorm,_T("queryNorm")); + queryExpl->addDetail(queryNormExpl); + + queryExpl->setValue(_this->getBoost()* // always 1.0 + idfExpl->getValue() * + queryNormExpl->getValue()); + + // explain field weight + const TCHAR* field = _term->field(); + Explanation* fieldExpl = _CLNEW Explanation(); + + tmp = _term->toString(); + _sntprintf(buf,LUCENE_SEARCH_EXPLANATION_DESC_LEN, + _T("fieldWeight(%s in %d), product of:"),tmp,doc); + _CLDELETE_CARRAY(tmp); + fieldExpl->setDescription(buf); + + Scorer* sc = scorer(reader); + Explanation* tfExpl = _CLNEW Explanation; + sc->explain(doc, tfExpl); + _CLDELETE(sc); + fieldExpl->addDetail(tfExpl); + fieldExpl->addDetail(idfExpl); + + Explanation* fieldNormExpl = _CLNEW Explanation(); + uint8_t* fieldNorms = reader->norms(field); + qreal fieldNorm = + fieldNorms!=NULL ? Similarity::decodeNorm(fieldNorms[doc]) : 0.0f; + fieldNormExpl->setValue(fieldNorm); + + _sntprintf(buf,LUCENE_SEARCH_EXPLANATION_DESC_LEN, + _T("fieldNorm(field=%s, doc=%d)"),field,doc); + fieldNormExpl->setDescription(buf); + fieldExpl->addDetail(fieldNormExpl); + + fieldExpl->setValue(tfExpl->getValue() * + idfExpl->getValue() * + fieldNormExpl->getValue()); + + /*if (queryExpl->getValue() == 1.0f){ + _CLDELETE(result); + return fieldExpl; + }else{*/ + result->addDetail(queryExpl); + result->addDetail(fieldExpl); + + // combine them + result->setValue(queryExpl->getValue() * fieldExpl->getValue()); + //} + } + + Weight* TermQuery::_createWeight(Searcher* searcher) { + return _CLNEW TermWeight(searcher,this,term); + } +CL_NS_END + diff --git a/3rdparty/clucene/src/CLucene/search/TermQuery.h b/3rdparty/clucene/src/CLucene/search/TermQuery.h new file mode 100644 index 000000000..a7dd8039b --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/TermQuery.h @@ -0,0 +1,81 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_TermQuery_ +#define _lucene_search_TermQuery_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "SearchHeader.h" +#include "Scorer.h" +#include "CLucene/index/Term.h" +#include "TermScorer.h" +#include "CLucene/index/IndexReader.h" +#include "CLucene/util/StringBuffer.h" +#include "CLucene/index/Terms.h" + +CL_NS_DEF(search) + + + /** A Query that matches documents containing a term. + This may be combined with other terms with a {@link BooleanQuery}. + */ + class TermQuery: public Query { + private: + CL_NS(index)::Term* term; + + + class TermWeight: public Weight { + private: + Searcher* searcher; + qreal value; + qreal idf; + qreal queryNorm; + qreal queryWeight; + TermQuery* _this; + CL_NS(index)::Term* _term; + + public: + TermWeight(Searcher* searcher, TermQuery* _this, CL_NS(index)::Term* _term); + ~TermWeight(); + TCHAR* toString(); + Query* getQuery() { return (Query*)_this; } + qreal getValue() { return value; } + + qreal sumOfSquaredWeights(); + void normalize(qreal queryNorm); + Scorer* scorer(CL_NS(index)::IndexReader* reader); + void explain(CL_NS(index)::IndexReader* reader, int32_t doc, Explanation* ret); + }; + + protected: + Weight* _createWeight(Searcher* searcher); + TermQuery(const TermQuery& clone); + public: + // Constructs a query for the term t. + TermQuery(CL_NS(index)::Term* t); + ~TermQuery(); + + static const TCHAR* getClassName(); + const TCHAR* getQueryName() const; + + //added by search highlighter + CL_NS(index)::Term* getTerm(bool pointer=true) const; + + // Prints a user-readable version of this query. + TCHAR* toString(const TCHAR* field) const; + + bool equals(Query* other) const; + Query* clone() const; + + /** Returns a hash code value for this object.*/ + size_t hashCode() const; + }; +CL_NS_END +#endif + diff --git a/3rdparty/clucene/src/CLucene/search/TermScorer.cpp b/3rdparty/clucene/src/CLucene/search/TermScorer.cpp new file mode 100644 index 000000000..ddd7f74ed --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/TermScorer.cpp @@ -0,0 +1,120 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "TermScorer.h" + +#include "CLucene/index/Terms.h" +#include "TermQuery.h" + +CL_NS_USE(index) +CL_NS_DEF(search) + + //TermScorer takes TermDocs and delets it when TermScorer is cleaned up + TermScorer::TermScorer(Weight* w, CL_NS(index)::TermDocs* td, + Similarity* similarity,uint8_t* _norms): + Scorer(similarity), + termDocs(td), + norms(_norms), + weight(w), + weightValue(w->getValue()), + _doc(0), + pointer(0), + pointerMax(0) + { + memset(docs,0,32*sizeof(int32_t)); + memset(freqs,0,32*sizeof(int32_t)); + + for (int32_t i = 0; i < LUCENE_SCORE_CACHE_SIZE; i++) + scoreCache[i] = getSimilarity()->tf(i) * weightValue; + } + + TermScorer::~TermScorer(){ + _CLDELETE(termDocs); + } + bool TermScorer::next(){ + pointer++; + if (pointer >= pointerMax) { + pointerMax = termDocs->read(docs, freqs, 32); // refill buffer + if (pointerMax != 0) { + pointer = 0; + } else { + termDocs->close(); // close stream + _doc = LUCENE_INT32_MAX_SHOULDBE; // set to sentinel value + return false; + } + } + _doc = docs[pointer]; + return true; + } + + bool TermScorer::skipTo(int32_t target) { + // first scan in cache + for (pointer++; pointer < pointerMax; pointer++) { + if (docs[pointer] >= target) { + _doc = docs[pointer]; + return true; + } + } + + // not found in cache, seek underlying stream + bool result = termDocs->skipTo(target); + if (result) { + pointerMax = 1; + pointer = 0; + docs[pointer] = _doc = termDocs->doc(); + freqs[pointer] = termDocs->freq(); + } else { + _doc = LUCENE_INT32_MAX_SHOULDBE; + } + return result; + } + + void TermScorer::explain(int32_t doc, Explanation* tfExplanation) { + TermQuery* query = (TermQuery*)weight->getQuery(); + int32_t tf = 0; + while (pointer < pointerMax) { + if (docs[pointer] == doc) + tf = freqs[pointer]; + pointer++; + } + if (tf == 0) { + while (termDocs->next()) { + if (termDocs->doc() == doc) { + tf = termDocs->freq(); + } + } + } + termDocs->close(); + tfExplanation->setValue(getSimilarity()->tf(tf)); + + TCHAR buf[LUCENE_SEARCH_EXPLANATION_DESC_LEN+1]; + TCHAR* termToString = query->getTerm(false)->toString(); + _sntprintf(buf,LUCENE_SEARCH_EXPLANATION_DESC_LEN,_T("tf(termFreq(%s)=%d)"), termToString, tf); + _CLDELETE_CARRAY(termToString); + tfExplanation->setDescription(buf); + } + + TCHAR* TermScorer::toString() { + TCHAR* wb = weight->toString(); + int32_t rl = _tcslen(wb) + 9; //9=_tcslen("scorer(" ")") + 1 + TCHAR* ret = _CL_NEWARRAY(TCHAR,rl); + _sntprintf(ret,rl,_T("scorer(%s)"), wb); + _CLDELETE_ARRAY(wb); + return ret; + } + + qreal TermScorer::score(){ + int32_t f = freqs[pointer]; + qreal raw = // compute tf(f)*weight + f < LUCENE_SCORE_CACHE_SIZE // check cache + ? scoreCache[f] // cache hit + : getSimilarity()->tf(f) * weightValue; // cache miss + + return raw * Similarity::decodeNorm(norms[_doc]); // normalize for field + } + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/TermScorer.h b/3rdparty/clucene/src/CLucene/search/TermScorer.h new file mode 100644 index 000000000..ccbf5f7ec --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/TermScorer.h @@ -0,0 +1,53 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_TermScorer_ +#define _lucene_search_TermScorer_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "Scorer.h" +#include "CLucene/index/Terms.h" +#include "CLucene/search/Similarity.h" +#include "SearchHeader.h" + +CL_NS_DEF(search) + + class TermScorer: public Scorer { + private: + CL_NS(index)::TermDocs* termDocs; + uint8_t* norms; + Weight* weight; + const qreal weightValue; + int32_t _doc; + + int32_t docs[32]; // buffered doc numbers + int32_t freqs[32]; // buffered term freqs + int32_t pointer; + int32_t pointerMax; + + qreal scoreCache[LUCENE_SCORE_CACHE_SIZE]; + public: + + //TermScorer takes TermDocs and delets it when TermScorer is cleaned up + TermScorer(Weight* weight, CL_NS(index)::TermDocs* td, + Similarity* similarity, uint8_t* _norms); + + ~TermScorer(); + + int32_t doc() const { return _doc; } + + bool next(); + bool skipTo(int32_t target); + void explain(int32_t doc, Explanation* ret); + TCHAR* toString(); + + qreal score(); + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/WildcardQuery.cpp b/3rdparty/clucene/src/CLucene/search/WildcardQuery.cpp new file mode 100644 index 000000000..9373cef0a --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/WildcardQuery.cpp @@ -0,0 +1,147 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "WildcardQuery.h" +#include "CLucene/util/BitSet.h" + +CL_NS_USE(index) +CL_NS_USE(util) +CL_NS_DEF(search) + + + WildcardQuery::WildcardQuery(Term* term): + MultiTermQuery( term ){ + //Func - Constructor + //Pre - term != NULL + //Post - Instance has been created + + } + + WildcardQuery::~WildcardQuery(){ + //Func - Destructor + //Pre - true + //Post - true + + } + + const TCHAR* WildcardQuery::getQueryName() const{ + //Func - Returns the string "WildcardQuery" + //Pre - true + //Post - The string "WildcardQuery" has been returned + return getClassName(); + } + + const TCHAR* WildcardQuery::getClassName(){ + return _T("WildcardQuery"); + } + + + FilteredTermEnum* WildcardQuery::getEnum(IndexReader* reader) { + return _CLNEW WildcardTermEnum(reader, getTerm(false)); + } + + WildcardQuery::WildcardQuery(const WildcardQuery& clone): + MultiTermQuery(clone) + { + } + + Query* WildcardQuery::clone() const{ + return _CLNEW WildcardQuery(*this); + } + size_t WildcardQuery::hashCode() const{ + //todo: we should give the query a seeding value... but + //need to do it for all hascode functions + return Similarity::floatToByte(getBoost()) ^ getTerm()->hashCode(); + } + bool WildcardQuery::equals(Query* other) const{ + if (!(other->instanceOf(WildcardQuery::getClassName()))) + return false; + + WildcardQuery* tq = (WildcardQuery*)other; + return (this->getBoost() == tq->getBoost()) + && getTerm()->equals(tq->getTerm()); + } + + + + + + + + + + + + +WildcardFilter::WildcardFilter( Term* term ) +{ + this->term = _CL_POINTER(term); +} + +WildcardFilter::~WildcardFilter() +{ + _CLDECDELETE(term); +} + +WildcardFilter::WildcardFilter( const WildcardFilter& copy ) : + term( _CL_POINTER(copy.term) ) +{ +} + +Filter* WildcardFilter::clone() const { + return _CLNEW WildcardFilter(*this ); +} + + +TCHAR* WildcardFilter::toString() +{ + //Instantiate a stringbuffer buffer to store the readable version temporarily + CL_NS(util)::StringBuffer buffer; + //check if field equal to the field of prefix + if( term->field() != NULL ) { + //Append the field of prefix to the buffer + buffer.append(term->field()); + //Append a colon + buffer.append(_T(":") ); + } + //Append the text of the prefix + buffer.append(term->text()); + + //Convert StringBuffer buffer to TCHAR block and return it + return buffer.toString(); +} + + +/** Returns a BitSet with true for documents which should be permitted in +search results, and false for those that should not. */ +BitSet* WildcardFilter::bits( IndexReader* reader ) +{ + BitSet* bts = _CLNEW BitSet( reader->maxDoc() ); + + WildcardTermEnum termEnum (reader, term); + if (termEnum.term(false) == NULL) + return bts; + + TermDocs* termDocs = reader->termDocs(); + try{ + do{ + termDocs->seek(&termEnum); + + while (termDocs->next()) { + bts->set(termDocs->doc()); + } + }while(termEnum.next()); + } _CLFINALLY( + termDocs->close(); + _CLDELETE(termDocs); + termEnum.close(); + ) + + return bts; +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/WildcardQuery.h b/3rdparty/clucene/src/CLucene/search/WildcardQuery.h new file mode 100644 index 000000000..cfc38f648 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/WildcardQuery.h @@ -0,0 +1,69 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_WildcardQuery_ +#define _lucene_search_WildcardQuery_ +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/index/IndexReader.h" +#include "CLucene/index/Term.h" +#include "MultiTermQuery.h" +#include "WildcardTermEnum.h" + +CL_NS_DEF(search) + + /** Implements the wildcard search query. Supported wildcards are *, which + * matches any character sequence (including the empty one), and ?, + * which matches any single character. Note this query can be slow, as it + * needs to iterate over all terms. In order to prevent extremely slow WildcardQueries, + * a Wildcard term must not start with one of the wildcards * or + * ?. + * + * @see WildcardTermEnum + */ + class WildcardQuery: public MultiTermQuery { + protected: + FilteredTermEnum* getEnum(CL_NS(index)::IndexReader* reader); + WildcardQuery(const WildcardQuery& clone); + public: + WildcardQuery(CL_NS(index)::Term* term); + ~WildcardQuery(); + + //Returns the string "WildcardQuery" + const TCHAR* getQueryName() const; + static const TCHAR* getClassName(); + + size_t hashCode() const; + bool equals(Query* other) const; + Query* clone() const; + }; + + + +class WildcardFilter: public Filter +{ +private: + CL_NS(index)::Term* term; +protected: + WildcardFilter( const WildcardFilter& copy ); + +public: + WildcardFilter(CL_NS(index)::Term* term); + ~WildcardFilter(); + + /** Returns a BitSet with true for documents which should be permitted in + search results, and false for those that should not. */ + CL_NS(util)::BitSet* bits( CL_NS(index)::IndexReader* reader ); + + Filter* clone() const; + TCHAR* toString(); +}; + + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/search/WildcardTermEnum.cpp b/3rdparty/clucene/src/CLucene/search/WildcardTermEnum.cpp new file mode 100644 index 000000000..bed9e6e0c --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/WildcardTermEnum.cpp @@ -0,0 +1,150 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "WildcardTermEnum.h" + +CL_NS_USE(index) +CL_NS_DEF(search) + + bool WildcardTermEnum::termCompare(Term* term) { + if ( term!=NULL && __term->field() == term->field() ) { + const TCHAR* searchText = term->text(); + const TCHAR* patternText = __term->text(); + if ( _tcsncmp( searchText, pre, preLen ) == 0 ){ + return wildcardEquals(patternText+preLen, __term->textLength()-preLen, 0, searchText, term->textLength(), preLen); + } + } + _endEnum = true; + return false; + } + + /** Creates new WildcardTermEnum */ + WildcardTermEnum::WildcardTermEnum(IndexReader* reader, Term* term): + FilteredTermEnum(), + __term(_CL_POINTER(term)), + fieldMatch(false), + _endEnum(false) + { + + pre = stringDuplicate(term->text()); + + const TCHAR* sidx = _tcschr( pre, LUCENE_WILDCARDTERMENUM_WILDCARD_STRING ); + const TCHAR* cidx = _tcschr( pre, LUCENE_WILDCARDTERMENUM_WILDCARD_CHAR ); + const TCHAR* tidx = sidx; + if (tidx == NULL) + tidx = cidx; + else if ( cidx && cidx > pre) + tidx = min(sidx, cidx); + CND_PRECONDITION(tidx != NULL, "tidx==NULL"); + int32_t idx = (int32_t)(tidx - pre); + preLen = idx; + CND_PRECONDITION(preLentextLength(), "preLen >= term->textLength()"); + pre[preLen]=0; //trim end + + Term* t = _CLNEW Term(__term, pre); + setEnum( reader->terms(t) ); + _CLDECDELETE(t); + } + + void WildcardTermEnum::close() + { + if ( __term != NULL ){ + FilteredTermEnum::close(); + + _CLDECDELETE(__term); + __term = NULL; + + _CLDELETE_CARRAY( pre ); + } + } + WildcardTermEnum::~WildcardTermEnum() { + close(); + } + + qreal WildcardTermEnum::difference() { + return 1.0f; + } + + bool WildcardTermEnum::endEnum() { + return _endEnum; + } + + bool WildcardTermEnum::wildcardEquals(const TCHAR* pattern, int32_t patternLen, int32_t patternIdx, const TCHAR* str, int32_t strLen, int32_t stringIdx) + { + for (int32_t p = patternIdx; ; ++p) + { + for (int32_t s = stringIdx; ; ++p, ++s) + { + // End of str yet? + bool sEnd = (s >= strLen); + // End of pattern yet? + bool pEnd = (p >= patternLen); + + // If we're looking at the end of the str... + if (sEnd) + { + // Assume the only thing left on the pattern is/are wildcards + bool justWildcardsLeft = true; + + // Current wildcard position + int32_t wildcardSearchPos = p; + // While we haven't found the end of the pattern, + // and haven't encountered any non-wildcard characters + while (wildcardSearchPos < patternLen && justWildcardsLeft) + { + // Check the character at the current position + TCHAR wildchar = pattern[wildcardSearchPos]; + // If it's not a wildcard character, then there is more + // pattern information after this/these wildcards. + + if (wildchar != LUCENE_WILDCARDTERMENUM_WILDCARD_CHAR && + wildchar != LUCENE_WILDCARDTERMENUM_WILDCARD_STRING){ + justWildcardsLeft = false; + }else{ + // to prevent "cat" matches "ca??" + if (wildchar == LUCENE_WILDCARDTERMENUM_WILDCARD_CHAR) + return false; + + wildcardSearchPos++; // Look at the next character + } + } + + // This was a prefix wildcard search, and we've matched, so + // return true. + if (justWildcardsLeft) + return true; + } + + // If we've gone past the end of the str, or the pattern, + // return false. + if (sEnd || pEnd) + break; + + // Match a single character, so continue. + if (pattern[p] == LUCENE_WILDCARDTERMENUM_WILDCARD_CHAR) + continue; + + if (pattern[p] == LUCENE_WILDCARDTERMENUM_WILDCARD_STRING) + { + // Look at the character beyond the '*'. + ++p; + // Examine the str, starting at the last character. + for (int32_t i = strLen; i >= s; --i) + { + if (wildcardEquals(pattern, patternLen, p, str, strLen, i)) + return true; + } + break; + } + if (pattern[p] != str[s]) + break; + } + return false; + } + } + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/search/WildcardTermEnum.h b/3rdparty/clucene/src/CLucene/search/WildcardTermEnum.h new file mode 100644 index 000000000..2a0373540 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/search/WildcardTermEnum.h @@ -0,0 +1,67 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_search_WildcardTermEnum_ +#define _lucene_search_WildcardTermEnum_ +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/index/IndexReader.h" +#include "CLucene/index/Term.h" +#include "CLucene/index/Terms.h" +#include "FilteredTermEnum.h" + +CL_NS_DEF(search) + /** + * Subclass of FilteredTermEnum for enumerating all terms that match the + * specified wildcard filter term-> + *

+ * Term enumerations are always ordered by term->compareTo(). Each term in + * the enumeration is greater than all that precede it. + */ + class WildcardTermEnum: public FilteredTermEnum { + private: + CL_NS(index)::Term* __term; + TCHAR* pre; + int32_t preLen; + bool fieldMatch; + bool _endEnum; + + /******************************************** + * const TCHAR* equality with support for wildcards + ********************************************/ + + protected: + bool termCompare(CL_NS(index)::Term* term) ; + + public: + + /** + * Creates a new WildcardTermEnum. Passing in a + * {@link Term Term} that does not contain a + * LUCENE_WILDCARDTERMENUM_WILDCARD_STRING or + * LUCENE_WILDCARDTERMENUM_WILDCARD_CHAR will cause an exception to be thrown. + */ + WildcardTermEnum(CL_NS(index)::IndexReader* reader, CL_NS(index)::Term* term); + ~WildcardTermEnum(); + + qreal difference() ; + + bool endEnum() ; + + /** + * Determines if a word matches a wildcard pattern. + */ + static bool wildcardEquals(const TCHAR* pattern, int32_t patternLen, int32_t patternIdx, const TCHAR* str, int32_t strLen, int32_t stringIdx); + + void close(); + + const char* getObjectName(){ return WildcardTermEnum::getClassName(); } + static const char* getClassName(){ return "WildcardTermEnum"; } + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/store/Directory.h b/3rdparty/clucene/src/CLucene/store/Directory.h new file mode 100644 index 000000000..818bc7af9 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/store/Directory.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +*/ +#ifndef _lucene_store_Directory +#define _lucene_store_Directory + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include + +#include "CLucene/store/Lock.h" +#include "CLucene/util/VoidList.h" +#include "CLucene/util/Misc.h" + +#include "IndexInput.h" +#include "IndexOutput.h" + +CL_NS_DEF(store) + +/** A Directory is a flat list of files. Files may be written once, when they +* are created. Once a file is created it may only be opened for read, or +* deleted. Random access is permitted both when reading and writing. +* +*

Direct i/o is not used directly, but rather all i/o is +* through this API. This permits things such as:

    +*
  • implementation of RAM-based indices; +*
  • implementation indices stored in a database, via a database; +*
  • implementation of an index as a single file; +*
+* +*/ +class Directory : LUCENE_REFBASE +{ +protected: + Directory() {} + // Removes an existing file in the directory. + virtual bool doDeleteFile(const QString& name) = 0; + +public: + DEFINE_MUTEX(THIS_LOCK) + + virtual ~Directory() {}; + + // Returns an array of strings, one for each file in the directory. + virtual QStringList list() const = 0; + + // Returns true iff a file with the given name exists. + virtual bool fileExists(const QString& name) const = 0; + + // Returns the time the named file was last modified. + virtual int64_t fileModified(const QString& name) const = 0; + + // Returns the length of a file in the directory. + virtual int64_t fileLength(const QString& name) const = 0; + + // Returns a stream reading an existing file. + virtual IndexInput* openInput(const QString& name) = 0; + virtual IndexInput* openInput(const QString& name, int32_t bufferSize) + { + // didnt overload bufferSize + return openInput(name); + } + + // Set the modified time of an existing file to now. + virtual void touchFile(const QString& name) = 0; + + // Removes an existing file in the directory. + virtual bool deleteFile(const QString& name, const bool throwError = true) { + bool ret = doDeleteFile(name); + if (!ret && throwError) { + char buffer[200]; + _snprintf(buffer, 200, "couldn't delete file %s", + name.toLocal8Bit().constData()); + _CLTHROWA(CL_ERR_IO, buffer); + } + return ret; + } + + // Renames an existing file in the directory. + // If a file already exists with the new name, then it is replaced. + virtual void renameFile(const QString& from, const QString& to) = 0; + + // Creates a new, empty file in the directory with the given name. + // Returns a stream writing this file. + virtual IndexOutput* createOutput(const QString& name) = 0; + + // Construct a {@link Lock}. + // @param name the name of the lock file + virtual LuceneLock* makeLock(const QString& name) = 0; + + // Closes the store. + virtual void close() = 0; + + virtual QString toString() const = 0; + + virtual QString getDirectoryType() const = 0; +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/store/FSDirectory.cpp b/3rdparty/clucene/src/CLucene/store/FSDirectory.cpp new file mode 100644 index 000000000..5f96e91cd --- /dev/null +++ b/3rdparty/clucene/src/CLucene/store/FSDirectory.cpp @@ -0,0 +1,662 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +*/ +#include +#include +#include +#include +#include + +#include "CLucene/StdHeader.h" +#include "FSDirectory.h" +#include "CLucene/index/IndexReader.h" +#include "CLucene/util/Misc.h" +#include "CLucene/debug/condition.h" + +CL_NS_DEF(store) +CL_NS_USE(util) + +bool FSDirectory::disableLocks = false; + +// This cache of directories ensures that there is a unique Directory instance +// per path, so that synchronization on the Directory can be used to synchronize +// access between readers and writers. +static CL_NS(util)::CLHashMap DIRECTORIES(false, false); + +// # pragma mark -- FSDirectory::FSLock + +FSDirectory::FSLock::FSLock(const QString& _lockDir, const QString& name) + : lockDir(_lockDir) + , lockFile(_lockDir + QDir::separator() + name) +{ +} + +FSDirectory::FSLock::~FSLock() +{ +} + +bool FSDirectory::FSLock::obtain() +{ + if (disableLocks) + return true; + + if (QFile::exists(lockFile)) + return false; + + QDir dir(lockDir); + if (!dir.exists()) { + if (!dir.mkpath(lockDir)) { + // 34: len of "Couldn't create lock directory: " + char* err = _CL_NEWARRAY( + char, 34 + strlen(lockDir.toLocal8Bit().constData()) + 1); + strcpy(err, "Couldn't create lock directory: "); + strcat(err, lockDir.toLocal8Bit().constData()); + _CLTHROWA_DEL(CL_ERR_IO, err); + } + } + + QFile file(lockFile); + return file.open(QIODevice::ReadWrite); +} + +void FSDirectory::FSLock::release() +{ + if (disableLocks) + return; + + QFile file(lockFile); + file.remove(); +} + +bool FSDirectory::FSLock::isLocked() +{ + if (disableLocks) + return false; + return QFile::exists(lockFile); +} + +QString FSDirectory::FSLock::toString() const +{ + QString ret(QLatin1String("Lock@")); + return ret.append(lockFile); +} + +// # pragma mark -- FSDirectory::FSIndexInput + +FSDirectory::FSIndexInput::FSIndexInput(const QString& path, int32_t bufferSize) + : BufferedIndexInput(bufferSize) +{ + CND_PRECONDITION(!path.isEmpty(), "path is NULL"); + + handle = _CLNEW SharedHandle(); + handle->fhandle.setFileName(path); + handle->fhandle.open(QIODevice::ReadOnly); + + if (handle->fhandle.error() != QFile::NoError) { + switch(handle->fhandle.error()) { + case 1: + _CLTHROWA(CL_ERR_IO, "An error occurred when reading from the file"); + break; + case 2: + _CLTHROWA(CL_ERR_IO, "An error occurred when writing to the file."); + break; + case 5: + _CLTHROWA(CL_ERR_IO, "The file could not be opened."); + break; + case 6: + _CLTHROWA(CL_ERR_IO, "The operation was aborted."); + break; + case 7: + _CLTHROWA(CL_ERR_IO, "A timeout occurred."); + break; + case 8: + _CLTHROWA(CL_ERR_IO, "An unspecified error occurred."); + break; + case 9: + _CLTHROWA(CL_ERR_IO, "The file could not be removed."); + break; + case 10: + _CLTHROWA(CL_ERR_IO, "The file could not be renamed."); + break; + case 11: + _CLTHROWA(CL_ERR_IO, "The position in the file could not be changed."); + break; + case 12: + _CLTHROWA(CL_ERR_IO, "The file could not be resized.e"); + break; + case 13: + _CLTHROWA(CL_ERR_IO, "The file could not be accessed."); + break; + case 14: + _CLTHROWA(CL_ERR_IO, "The file could not be copied."); + break; + case 4: + default: + _CLTHROWA(CL_ERR_IO, "A fatal error occurred."); + } + } + + //Store the file length + handle->_length = handle->fhandle.size(); + handle->_fpos = 0; + this->_pos = 0; +} + +FSDirectory::FSIndexInput::FSIndexInput(const FSIndexInput& other) + : BufferedIndexInput(other) +{ + if (other.handle == NULL) + _CLTHROWA(CL_ERR_NullPointer, "other handle is null"); + + SCOPED_LOCK_MUTEX(*other.handle->THIS_LOCK) + + _pos = other.handle->_fpos; + handle = _CL_POINTER(other.handle); +} + +FSDirectory::FSIndexInput::~FSIndexInput() +{ + FSIndexInput::close(); +} + +void FSDirectory::FSIndexInput::close() +{ + BufferedIndexInput::close(); +#ifdef _LUCENE_THREADMUTEX + if (handle != NULL) { + // Here we have a bit of a problem... We need to lock the handle to + // ensure that we can safely delete the handle... But if we delete the + // handle, then the scoped unlock, won't be able to unlock the mutex... + + // take a reference of the lock object... + _LUCENE_THREADMUTEX* mutex = handle->THIS_LOCK; + //lock the mutex + mutex->lock(); + + // determine if we are about to delete the handle... + bool doUnlock = (handle->__cl_refcount > 1); + // decdelete (deletes if refcount is down to 0) + _CLDECDELETE(handle); + + if (doUnlock) + mutex->unlock(); + else + delete mutex; + } +#else + _CLDECDELETE(handle); +#endif +} + +IndexInput* FSDirectory::FSIndexInput::clone() const +{ + return _CLNEW FSDirectory::FSIndexInput(*this); +} + +void FSDirectory::FSIndexInput::seekInternal(const int64_t position) +{ + CND_PRECONDITION(position >= 0 && position < handle->_length, + "Seeking out of range") + _pos = position; +} + +void FSDirectory::FSIndexInput::readInternal(uint8_t* b, const int32_t len) +{ + SCOPED_LOCK_MUTEX(*handle->THIS_LOCK) + + CND_PRECONDITION(handle != NULL, "shared file handle has closed"); + CND_PRECONDITION(handle->fhandle.isOpen(), "file is not open"); + + if (handle->_fpos != _pos) { + handle->fhandle.seek(_pos); + if (handle->fhandle.pos() != _pos) + _CLTHROWA( CL_ERR_IO, "File IO Seek error"); + handle->_fpos = _pos; + } + + bufferLength = (int32_t)handle->fhandle.read((char*)b, len); + if (bufferLength == 0) + _CLTHROWA(CL_ERR_IO, "read past EOF"); + + if (bufferLength == -1) + _CLTHROWA(CL_ERR_IO, "read error"); + + _pos += bufferLength; + handle->_fpos =_pos; +} + +// # pragma mark -- FSDirectory::FSIndexInput::SharedHandle + +FSDirectory::FSIndexInput::SharedHandle::SharedHandle() + : _fpos(0) + , _length(0) +{ +#ifdef _LUCENE_THREADMUTEX + THIS_LOCK = new _LUCENE_THREADMUTEX; +#endif +} + +FSDirectory::FSIndexInput::SharedHandle::~SharedHandle() +{ + if (fhandle.isOpen()) + fhandle.close(); +} + +// # pragma mark -- FSDirectory::FSIndexOutput + +FSDirectory::FSIndexOutput::FSIndexOutput(const QString& path) +{ + //O_BINARY - Opens file in binary (untranslated) mode + //O_CREAT - Creates and opens new file for writing. Has no effect if file specified by filename exists + //O_RANDOM - Specifies that caching is optimized for, but not restricted to, random access from disk. + //O_WRONLY - Opens file for writing only; + fhandle.setFileName(path); + fhandle.open(QIODevice::ReadWrite | QIODevice::Truncate); + + if (fhandle.error() != QFile::NoError) { + switch(fhandle.error()) { + case 1: + _CLTHROWA(CL_ERR_IO, "An error occurred when reading from the file"); + break; + case 2: + _CLTHROWA(CL_ERR_IO, "An error occurred when writing to the file."); + break; + case 5: + _CLTHROWA(CL_ERR_IO, "The file could not be opened."); + break; + case 6: + _CLTHROWA(CL_ERR_IO, "The operation was aborted."); + break; + case 7: + _CLTHROWA(CL_ERR_IO, "A timeout occurred."); + break; + case 8: + _CLTHROWA(CL_ERR_IO, "An unspecified error occurred."); + break; + case 9: + _CLTHROWA(CL_ERR_IO, "The file could not be removed."); + break; + case 10: + _CLTHROWA(CL_ERR_IO, "The file could not be renamed."); + break; + case 11: + _CLTHROWA(CL_ERR_IO, "The position in the file could not be changed."); + break; + case 12: + _CLTHROWA(CL_ERR_IO, "The file could not be resized.e"); + break; + case 13: + _CLTHROWA(CL_ERR_IO, "The file could not be accessed."); + break; + case 14: + _CLTHROWA(CL_ERR_IO, "The file could not be copied."); + break; + case 4: + default: + _CLTHROWA(CL_ERR_IO, "A fatal error occurred."); + } + } +} + +FSDirectory::FSIndexOutput::~FSIndexOutput() +{ + if (fhandle.isOpen()) { + try { + FSIndexOutput::close(); + } catch (CLuceneError& err) { + //ignore IO errors... + if (err.number() != CL_ERR_IO) + throw; + } + } +} + +void FSDirectory::FSIndexOutput::close() +{ + try { + BufferedIndexOutput::close(); + } catch (CLuceneError& err) { + //ignore IO errors... + if (err.number() != CL_ERR_IO) + throw; + } + fhandle.close(); +} + +int64_t FSDirectory::FSIndexOutput::length() +{ + CND_PRECONDITION(fhandle.isOpen(), "file is not open"); + return fhandle.size(); +} + +void FSDirectory::FSIndexOutput::seek(const int64_t pos) +{ + CND_PRECONDITION(fhandle.isOpen(), "file is not open"); + + BufferedIndexOutput::seek(pos); + fhandle.seek(pos); + if (fhandle.pos() != pos) + _CLTHROWA(CL_ERR_IO, "File IO Seek error"); +} + +void FSDirectory::FSIndexOutput::flushBuffer(const uint8_t* b, const int32_t size) +{ + CND_PRECONDITION(fhandle.isOpen(), "file is not open"); + + if (size > 0 && fhandle.write((const char*)b, size) != size) + _CLTHROWA(CL_ERR_IO, "File IO Write error"); +} + +// # pragma mark -- FSDirectory + +FSDirectory::FSDirectory(const QString& path, const bool createDir) + : Directory() + , refCount(0) + , useMMap(false) +{ + //set a realpath so that if we change directory, we can still function + directory = QFileInfo(path).absoluteFilePath(); + lockDir = directory; + + QDir dir(lockDir); + if (!dir.exists()) { + if (!dir.mkpath(lockDir)) + _CLTHROWA_DEL(CL_ERR_IO, "Cannot create temp directory"); + } + + QFileInfo info(lockDir); + if (info.isFile() || info.isSymLink()) + _CLTHROWA(CL_ERR_IO, "Found regular file where directory expected"); + + if (createDir) + create(); + + dir.setPath(directory); + if (!dir.exists()) { + //19: len of " is not a directory" + char* err = + _CL_NEWARRAY(char, 19 + strlen(path.toLocal8Bit().constData()) + 1); + strcpy(err, path.toLocal8Bit().constData()); + strcat(err, " is not a directory"); + _CLTHROWA_DEL(CL_ERR_IO, err); + } +} + +void FSDirectory::create() +{ + SCOPED_LOCK_MUTEX(THIS_LOCK) + + bool clear = false; + QDir dir(directory); + if (!dir.exists()) { + if (!dir.mkpath(directory)) { + char* err = _CL_NEWARRAY( // 27 len of "Couldn't create directory:" + char, 27 + strlen(directory.toLocal8Bit().constData()) + 1); + strcpy(err, "Couldn't create directory: "); + strcat(err, directory.toLocal8Bit().constData()); + _CLTHROWA_DEL(CL_ERR_IO, err); + } + } else { + clear = true; + } + + QFileInfo info(directory); + if (info.isFile() || info.isSymLink()) { + char tmp[1024]; + _snprintf(tmp, 1024, "%s not a directory", + directory.toLocal8Bit().constData()); + _CLTHROWA(CL_ERR_IO, tmp); + } + + if (clear) { + dir.setPath(directory); + // clear probably existing lucene index files + QStringList fileList = dir.entryList(QDir::Files | QDir::Hidden + | QDir::NoSymLinks); + foreach(const QString file, fileList) { + if (CL_NS(index)::IndexReader::isLuceneFile(file)) { + if (!dir.remove(file)) + _CLTHROWA(CL_ERR_IO, "Couldn't delete file "); + } + } + + // clear probably existing file locks + QFileInfo dirInfo(lockDir); + if (dirInfo.exists() && dirInfo.isReadable() && dirInfo.isWritable() + && !dirInfo.isFile() && !dirInfo.isSymLink()) { + QDir lockDirectory(lockDir); + fileList = dir.entryList(QStringList() << getLockPrefix() + + QLatin1Char('*'), QDir::Files | QDir::Hidden | QDir::NoSymLinks); + + foreach(const QString file, fileList) { + if (!lockDirectory.remove(file)) + _CLTHROWA(CL_ERR_IO, "Couldn't delete file "); + } + } + else { + //todo: richer error: + lockDir.getAbsolutePath()); + _CLTHROWA(CL_ERR_IO, "Cannot read lock directory"); + } + } +} + +void FSDirectory::priv_getFN(QString& buffer, const QString& name) const +{ + buffer.clear(); + buffer.append(directory); + buffer.append(QDir::separator()); + buffer.append(name); +} + +FSDirectory::~FSDirectory() +{ +} + +QStringList FSDirectory::list() const +{ + CND_PRECONDITION(!directory.isEmpty(), "directory is not open"); + + QDir dir(directory); + return dir.entryList(QDir::Files | QDir::Hidden); +} + +bool FSDirectory::fileExists(const QString& name) const +{ + CND_PRECONDITION(!directory.isEmpty(), "directory is not open"); + + QDir dir(directory); + return dir.entryList().contains(name); +} + +QString FSDirectory::getDirName() const +{ + return directory; +} + +//static +FSDirectory* FSDirectory::getDirectory(const QString& file, const bool _create) +{ + FSDirectory* dir = NULL; + { + if (file.isEmpty()) + _CLTHROWA(CL_ERR_IO, "Invalid directory"); + + SCOPED_LOCK_MUTEX(DIRECTORIES.THIS_LOCK) + dir = DIRECTORIES.get(file); + if ( dir == NULL ){ + dir = _CLNEW FSDirectory(file, _create); + DIRECTORIES.put(dir->directory, dir); + } else if (_create) { + dir->create(); + } + + { + SCOPED_LOCK_MUTEX(dir->THIS_LOCK) + dir->refCount++; + } + } + + return _CL_POINTER(dir); +} + +int64_t FSDirectory::fileModified(const QString& name) const +{ + CND_PRECONDITION(!directory.isEmpty(), "directory is not open"); + + QFileInfo fInfo(directory + QDir::separator() + name); + return fInfo.lastModified().toTime_t(); +} + +//static +int64_t FSDirectory::fileModified(const QString& dir, const QString& name) +{ + QFileInfo fInfo(dir + QDir::separator() + name); + return fInfo.lastModified().toTime_t(); +} + +void FSDirectory::touchFile(const QString& name) +{ + CND_PRECONDITION(!directory.isEmpty(), "directory is not open"); + + QFile file(directory + QDir::separator() + name); + if (!file.open(QIODevice::ReadWrite)) + _CLTHROWA(CL_ERR_IO, "IO Error while touching file"); +} + +int64_t FSDirectory::fileLength(const QString& name) const +{ + CND_PRECONDITION(!directory.isEmpty(), "directory is not open"); + + QFileInfo fInfo(directory + QDir::separator() + name); + return fInfo.size(); +} + +IndexInput* FSDirectory::openInput(const QString& name) +{ + return openInput(name, CL_NS(store)::BufferedIndexOutput::BUFFER_SIZE); +} + +IndexInput* FSDirectory::openInput(const QString& name, int32_t bufferSize ) +{ + CND_PRECONDITION(directory[0]!=0,"directory is not open") + + return _CLNEW FSIndexInput(directory + QDir::separator() + name, bufferSize); +} + +void FSDirectory::close() +{ + SCOPED_LOCK_MUTEX(DIRECTORIES.THIS_LOCK) + { + SCOPED_LOCK_MUTEX(THIS_LOCK) + + CND_PRECONDITION(!directory.isEmpty(), "directory is not open"); + + //refcount starts at 1 + if (--refCount <= 0) { + Directory* dir = DIRECTORIES.get(getDirName()); + if (dir) { + //this will be removed in ~FSDirectory + DIRECTORIES.remove(getDirName()); + _CLDECDELETE(dir); + } + } + } +} + +QString FSDirectory::getLockPrefix() const +{ + CND_PRECONDITION(!directory.isEmpty(), "directory is not open"); + + QString dirName(QFileInfo(directory).absoluteFilePath()); + if (dirName.isEmpty()) + _CLTHROWA(CL_ERR_Runtime, "Invalid directory path"); + + // to be compatible with jlucene, + // we need to make some changes ... + if (dirName.at(1) == QLatin1Char(':')) + dirName[0] = dirName.at(0).toUpper(); + + TCHAR tBuffer[2048] = { 0 }; + dirName.toWCharArray(tBuffer); + + char aBuffer[4096] = { 0 }; + STRCPY_TtoA(aBuffer, tBuffer, 4096); + + QString string(QLatin1String("lucene-")); + QByteArray hash(QCryptographicHash::hash(aBuffer, QCryptographicHash::Md5)); + + // TODO: verify this !!! + return string.append(QLatin1String(hash.toHex().constData())); +} + +bool FSDirectory::doDeleteFile(const QString& name) +{ + CND_PRECONDITION(!directory.isEmpty(), "directory is not open"); + + QDir dir(directory); + return dir.remove(name); +} + +void FSDirectory::renameFile(const QString& from, const QString& to) +{ + CND_PRECONDITION(!directory.isEmpty(), "directory is not open"); + SCOPED_LOCK_MUTEX(THIS_LOCK) + + if (fileExists(to)) + deleteFile(to, false); + + QFile file(directory + QDir::separator() + from); + QString newFile(directory + QDir::separator() + to); + if (!file.rename(newFile)) { + // try a second time if we fail + if (fileExists(to)) + deleteFile(to, false); + + if (!file.rename(newFile)) { + QString error(QLatin1String("Could not rename: %1 to %2!!!!")); + error.arg(from).arg(newFile); + QByteArray bArray(error.toLocal8Bit()); + _CLTHROWA(CL_ERR_IO, bArray.constData()); + } + } +} + +IndexOutput* FSDirectory::createOutput(const QString& name) +{ + CND_PRECONDITION(!directory.isEmpty(), "directory is not open"); + + QString file = directory + QDir::separator() + name; + if (QFileInfo(file).exists()) { + if (!QFile::remove(file)) { + QByteArray bArray("Cannot overwrite: "); + bArray.append(name.toLocal8Bit()); + _CLTHROWA(CL_ERR_IO, bArray.constData()); + } + } + return _CLNEW FSIndexOutput(file); +} + +LuceneLock* FSDirectory::makeLock(const QString& name) +{ + CND_PRECONDITION(!directory.isEmpty(), "directory is not open"); + + + QString lockFile(getLockPrefix()); + lockFile.append(QLatin1Char('-')).append(name); + + return _CLNEW FSLock(lockDir, lockFile); +} + +QString FSDirectory::toString() const +{ + return QString::fromLatin1("FSDirectory@").append(directory); +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/store/FSDirectory.h b/3rdparty/clucene/src/CLucene/store/FSDirectory.h new file mode 100644 index 000000000..e967380e0 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/store/FSDirectory.h @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +*/ +#ifndef _lucene_store_FSDirectory_ +#define _lucene_store_FSDirectory_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +#include "Directory.h" +#include "Lock.h" +#include "CLucene/util/VoidMap.h" +#include "CLucene/util/StringBuffer.h" + +CL_NS_DEF(store) + +/** +* Straightforward implementation of {@link Directory} as a directory of files. +*

If the system property 'disableLuceneLocks' has the String value of +* "true", lock creation will be disabled. +* +* @see Directory +*/ +class FSDirectory : public Directory +{ +public: + // Destructor - only call this if you are sure the directory + // is not being used anymore. Otherwise use the ref-counting + // facilities of _CLDECDELETE + ~FSDirectory(); + + // Get a list of strings, one for each file in the directory. + QStringList list() const; + + // Returns true iff a file with the given name exists. + bool fileExists(const QString& name) const; + + // Returns the text name of the directory + QString getDirName() const; ///Directories are cached, so that, for a given canonical path, the same + FSDirectory instance will always be returned. This permits + synchronization on directories. + + @param file the path to the directory. + @param create if true, create, or erase any existing contents. + @return the FSDirectory for the named file. + */ + static FSDirectory* getDirectory(const QString& file, const bool create); + + // Returns the time the named file was last modified. + int64_t fileModified(const QString& name) const; + + //static + // Returns the time the named file was last modified. + static int64_t fileModified(const QString& dir, const QString& name); + + // static + // Returns the length in bytes of a file in the directory. + int64_t fileLength(const QString& name) const; + + // Returns a stream reading an existing file. + IndexInput* openInput(const QString& name); + IndexInput* openInput(const QString& name, int32_t bufferSize); + + // Renames an existing file in the directory. + void renameFile(const QString& from, const QString& to); + + // Set the modified time of an existing file to now. + void touchFile(const QString& name); + + // Creates a new, empty file in the directory with the given name. + // Returns a stream writing this file. + IndexOutput* createOutput(const QString& name); + + // Construct a {@link Lock}. + // @param name the name of the lock file + LuceneLock* makeLock(const QString& name); + + // Decrease the ref-count to the directory by one. If the object is no + // longer needed, then the object is removed from the directory pool. + void close(); + + // If MMap is available, this can disable use of mmap reading. + void setUseMMap(bool value) { useMMap = value; } + + // Gets whether the directory is using MMap for inputstreams. + bool getUseMMap() const { return useMMap; } + + QString toString() const; + + static QString DirectoryType() { return QLatin1String("FS"); } + QString getDirectoryType() const { return QLatin1String("FS"); } + + // Set whether Lucene's use of lock files is disabled. By default, + // lock files are enabled. They should only be disabled if the index + // is on a read-only medium like a CD-ROM. + static void setDisableLocks(bool doDisableLocks) + { disableLocks = doDisableLocks; } + + // Returns whether Lucene's use of lock files is disabled. + // @return true if locks are disabled, false if locks are enabled. + static bool getDisableLocks() { return disableLocks; } + +protected: + FSDirectory(const QString& path, const bool createDir); + // Removes an existing file in the directory. + bool doDeleteFile(const QString& name); + +private: + class FSLock : public LuceneLock { + public: + FSLock (const QString& lockDir, const QString& name); + ~FSLock(); + + bool obtain(); + void release(); + bool isLocked(); + QString toString() const; + + QString lockDir; + QString lockFile; + }; + friend class FSDirectory::FSLock; + + class FSIndexInput : public BufferedIndexInput { + public: + FSIndexInput(const QString& path, int32_t bufferSize = + CL_NS(store)::BufferedIndexOutput::BUFFER_SIZE); + ~FSIndexInput(); + + void close(); + IndexInput* clone() const; + + int64_t length() + { return handle->_length; } + + QString getDirectoryType() const + { return FSDirectory::DirectoryType(); } + + protected: + FSIndexInput(const FSIndexInput& clone); + // Random-access methods + void seekInternal(const int64_t position); + // IndexInput methods + void readInternal(uint8_t* b, const int32_t len); + + private: + // We used a shared handle between all the fsindexinput clones. + // This reduces number of file handles we need, and it means + // we dont have to use file tell (which is slow) before doing a read. + class SharedHandle : LUCENE_REFBASE { + public: + SharedHandle(); + ~SharedHandle(); + + int64_t _fpos; + int64_t _length; + + QFile fhandle; + DEFINE_MUTEX(*THIS_LOCK) + }; + SharedHandle* handle; + int64_t _pos; + }; + friend class FSDirectory::FSIndexInput; + + class FSIndexOutput : public BufferedIndexOutput { + public: + FSIndexOutput(const QString& path); + ~FSIndexOutput(); + + void close(); + int64_t length(); + void seek(const int64_t pos); + + protected: + void flushBuffer(const uint8_t* b, const int32_t size); + + private: + QFile fhandle; + }; + friend class FSDirectory::FSIndexOutput; + +private: + QString directory; + int refCount; + void create(); + + QString lockDir; + QString getLockPrefix() const; + static bool disableLocks; + + void priv_getFN(QString& buffer, const QString& name) const; + bool useMMap; +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/store/IndexInput.cpp b/3rdparty/clucene/src/CLucene/store/IndexInput.cpp new file mode 100644 index 000000000..cf7bd16b7 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/store/IndexInput.cpp @@ -0,0 +1,233 @@ + /*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "IndexInput.h" + +CL_NS_USE(util) +CL_NS_DEF(store) + + IndexInput::IndexInput() + { + } + IndexInput::IndexInput(const IndexInput& other) + { + } + + int32_t IndexInput::readInt() { + int32_t b = (readByte() << 24); + b |= (readByte() << 16); + b |= (readByte() << 8); + return (b | readByte()); + } + + int32_t IndexInput::readVInt() { + uint8_t b = readByte(); + int32_t i = b & 0x7F; + for (int32_t shift = 7; (b & 0x80) != 0; shift += 7) { + b = readByte(); + i |= (b & 0x7F) << shift; + } + return i; + } + + int64_t IndexInput::readLong() { + int64_t i = ((int64_t)readInt() << 32); + return (i | ((int64_t)readInt() & 0xFFFFFFFFL)); + } + + int64_t IndexInput::readVLong() { + uint8_t b = readByte(); + int64_t i = b & 0x7F; + for (int32_t shift = 7; (b & 0x80) != 0; shift += 7) { + b = readByte(); + i |= (((int64_t)b) & 0x7FL) << shift; + } + return i; + } + + void IndexInput::skipChars( const int32_t count) { + for (int32_t i = 0; i < count; i++) { + TCHAR b = readByte(); + if ((b & 0x80) == 0) { + // Do Nothing. + } else if ((b & 0xE0) != 0xE0) { + readByte(); + } else { + readByte(); + readByte(); + } + } + } + + int32_t IndexInput::readString(TCHAR* buffer, const int32_t maxLength){ + int32_t len = readVInt(); + int32_t ml=maxLength-1; + if ( len >= ml ){ + readChars(buffer, 0, ml); + buffer[ml] = 0; + //we have to finish reading all the data for this string! + if ( len-ml > 0 ){ + //seek(getFilePointer()+(len-ml)); <- that was the wrong way to "finish reading" + skipChars(len-ml); + } + return ml; + }else{ + readChars(buffer, 0, len); + buffer[len] = 0; + return len; + } + } + + TCHAR* IndexInput::readString(const bool _unique){ + int32_t len = readVInt(); + + if ( len == 0){ + if ( _unique ) //todo: does non unique ever occur? + return stringDuplicate(LUCENE_BLANK_STRING); + else + return LUCENE_BLANK_STRING; + } + + TCHAR* ret = _CL_NEWARRAY(TCHAR,len+1); + readChars(ret, 0, len); + ret[len] = 0; + + return ret; + } + + void IndexInput::readChars( TCHAR* buffer, const int32_t start, const int32_t len) { + const int32_t end = start + len; + TCHAR b; + for (int32_t i = start; i < end; ++i) { + b = readByte(); + if ((b & 0x80) == 0) { + b = (b & 0x7F); + } else if ((b & 0xE0) != 0xE0) { + b = (((b & 0x1F) << 6) + | (readByte() & 0x3F)); + } else { + b = ((b & 0x0F) << 12) | ((readByte() & 0x3F) << 6); + b |= (readByte() & 0x3F); + } + buffer[i] = b; + } + } + + + + + + +BufferedIndexInput::BufferedIndexInput(int32_t _bufferSize): + buffer(NULL), + bufferSize(_bufferSize), + bufferStart(0), + bufferLength(0), + bufferPosition(0) + { + } + + BufferedIndexInput::BufferedIndexInput(const BufferedIndexInput& other): + IndexInput(other), + buffer(NULL), + bufferSize(other.bufferSize), + bufferStart(other.bufferStart), + bufferLength(other.bufferLength), + bufferPosition(other.bufferPosition) + { + /* DSR: Does the fact that sometime clone.buffer is not NULL even when + ** clone.bufferLength is zero indicate memory corruption/leakage? + ** if ( clone.buffer != NULL) { */ + if (other.bufferLength != 0 && other.buffer != NULL) { + buffer = _CL_NEWARRAY(uint8_t,bufferLength); + memcpy(buffer,other.buffer,bufferLength * sizeof(uint8_t)); + } + } + + void BufferedIndexInput::readBytes(uint8_t* b, const int32_t len){ + if (len < bufferSize) { + for (int32_t i = 0; i < len; ++i) // read byte-by-byte + b[i] = readByte(); + } else { // read all-at-once + int64_t start = getFilePointer(); + seekInternal(start); + readInternal(b, len); + + bufferStart = start + len; // adjust stream variables + bufferPosition = 0; + bufferLength = 0; // trigger refill() on read + } + } + + int64_t BufferedIndexInput::getFilePointer() const{ + return bufferStart + bufferPosition; + } + + void BufferedIndexInput::seek(const int64_t pos) { + if ( pos < 0 ) + _CLTHROWA(CL_ERR_IO, "IO Argument Error. Value must be a positive value."); + if (pos >= bufferStart && pos < (bufferStart + bufferLength)) + bufferPosition = (int32_t)(pos - bufferStart); // seek within buffer + else { + bufferStart = pos; + bufferPosition = 0; + bufferLength = 0; // trigger refill() on read() + seekInternal(pos); + } + } + void BufferedIndexInput::close(){ + _CLDELETE_ARRAY(buffer); + bufferLength = 0; + bufferPosition = 0; + bufferStart = 0; + } + + + BufferedIndexInput::~BufferedIndexInput(){ + BufferedIndexInput::close(); + } + + void BufferedIndexInput::refill() { + int64_t start = bufferStart + bufferPosition; + int64_t end = start + bufferSize; + if (end > length()) // don't read past EOF + end = length(); + bufferLength = (int32_t)(end - start); + if (bufferLength == 0) + _CLTHROWA(CL_ERR_IO, "IndexInput read past EOF"); + + if (buffer == NULL){ + buffer = _CL_NEWARRAY(uint8_t,bufferSize); // allocate buffer lazily + } + readInternal(buffer, bufferLength); + + + bufferStart = start; + bufferPosition = 0; + } + + +IndexInputStream::IndexInputStream(IndexInput* input){ + this->input = input; + this->size = input->length(); + this->position = input->getFilePointer(); +} +IndexInputStream::~IndexInputStream(){ +} +int32_t IndexInputStream::fillBuffer(char* start, int32_t space){ + int64_t avail = input->length()-input->getFilePointer(); + if ( avail == 0 ) + return -1; + else if ( availreadBytes((uint8_t*)start,space); + return space; +} + +CL_NS_END + diff --git a/3rdparty/clucene/src/CLucene/store/IndexInput.h b/3rdparty/clucene/src/CLucene/store/IndexInput.h new file mode 100644 index 000000000..9453b5cf1 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/store/IndexInput.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#ifndef _lucene_store_IndexInput_ +#define _lucene_store_IndexInput_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include + +#include "CLucene/util/bufferedstream.h" +#include "IndexOutput.h" + +CL_NS_DEF(store) + + /** Abstract base class for input from a file in a {@link Directory}. A + * random-access input stream. Used for all Lucene index input operations. + * @see Directory + * @see IndexOutput + */ + class IndexInput: LUCENE_BASE { + private: + void skipChars( const int32_t count); + protected: + IndexInput(); + IndexInput(const IndexInput& clone); + public: + virtual ~IndexInput(){} + virtual IndexInput* clone() const =0; + + DEFINE_MUTEX(THIS_LOCK) + + /** Reads and returns a single byte. + * @see IndexOutput#writeByte(byte) + */ + virtual uint8_t readByte() =0; + + /** Reads a specified number of bytes into an array at the specified offset. + * @param b the array to read bytes into + * @param offset the offset in the array to start storing bytes + * @param len the number of bytes to read + * @see IndexOutput#writeBytes(byte[],int32_t) + */ + virtual void readBytes(uint8_t* b, const int32_t len) =0; + + /** Reads four bytes and returns an int. + * @see IndexOutput#writeInt(int32_t) + */ + int32_t readInt(); + + /** Reads an int stored in variable-length format. Reads between one and + * five bytes. Smaller values take fewer bytes. Negative numbers are not + * supported. + * @see IndexOutput#writeVInt(int32_t) + */ + virtual int32_t readVInt(); + + /** Reads eight bytes and returns a long. + * @see IndexOutput#writeLong(long) + */ + int64_t readLong(); + + /** Reads a long stored in variable-length format. Reads between one and + * nine bytes. Smaller values take fewer bytes. Negative numbers are not + * supported. */ + int64_t readVLong(); + + /** Reads a string. + * @see IndexOutput#writeString(String) + * maxLength is the amount read into the buffer, the whole string is still read from the stream + * returns the amount read + */ + int32_t readString(TCHAR* buffer, const int32_t maxlength); + + /** Reads a string. + * @see IndexOutput#writeString(String) + * If unique is true (default) the string will be duplicated. + * If false and the length is zero, LUCENE_BLANK_STRING is returned + */ + TCHAR* readString(const bool unique=true); + + + /** Reads UTF-8 encoded characters into an array. + * @param buffer the array to read characters into + * @param start the offset in the array to start storing characters + * @param length the number of characters to read + * @see IndexOutput#writeChars(String,int32_t,int32_t) + */ + void readChars( TCHAR* buffer, const int32_t start, const int32_t len); + + /** Closes the stream to futher operations. */ + virtual void close() =0; + + /** Returns the current position in this file, where the next read will + * occur. + * @see #seek(long) + */ + virtual int64_t getFilePointer() const =0; + + /** Sets current position in this file, where the next read will occur. + * @see #getFilePointer() + */ + virtual void seek(const int64_t pos) =0; + + /** The number of bytes in the file. */ + virtual int64_t length() = 0; + + virtual QString getDirectoryType() const = 0; + }; + + /** Abstract base class for input from a file in a {@link Directory}. A + * random-access input stream. Used for all Lucene index input operations. + * @see Directory + * @see IndexOutput + */ + class BufferedIndexInput: public IndexInput{ + private: + uint8_t* buffer; //array of bytes + void refill(); + protected: + int32_t bufferSize; //size of the buffer + int64_t bufferStart; // position in file of buffer + int32_t bufferLength; // end of valid l_byte_ts + int32_t bufferPosition; // next uint8_t to read + + /** Returns a clone of this stream. + * + *

Clones of a stream access the same data, and are positioned at the same + * point as the stream they were cloned from. + * + *

Expert: Subclasses must ensure that clones may be positioned at + * different points in the input from each other and from the stream they + * were cloned from. + */ + BufferedIndexInput(const BufferedIndexInput& clone); + BufferedIndexInput(int32_t bufferSize = CL_NS(store)::BufferedIndexOutput::BUFFER_SIZE); + public: + + virtual ~BufferedIndexInput(); + virtual IndexInput* clone() const = 0; + void close(); + inline uint8_t readByte(){ + if (bufferPosition >= bufferLength) + refill(); + + return buffer[bufferPosition++]; + } + void readBytes(uint8_t* b, const int32_t len); + int64_t getFilePointer() const; + void seek(const int64_t pos); + + protected: + /** Expert: implements buffer refill. Reads bytes from the current position + * in the input. + * @param b the array to read bytes into + * @param offset the offset in the array to start storing bytes + * @param length the number of bytes to read + */ + virtual void readInternal(uint8_t* b, const int32_t len) = 0; + + /** Expert: implements seek. Sets current position in this file, where the + * next {@link #readInternal(byte[],int32_t,int32_t)} will occur. + * @see #readInternal(byte[],int32_t,int32_t) + */ + virtual void seekInternal(const int64_t pos) = 0; + }; + + /** + * JStream InputStream which reads from an IndexInput. This class is + * used by the FieldReader to create binary fields. You can then use + * a GZipInputStream to read compressed data or any of the other + * JStream stream types. + * + */ + class IndexInputStream: public jstreams::BufferedInputStream{ + IndexInput* input; + public: + IndexInputStream(IndexInput* input); + ~IndexInputStream(); + int32_t fillBuffer(char* start, int32_t space); + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/store/IndexOutput.cpp b/3rdparty/clucene/src/CLucene/store/IndexOutput.cpp new file mode 100644 index 000000000..04f78c348 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/store/IndexOutput.cpp @@ -0,0 +1,163 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "IndexOutput.h" + +CL_NS_USE(util) +CL_NS_DEF(store) + + + IndexOutput::IndexOutput() + { + } + + IndexOutput::~IndexOutput(){ + } + + BufferedIndexOutput::BufferedIndexOutput() + { + buffer = _CL_NEWARRAY(uint8_t, BUFFER_SIZE ); + bufferStart = 0; + bufferPosition = 0; + } + + BufferedIndexOutput::~BufferedIndexOutput(){ + if ( buffer != NULL ) + close(); + } + + void BufferedIndexOutput::close(){ + flush(); + _CLDELETE_ARRAY( buffer ); + + bufferStart = 0; + bufferPosition = 0; + } + + void BufferedIndexOutput::writeByte(const uint8_t b) { + CND_PRECONDITION(buffer!=NULL,"IndexOutput is closed") + if (bufferPosition >= BUFFER_SIZE) + flush(); + buffer[bufferPosition++] = b; + } + + void BufferedIndexOutput::writeBytes(const uint8_t* b, const int32_t length) { + if ( length < 0 ) + _CLTHROWA(CL_ERR_IllegalArgument, "IO Argument Error. Value must be a positive value."); + int32_t bytesLeft = BUFFER_SIZE - bufferPosition; + // is there enough space in the buffer? + if (bytesLeft >= length) { + // we add the data to the end of the buffer + memcpy(buffer + bufferPosition, b, length); + bufferPosition += length; + // if the buffer is full, flush it + if (BUFFER_SIZE - bufferPosition == 0) + flush(); + } else { + // is data larger then buffer? + if (length > BUFFER_SIZE) { + // we flush the buffer + if (bufferPosition > 0) + flush(); + // and write data at once + flushBuffer(b, length); + bufferStart += length; + } else { + // we fill/flush the buffer (until the input is written) + int64_t pos = 0; // position in the input data + int32_t pieceLength; + while (pos < length) { + if ( length - pos < bytesLeft ) + pieceLength = length - pos; + else + pieceLength = bytesLeft; + memcpy(buffer + bufferPosition, b + pos, pieceLength); + pos += pieceLength; + bufferPosition += pieceLength; + // if the buffer is full, flush it + bytesLeft = BUFFER_SIZE - bufferPosition; + if (bytesLeft == 0) { + flush(); + bytesLeft = BUFFER_SIZE; + } + } + } + } + } + + void IndexOutput::writeInt(const int32_t i) { + writeByte((uint8_t)(i >> 24)); + writeByte((uint8_t)(i >> 16)); + writeByte((uint8_t)(i >> 8)); + writeByte((uint8_t) i); + } + + void IndexOutput::writeVInt(const int32_t vi) { + uint32_t i = vi; + while ((i & ~0x7F) != 0) { + writeByte((uint8_t)((i & 0x7f) | 0x80)); + i >>= 7; //doing unsigned shift + } + writeByte( (uint8_t)i ); + } + + void IndexOutput::writeLong(const int64_t i) { + writeInt((int32_t) (i >> 32)); + writeInt((int32_t) i); + } + + void IndexOutput::writeVLong(const int64_t vi) { + uint64_t i = vi; + while ((i & ~0x7F) != 0) { + writeByte((uint8_t)((i & 0x7f) | 0x80)); + i >>= 7; //doing unsigned shift + } + writeByte((uint8_t)i); + } + + void IndexOutput::writeString(const TCHAR* s, const int32_t length ) { + writeVInt(length); + writeChars(s, 0, length); + } + + void IndexOutput::writeChars(const TCHAR* s, const int32_t start, const int32_t length){ + if ( length < 0 || start < 0 ) + _CLTHROWA(CL_ERR_IllegalArgument, "IO Argument Error. Value must be a positive value."); + + const int32_t end = start + length; + for (int32_t i = start; i < end; ++i) { + const int32_t code = (int32_t)s[i]; + if (code >= 0x01 && code <= 0x7F) + writeByte((uint8_t)code); + else if (((code >= 0x80) && (code <= 0x7FF)) || code == 0) { + writeByte((uint8_t)(0xC0 | (code >> 6))); + writeByte((uint8_t)(0x80 | (code & 0x3F))); + } else { + writeByte((uint8_t)(0xE0 | (((uint32_t)code) >> 12))); //unsigned shift + writeByte((uint8_t)(0x80 | ((code >> 6) & 0x3F))); + writeByte((uint8_t)(0x80 | (code & 0x3F))); + } + } + } + + + int64_t BufferedIndexOutput::getFilePointer() const{ + return bufferStart + bufferPosition; + } + + void BufferedIndexOutput::seek(const int64_t pos) { + flush(); + bufferStart = pos; + } + + void BufferedIndexOutput::flush() { + flushBuffer(buffer, bufferPosition); + bufferStart += bufferPosition; + bufferPosition = 0; + } + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/store/IndexOutput.h b/3rdparty/clucene/src/CLucene/store/IndexOutput.h new file mode 100644 index 000000000..c47ee73a7 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/store/IndexOutput.h @@ -0,0 +1,152 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_store_IndexOutput_ +#define _lucene_store_IndexOutput_ +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +CL_NS_DEF(store) + + +/** Abstract class for output to a file in a Directory. A random-access output +* stream. Used for all Lucene index output operations. +* @see Directory +* @see IndexInput +*/ +class IndexOutput:LUCENE_BASE{ + bool isclosed; +public: + IndexOutput(); + virtual ~IndexOutput(); + + /** Writes a single byte. + * @see IndexInput#readByte() + */ + virtual void writeByte(const uint8_t b) = 0; + + /** Writes an array of bytes. + * @param b the bytes to write + * @param length the number of bytes to write + * @see IndexInput#readBytes(byte[],int32_t,int32_t) + */ + virtual void writeBytes(const uint8_t* b, const int32_t length) = 0; + + /** Writes an int as four bytes. + * @see IndexInput#readInt() + */ + void writeInt(const int32_t i); + + /** Writes an int in a variable-length format. Writes between one and + * five bytes. Smaller values take fewer bytes. Negative numbers are not + * supported. + * @see IndexInput#readVInt() + */ + void writeVInt(const int32_t vi); + + /** Writes a long as eight bytes. + * @see IndexInput#readLong() + */ + void writeLong(const int64_t i); + + /** Writes an long in a variable-length format. Writes between one and five + * bytes. Smaller values take fewer bytes. Negative numbers are not + * supported. + * @see IndexInput#readVLong() + */ + void writeVLong(const int64_t vi); + + /** Writes a string. + * @see IndexInput#readString() + */ + void writeString(const TCHAR* s, const int32_t length); + + /** Writes a sequence of UTF-8 encoded characters from a string. + * @param s the source of the characters + * @param start the first character in the sequence + * @param length the number of characters in the sequence + * @see IndexInput#readChars(char[],int32_t,int32_t) + */ + void writeChars(const TCHAR* s, const int32_t start, const int32_t length); + + /** Closes this stream to further operations. */ + virtual void close() = 0; + + /** Returns the current position in this file, where the next write will + * occur. + * @see #seek(long) + */ + virtual int64_t getFilePointer() const = 0; + + /** Sets current position in this file, where the next write will occur. + * @see #getFilePointer() + */ + virtual void seek(const int64_t pos) = 0; + + /** The number of bytes in the file. */ + virtual int64_t length() = 0; + + /** Forces any buffered output to be written. */ + virtual void flush() = 0; +}; + +/** Base implementation class for buffered {@link IndexOutput}. */ +class BufferedIndexOutput : public IndexOutput{ +public: + LUCENE_STATIC_CONSTANT(int32_t, BUFFER_SIZE=LUCENE_STREAM_BUFFER_SIZE); +private: + uint8_t* buffer; + int64_t bufferStart; // position in file of buffer + int32_t bufferPosition; // position in buffer + +public: + BufferedIndexOutput(); + virtual ~BufferedIndexOutput(); + + /** Writes a single byte. + * @see IndexInput#readByte() + */ + virtual void writeByte(const uint8_t b); + + /** Writes an array of bytes. + * @param b the bytes to write + * @param length the number of bytes to write + * @see IndexInput#readBytes(byte[],int32_t,int32_t) + */ + virtual void writeBytes(const uint8_t* b, const int32_t length); + + /** Closes this stream to further operations. */ + virtual void close(); + + /** Returns the current position in this file, where the next write will + * occur. + * @see #seek(long) + */ + int64_t getFilePointer() const; + + /** Sets current position in this file, where the next write will occur. + * @see #getFilePointer() + */ + virtual void seek(const int64_t pos); + + /** The number of bytes in the file. */ + virtual int64_t length() = 0; + + /** Forces any buffered output to be written. */ + void flush(); + +protected: + /** Expert: implements buffer write. Writes bytes at the current position in + * the output. + * @param b the bytes to write + * @param len the number of bytes to write + */ + virtual void flushBuffer(const uint8_t* b, const int32_t len) = 0; +}; + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/store/InputStream.h b/3rdparty/clucene/src/CLucene/store/InputStream.h new file mode 100644 index 000000000..f56819eeb --- /dev/null +++ b/3rdparty/clucene/src/CLucene/store/InputStream.h @@ -0,0 +1,21 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_store_InputStream_ +#define _lucene_store_InputStream_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +CL_NS_DEF(store) + +deprecated... please use IndexInput.h header +and change InputStream to IndexInput + + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/store/Lock.cpp b/3rdparty/clucene/src/CLucene/store/Lock.cpp new file mode 100644 index 000000000..a66e784b0 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/store/Lock.cpp @@ -0,0 +1,27 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "Lock.h" + +CL_NS_DEF(store) + + bool LuceneLock::obtain(int64_t lockWaitTimeout) { + bool locked = obtain(); + int maxSleepCount = (int)(lockWaitTimeout / LOCK_POLL_INTERVAL); + int sleepCount = 0; + while (!locked) { + if (sleepCount++ == maxSleepCount) { + _CLTHROWA(CL_ERR_IO,"Lock obtain timed out"); + } + _LUCENE_SLEEP(LOCK_POLL_INTERVAL); + locked = obtain(); + } + return locked; + } + + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/store/Lock.h b/3rdparty/clucene/src/CLucene/store/Lock.h new file mode 100644 index 000000000..b5dda3b06 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/store/Lock.h @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#ifndef _lucene_store_Lock_ +#define _lucene_store_Lock_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +CL_NS_DEF(store) + +class LuceneLock : LUCENE_BASE +{ +public: + LUCENE_STATIC_CONSTANT(int64_t, LOCK_POLL_INTERVAL = 1000); + + virtual ~LuceneLock() {} + + // Attempts to obtain exclusive access and immediately return upon success + // or failure. Return true if exclusive access is obtained. + virtual bool obtain() = 0; + + // Attempts to obtain an exclusive lock within amount of time given. + // Currently polls once per second until lockWaitTimeout is passed. + // @param lockWaitTimeout length of time to wait in ms + // @return true if lock was obtained + // @throws IOException if lock wait times out or obtain() throws an IOException + bool obtain(int64_t lockWaitTimeout); + + // Release exclusive access. + virtual void release() = 0; + + // Returns true if the resource is currently locked. Note that one must + // still call {@link #obtain()} before using the resource. + virtual bool isLocked() = 0; + + virtual QString toString() const = 0; +}; + + +// Utility class for executing code with exclusive access. +template +class LuceneLockWith +{ +public: + // Constructs an executor that will grab the named lock. Defaults + // lockWaitTimeout to LUCENE_COMMIT_LOCK_TIMEOUT. + // @deprecated Kept only to avoid breaking existing code. + LuceneLockWith(LuceneLock* lock, int64_t lockWaitTimeout) + { + this->lock = lock; + this->lockWaitTimeout = lockWaitTimeout; + } + + virtual ~LuceneLockWith() {} + + // Calls {@link #doBody} while lock is obtained. Blocks if lock + // cannot be obtained immediately. Retries to obtain lock once per second + // until it is obtained, or until it has tried ten times. Lock is released + // when {@link #doBody} exits. + T runAndReturn() + { + bool locked = false; + T ret = NULL; + try { + locked = lock->obtain(lockWaitTimeout); + ret = doBody(); + } _CLFINALLY ( + if (locked) + lock->release(); + ); + return ret; + } + + // @see runAndReturn + // Same as runAndReturn, except doesn't return any value. The only + // difference is that no void values are used + void run() + { + bool locked = false; + try { + locked = lock->obtain(lockWaitTimeout); + doBody(); + } _CLFINALLY ( + if (locked) + lock->release(); + ); + } + +protected: + virtual T doBody() = 0; + +private: + LuceneLock* lock; + int64_t lockWaitTimeout; +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/store/MMapInput.cpp b/3rdparty/clucene/src/CLucene/store/MMapInput.cpp new file mode 100644 index 000000000..d660032c6 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/store/MMapInput.cpp @@ -0,0 +1,203 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#if defined(LUCENE_FS_MMAP) + +#include "FSDirectory.h" +#include "CLucene/util/Misc.h" +#include "CLucene/debug/condition.h" + +#ifndef _CLCOMPILER_MSVC + #include +#endif + +CL_NS_DEF(store) +CL_NS_USE(util) + + FSDirectory::MMapIndexInput::MMapIndexInput(const char* path): + pos(0), + data(NULL), + _length(0), + isClone(false) + { + //Func - Constructor. + // Opens the file named path + //Pre - path != NULL + //Post - if the file could not be opened an exception is thrown. + + CND_PRECONDITION(path != NULL, "path is NULL"); + +#ifdef _CLCOMPILER_MSVC + mmaphandle = NULL; + fhandle = CreateFileA(path,GENERIC_READ,FILE_SHARE_READ, 0,OPEN_EXISTING,0,0); + + //Check if a valid fhandle was retrieved + if (fhandle < 0){ + DWORD err = GetLastError(); + if ( err == ERROR_FILE_NOT_FOUND ) + _CLTHROWA(CL_ERR_IO, "File does not exist"); + else if ( err == EACCES ) + _CLTHROWA(ERROR_ACCESS_DENIED, "File Access denied"); + else if ( err == ERROR_TOO_MANY_OPEN_FILES ) + _CLTHROWA(CL_ERR_IO, "Too many open files"); + else + _CLTHROWA(CL_ERR_IO, "File IO Error"); + } + + DWORD dummy=0; + _length = GetFileSize(fhandle,&dummy); + + if ( _length > 0 ){ + mmaphandle = CreateFileMappingA(fhandle,NULL,PAGE_READONLY,0,0,NULL); + if ( mmaphandle != NULL ){ + void* address = MapViewOfFile(mmaphandle,FILE_MAP_READ,0,0,0); + if ( address != NULL ){ + data = (uint8_t*)address; + return; //SUCCESS! + } + } + CloseHandle(mmaphandle); + + char* lpMsgBuf=0; + DWORD dw = GetLastError(); + + FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + lpMsgBuf, + 0, NULL ); + + char* errstr = _CL_NEWARRAY(char, strlen(lpMsgBuf)+40); + sprintf(errstr, "MMapIndexInput::MMapIndexInput failed with error %d: %s", dw, lpMsgBuf); + LocalFree(lpMsgBuf); + + _CLTHROWA_DEL(CL_ERR_IO,errstr); + } + +#else //_CLCOMPILER_MSVC + fhandle = ::open (path, O_RDONLY); + if (fhandle < 0){ + _CLTHROWA(CL_ERR_IO,strerror(errno)); + }else{ + // stat it + struct stat sb; + if (::fstat (fhandle, &sb)){ + _CLTHROWA(CL_ERR_IO,strerror(errno)); + }else{ + // get length from stat + _length = sb.st_size; + + // mmap the file + void* address = ::mmap(0, _length, PROT_READ, MAP_SHARED, fhandle, 0); + if (address == MAP_FAILED){ + _CLTHROWA(CL_ERR_IO,strerror(errno)); + }else{ + data = (uint8_t*)address; + } + } + } +#endif + } + + FSDirectory::MMapIndexInput::MMapIndexInput(const MMapIndexInput& clone): IndexInput(clone){ + //Func - Constructor + // Uses clone for its initialization + //Pre - clone is a valide instance of FSIndexInput + //Post - The instance has been created and initialized by clone + +#ifdef _CLCOMPILER_MSVC + mmaphandle = NULL; + fhandle = NULL; +#endif + + data = clone.data; + pos = clone.pos; + + //clone the file length + _length = clone._length; + //Keep in mind that this instance is a clone + isClone = true; + } + + uint8_t FSDirectory::MMapIndexInput::readByte(){ + return *(data+(pos++)); + } + + void FSDirectory::MMapIndexInput::readBytes(uint8_t* b, const int32_t len){ + memcpy(b, data+pos, len); + pos+=len; + } + int32_t FSDirectory::MMapIndexInput::readVInt(){ + uint8_t b = *(data+(pos++)); + int32_t i = b & 0x7F; + for (int shift = 7; (b & 0x80) != 0; shift += 7) { + b = *(data+(pos++)); + i |= (b & 0x7F) << shift; + } + return i; + } + int64_t FSDirectory::MMapIndexInput::getFilePointer() const{ + return pos; + } + void FSDirectory::MMapIndexInput::seek(const int64_t pos){ + this->pos=pos; + } + + FSDirectory::MMapIndexInput::~MMapIndexInput(){ + //Func - Destructor + //Pre - True + //Post - The file for which this instance is responsible has been closed. + // The instance has been destroyed + + close(); + } + + IndexInput* FSDirectory::MMapIndexInput::clone() const + { + return _CLNEW FSDirectory::MMapIndexInput(*this); + } + void FSDirectory::MMapIndexInput::close() { + //IndexInput::close(); + + if ( !isClone ){ +#ifdef _CLCOMPILER_MSVC + if ( data != NULL ){ + if ( ! UnmapViewOfFile(data) ){ + CND_PRECONDITION( false, "UnmapViewOfFile(data) failed"); //todo: change to rich error + } + } + + if ( mmaphandle != NULL ){ + if ( ! CloseHandle(mmaphandle) ){ + CND_PRECONDITION( false, "CloseHandle(mmaphandle) failed"); + } + } + if ( fhandle != NULL ){ + if ( !CloseHandle(fhandle) ){ + CND_PRECONDITION( false, "CloseHandle(fhandle) failed"); + } + } + mmaphandle = NULL; + fhandle = NULL; +#else + if ( data != NULL ) + ::munmap(data, _length); + if ( fhandle > 0 ) + ::close(fhandle); + fhandle = 0; +#endif + } + data = NULL; + pos = 0; + } + + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/store/OutputStream.h b/3rdparty/clucene/src/CLucene/store/OutputStream.h new file mode 100644 index 000000000..a82d6718a --- /dev/null +++ b/3rdparty/clucene/src/CLucene/store/OutputStream.h @@ -0,0 +1,23 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_store_IndexOutput_ +#define _lucene_store_IndexOutput_ +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +CL_NS_DEF(store) + + +deprecated... please use IndexOutput.h header +and change OutputStream to OutdexInput + + + +CL_NS_END + +#endif // _lucene_store_IndexOutput_ diff --git a/3rdparty/clucene/src/CLucene/store/RAMDirectory.cpp b/3rdparty/clucene/src/CLucene/store/RAMDirectory.cpp new file mode 100644 index 000000000..b0a7c4d64 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/store/RAMDirectory.cpp @@ -0,0 +1,446 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +*/ +#include "CLucene/StdHeader.h" +#include "RAMDirectory.h" + +#include "Lock.h" +#include "Directory.h" +#include "FSDirectory.h" +#include "CLucene/index/IndexReader.h" +#include "CLucene/util/VoidMap.h" +#include "CLucene/util/Misc.h" +#include "CLucene/debug/condition.h" + +CL_NS_USE(util) +CL_NS_DEF(store) + +RAMFile::RAMFile() +{ + length = 0; + lastModified = Misc::currentTimeMillis(); +} + +RAMFile::~RAMFile() +{ +} + + +RAMDirectory::RAMLock::RAMLock(const QString& name, RAMDirectory* dir) + : directory(dir) +{ + fname = name; +} + +RAMDirectory::RAMLock::~RAMLock() +{ + directory = NULL; +} + +QString RAMDirectory::RAMLock::toString() const +{ + return QLatin1String("LockFile@RAM"); +} + +bool RAMDirectory::RAMLock::isLocked() +{ + return directory->fileExists(fname); +} + +bool RAMDirectory::RAMLock::obtain() +{ + SCOPED_LOCK_MUTEX(directory->files_mutex); + if (!directory->fileExists(fname)) { + IndexOutput* tmp = directory->createOutput(fname); + tmp->close(); + _CLDELETE(tmp); + + return true; + } + return false; +} + +void RAMDirectory::RAMLock::release() +{ + directory->deleteFile(fname); +} + +RAMIndexOutput::~RAMIndexOutput() +{ + if (deleteFile) + _CLDELETE(file); + file = NULL; +} + +RAMIndexOutput::RAMIndexOutput(RAMFile* f) + : file(f) +{ + pointer = 0; + deleteFile = false; +} + +RAMIndexOutput::RAMIndexOutput() + : file(_CLNEW RAMFile) +{ + pointer = 0; + deleteFile = true; +} + +void RAMIndexOutput::writeTo(IndexOutput* out) +{ + flush(); + int64_t end = file->length; + int64_t pos = 0; + int32_t p = 0; + while (pos < end) { + int32_t length = CL_NS(store)::BufferedIndexOutput::BUFFER_SIZE; + int64_t nextPos = pos + length; + if (nextPos > end) { // at the last buffer + length = (int32_t)(end - pos); + } + out->writeBytes((uint8_t*)file->buffers[p++], length); + pos = nextPos; + } +} + +void RAMIndexOutput::reset() +{ + seek(_ILONGLONG(0)); + file->length = _ILONGLONG(0); +} + +void RAMIndexOutput::flushBuffer(const uint8_t* src, const int32_t len) +{ + uint8_t* b = NULL; + int32_t bufferPos = 0; + while (bufferPos != len) { + uint32_t bufferNumber = pointer/CL_NS(store)::BufferedIndexOutput::BUFFER_SIZE; + int32_t bufferOffset = pointer%CL_NS(store)::BufferedIndexOutput::BUFFER_SIZE; + int32_t bytesInBuffer = CL_NS(store)::BufferedIndexOutput::BUFFER_SIZE - bufferOffset; + int32_t remainInSrcBuffer = len - bufferPos; + int32_t bytesToCopy = bytesInBuffer >= remainInSrcBuffer ? remainInSrcBuffer : bytesInBuffer; + + if (bufferNumber == file->buffers.size()){ + b = _CL_NEWARRAY(uint8_t, CL_NS(store)::BufferedIndexOutput::BUFFER_SIZE); + file->buffers.push_back( b ); + }else{ + b = file->buffers[bufferNumber]; + } + memcpy(b+bufferOffset, src+bufferPos, bytesToCopy * sizeof(uint8_t)); + bufferPos += bytesToCopy; + pointer += bytesToCopy; + } + if (pointer > file->length) + file->length = pointer; + + file->lastModified = Misc::currentTimeMillis(); +} + +void RAMIndexOutput::close() +{ + BufferedIndexOutput::close(); +} + +/** Random-at methods */ +void RAMIndexOutput::seek(const int64_t pos) +{ + BufferedIndexOutput::seek(pos); + pointer = (int32_t)pos; +} + +int64_t RAMIndexOutput::length() +{ + return file->length; +} + + +RAMIndexInput::RAMIndexInput(RAMFile* f) + : file(f) +{ + pointer = 0; + _length = f->length; +} + +RAMIndexInput::RAMIndexInput(const RAMIndexInput& other) + : BufferedIndexInput(other) +{ + file = other.file; + pointer = other.pointer; + _length = other._length; +} + +RAMIndexInput::~RAMIndexInput() +{ + RAMIndexInput::close(); +} + +IndexInput* RAMIndexInput::clone() const +{ + return _CLNEW RAMIndexInput(*this); +} + +int64_t RAMIndexInput::length() +{ + return _length; +} + +QString RAMIndexInput::getDirectoryType() const +{ + return RAMDirectory::DirectoryType(); +} + +void RAMIndexInput::readInternal(uint8_t* dest, const int32_t len) +{ + const int64_t bytesAvailable = file->length - pointer; + int64_t remainder = len <= bytesAvailable ? len : bytesAvailable; + int32_t start = pointer; + int32_t destOffset = 0; + while (remainder != 0) { + int32_t bufferNumber = start / CL_NS(store)::BufferedIndexOutput::BUFFER_SIZE; + int32_t bufferOffset = start % CL_NS(store)::BufferedIndexOutput::BUFFER_SIZE; + int32_t bytesInBuffer = CL_NS(store)::BufferedIndexOutput::BUFFER_SIZE - bufferOffset; + + /* The buffer's entire length (bufferLength) is defined by IndexInput.h + ** as int32_t, so obviously the number of bytes in a given segment of the + ** buffer won't exceed the the capacity of int32_t. Therefore, the + ** int64_t->int32_t cast on the next line is safe. */ + int32_t bytesToCopy = bytesInBuffer >= remainder ? static_cast(remainder) : bytesInBuffer; + uint8_t* b = file->buffers[bufferNumber]; + memcpy(dest + destOffset, b + bufferOffset, bytesToCopy * sizeof(uint8_t)); + + destOffset += bytesToCopy; + start += bytesToCopy; + remainder -= bytesToCopy; + pointer += bytesToCopy; + } +} + +void RAMIndexInput::close() +{ + BufferedIndexInput::close(); +} + +void RAMIndexInput::seekInternal(const int64_t pos) +{ + CND_PRECONDITION(pos >= 0 && pos < this->_length, "Seeking out of range") + pointer = (int32_t)pos; +} + +// #pragma mark -- RAMDirectory + +QStringList RAMDirectory::list() const +{ + SCOPED_LOCK_MUTEX(files_mutex); + + QStringList names; + + FileMap::const_iterator itr; + for (itr = files.begin(); itr != files.end(); ++itr) + names.push_back(itr->first); + + return names; +} + +RAMDirectory::RAMDirectory() + : Directory() + , files(false, true) +{ +} + +RAMDirectory::~RAMDirectory() +{ + //todo: should call close directory? +} + +void RAMDirectory::_copyFromDir(Directory* dir, bool closeDir) +{ + QStringList names = dir->list(); + uint8_t buf[CL_NS(store)::BufferedIndexOutput::BUFFER_SIZE]; + + foreach (const QString& name, names) { + if (!CL_NS(index)::IndexReader::isLuceneFile(name)) + continue; + + // make place on ram disk + IndexOutput* os = createOutput(name); + // read current file + IndexInput* is = dir->openInput(name); + + // and copy to ram disk + //todo: this could be a problem when copying from big indexes... + int64_t readCount = 0; + int64_t len = is->length(); + while (readCount < len) { + int32_t toRead = CL_NS(store)::BufferedIndexOutput::BUFFER_SIZE; + if ((readCount + toRead) > len) + toRead = int32_t(len - readCount); + is->readBytes(buf, toRead); + os->writeBytes(buf, toRead); + readCount += toRead; + } + + // graceful cleanup + is->close(); + _CLDELETE(is); + os->close(); + _CLDELETE(os); + } + if (closeDir) + dir->close(); +} + +RAMDirectory::RAMDirectory(Directory* dir) + : Directory() + , files(false, true) +{ + _copyFromDir(dir, false); +} + +RAMDirectory::RAMDirectory(const QString& dir) + : Directory() + , files(false, true) +{ + Directory* fsdir = FSDirectory::getDirectory(dir, false); + try { + _copyFromDir(fsdir, false); + } _CLFINALLY ( + fsdir->close(); + _CLDECDELETE(fsdir); + ); +} + +bool RAMDirectory::fileExists(const QString& name) const +{ + SCOPED_LOCK_MUTEX(files_mutex); + return files.exists(name); +} + +int64_t RAMDirectory::fileModified(const QString& name) const +{ + SCOPED_LOCK_MUTEX(files_mutex); + const RAMFile* f = files.get(name); + return f->lastModified; +} + +int64_t RAMDirectory::fileLength(const QString& name) const +{ + SCOPED_LOCK_MUTEX(files_mutex); + RAMFile* f = files.get(name); + return f->length; +} + + +IndexInput* RAMDirectory::openInput(const QString& name) +{ + SCOPED_LOCK_MUTEX(files_mutex); + RAMFile* file = files.get(name); + if (file == NULL) { + _CLTHROWA(CL_ERR_IO, // DSR:PROPOSED: Better error checking. + "[RAMDirectory::open] The requested file does not exist."); + } + return _CLNEW RAMIndexInput(file); +} + +void RAMDirectory::close() +{ + SCOPED_LOCK_MUTEX(files_mutex); + files.clear(); +} + +bool RAMDirectory::doDeleteFile(const QString& name) +{ + SCOPED_LOCK_MUTEX(files_mutex); + files.remove(name); + return true; +} + +void RAMDirectory::renameFile(const QString& from, const QString& to) +{ + SCOPED_LOCK_MUTEX(files_mutex); + FileMap::iterator itr = files.find(from); + + /* DSR:CL_BUG_LEAK: + ** If a file named $to already existed, its old value was leaked. + ** My inclination would be to prevent this implicit deletion with an + ** exception, but it happens routinely in CLucene's internals (e.g., during + ** IndexWriter.addIndexes with the file named 'segments'). */ + if (files.exists(to)) + files.remove(to); + + if (itr == files.end()) { + char tmp[1024]; + _snprintf(tmp, 1024, "cannot rename %s, file does not exist", + from.toLocal8Bit().constData()); + _CLTHROWT(CL_ERR_IO, tmp); + } + + CND_PRECONDITION(itr != files.end(), "itr == files.end()") + + RAMFile* file = itr->second; + files.removeitr(itr, true, true); + files.put(to, file); +} + + +void RAMDirectory::touchFile(const QString& name) +{ + RAMFile* file = NULL; + { + SCOPED_LOCK_MUTEX(files_mutex); + file = files.get(name); + } + uint64_t ts1 = file->lastModified; + uint64_t ts2 = Misc::currentTimeMillis(); + + //make sure that the time has actually changed + while (ts1 == ts2) { + _LUCENE_SLEEP(1); + ts2 = Misc::currentTimeMillis(); + }; + + file->lastModified = ts2; +} + +IndexOutput* RAMDirectory::createOutput(const QString& name) +{ + /* Check the $files VoidMap to see if there was a previous file named + ** $name. If so, delete the old RAMFile object, but reuse the existing + ** char buffer ($n) that holds the filename. If not, duplicate the + ** supplied filename buffer ($name) and pass ownership of that memory ($n) + ** to $files. */ + + SCOPED_LOCK_MUTEX(files_mutex); + + QString n = files.getKey(name); + if (!n.isEmpty()) { + RAMFile* rf = files.get(name); + _CLDELETE(rf); + } else { + n = name; + } + + RAMFile* file = _CLNEW RAMFile(); +#ifdef _DEBUG + file->filename = n; +#endif + files[n] = file; + + return _CLNEW RAMIndexOutput(file); +} + +LuceneLock* RAMDirectory::makeLock(const QString& name) +{ + return _CLNEW RAMLock(name, this); +} + +QString RAMDirectory::toString() const +{ + return QLatin1String("RAMDirectory"); +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/store/RAMDirectory.h b/3rdparty/clucene/src/CLucene/store/RAMDirectory.h new file mode 100644 index 000000000..af92e30b2 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/store/RAMDirectory.h @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +*/ +#ifndef _lucene_store_RAMDirectory_ +#define _lucene_store_RAMDirectory_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include "Lock.h" +#include "Directory.h" +#include "CLucene/util/VoidMap.h" +#include "CLucene/util/Arrays.h" + +CL_NS_DEF(store) + +class RAMFile : LUCENE_BASE +{ +public: + CL_NS(util)::CLVector > buffers; + int64_t length; + uint64_t lastModified; + +#ifdef _DEBUG + QString filename; +#endif + + RAMFile(); + ~RAMFile(); +}; + +class RAMIndexOutput : public BufferedIndexOutput +{ +protected: + RAMFile* file; + int32_t pointer; + bool deleteFile; + + // output methods: + void flushBuffer(const uint8_t* src, const int32_t len); + +public: + RAMIndexOutput(RAMFile* f); + RAMIndexOutput(); + /** Construct an empty output buffer. */ + virtual ~RAMIndexOutput(); + + virtual void close(); + + // Random-at methods + virtual void seek(const int64_t pos); + int64_t length(); + /** Resets this to an empty buffer. */ + void reset(); + /** Copy the current contents of this buffer to the named output. */ + void writeTo(IndexOutput* output); +}; + +class RAMIndexInput : public BufferedIndexInput +{ +private: + RAMFile* file; + int32_t pointer; + int64_t _length; + +protected: + /** IndexInput methods */ + RAMIndexInput(const RAMIndexInput& clone); + void readInternal(uint8_t *dest, const int32_t len); + + /** Random-at methods */ + void seekInternal(const int64_t pos); + +public: + RAMIndexInput(RAMFile* f); + ~RAMIndexInput(); + IndexInput* clone() const; + + void close(); + int64_t length(); + QString getDirectoryType() const; +}; + + +/** +* A memory-resident {@link Directory} implementation. +*/ +class RAMDirectory : public Directory +{ + class RAMLock : public LuceneLock + { + private: + RAMDirectory* directory; + QString fname; + public: + RAMLock(const QString& name, RAMDirectory* dir); + virtual ~RAMLock(); + bool obtain(); + void release(); + bool isLocked(); + virtual QString toString() const; + }; + + typedef CL_NS(util)::CLHashMap > FileMap; + +protected: + /// Removes an existing file in the directory. + virtual bool doDeleteFile(const QString& name); + + /** + * Creates a new RAMDirectory instance from a different + * Directory implementation. This can be used to load + * a disk-based index into memory. + *

+ * This should be used only with indices that can fit into memory. + * + * @param dir a Directory value + * @exception IOException if an error occurs + */ + void _copyFromDir(Directory* dir, bool closeDir); + FileMap files; // unlike the java Hashtable, FileMap is not synchronized, and all access must be protected by a lock + +public: +#ifndef _CL_DISABLE_MULTITHREADING //do this so that the mutable keyword still works without mt enabled + mutable DEFINE_MUTEX(files_mutex) // mutable: const methods must also be able to synchronize properly +#endif + + // Returns a null terminated array of strings, one for each file in the directory. + QStringList list() const; + + /** Constructs an empty {@link Directory}. */ + RAMDirectory(); + + // Destructor - only call this if you are sure the directory + // is not being used anymore. Otherwise use the ref-counting + // facilities of dir->close + virtual ~RAMDirectory(); + RAMDirectory(Directory* dir); + + /** + * Creates a new RAMDirectory instance from the {@link FSDirectory}. + * + * @param dir a String specifying the full index directory path + */ + RAMDirectory(const QString& dir); + + /// Returns true iff the named file exists in this directory. + bool fileExists(const QString& name) const; + + /// Returns the time the named file was last modified. + int64_t fileModified(const QString& name) const; + + /// Returns the length in bytes of a file in the directory. + int64_t fileLength(const QString& name) const; + + /// Removes an existing file in the directory. + virtual void renameFile(const QString& from, const QString& to); + + /** Set the modified time of an existing file to now. */ + void touchFile(const QString& name); + + /// Creates a new, empty file in the directory with the given name. + /// Returns a stream writing this file. + virtual IndexOutput* createOutput(const QString& name); + + /// Construct a {@link Lock}. + /// @param name the name of the lock file + LuceneLock* makeLock(const QString& name); + + /// Returns a stream reading an existing file. + IndexInput* openInput(const QString& name); + + virtual void close(); + + QString toString() const; + + static QString DirectoryType() { return QLatin1String("RAM"); } + QString getDirectoryType() const { return DirectoryType(); } +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/store/TransactionalRAMDirectory.cpp b/3rdparty/clucene/src/CLucene/store/TransactionalRAMDirectory.cpp new file mode 100644 index 000000000..056fa9bc3 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/store/TransactionalRAMDirectory.cpp @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#include "CLucene/StdHeader.h" +#include "TransactionalRAMDirectory.h" + +CL_NS_DEF(store) +CL_NS_USE(util) + +TransactionalRAMDirectory::TransactionalRAMDirectory() + : RAMDirectory() + , filesToRestoreOnAbort(false, true) +{ + transOpen = false; +} + +TransactionalRAMDirectory::~TransactionalRAMDirectory() +{ +} + +bool TransactionalRAMDirectory::archiveOrigFileIfNecessary(const QString& name) +{ + // If a file named $name was present when the transaction started and the + // original RAMFile object has not been archived for restoration upon + // transaction abort, then do so, and return true. + // In any other case, return false. + if (fileExists(name) && filesToRemoveOnAbort.find(name) == filesToRemoveOnAbort.end()) { + // The file exists, but isn't recorded as having been created after the + // start of the transaction, so it must've been present at the start of + // the transaction. + + // Transfer memory ownership of both the key and the value from files to + // filesToRestoreOnAbort. + QString origName = files.getKey(name); + RAMFile* origFile = files.get(name); + files.remove(name, true, true); + filesToRestoreOnAbort.put(origName, origFile); + + CND_CONDITION(!fileExists(name), + "File should not exist immediately after archival."); + return true; + } + + return false; +} + +void TransactionalRAMDirectory::unarchiveOrigFile(const QString& name) +{ + QString origName = filesToRestoreOnAbort.getKey(name); + if (origName.isEmpty()) { + _CLTHROWA(CL_ERR_RAMTransaction, + "File submitted for unarchival was not archived."); + } + RAMFile* origFile = filesToRestoreOnAbort.get(name); + // Transfer memory ownership back to files from filesToRestoreOnAbort. + filesToRestoreOnAbort.remove(name, true, true); + files.put(origName, origFile); +} + +bool TransactionalRAMDirectory::transIsOpen() const +{ + return transOpen; +} + +void TransactionalRAMDirectory::transStart() +{ + if (transOpen) { + _CLTHROWA(CL_ERR_RAMTransaction, + "Must resolve previous transaction before starting another."); + } + + CND_CONDITION(filesToRemoveOnAbort.size() == 0, + "filesToRemoveOnAbort should have been cleared by either its" + " constructor or transResolved."); + + CND_CONDITION(filesToRestoreOnAbort.size() == 0, + "filesToRestoreOnAbort should have been cleared by either its" + " constructor or transResolved."); + + transOpen = true; +} + +void TransactionalRAMDirectory::transResolved() +{ + // This method implements actions common to both forms of transaction + // resolution. + filesToRemoveOnAbort.clear(); + filesToRestoreOnAbort.clear(); + transOpen = false; +} + +void TransactionalRAMDirectory::transCommit() +{ + if (!transOpen) + _CLTHROWA(CL_ERR_RAMTransaction, "There is no open transaction."); + + // All storage is in memory, so commit is ultra-simple. + transResolved(); +} + +void TransactionalRAMDirectory::transAbort() +{ + if (!transOpen) + _CLTHROWA(CL_ERR_RAMTransaction, "There is no open transaction."); + + // Delete each file in filesToRemoveOnAbort. + FilenameSet::const_iterator itrDel = filesToRemoveOnAbort.begin(); + for ( ; itrDel != filesToRemoveOnAbort.end(); ++itrDel) { + size_t nameLength = itrDel->first.length(); + + // Special exception: Refrain from deleting a lock's flag file, as that + // would interfere with the operation of the lock. + if (!(nameLength >= 5 + && itrDel->first.rightRef(5) == QLatin1String(".lock"))) { + RAMDirectory::deleteFile(itrDel->first); + } + } + // Ownership of the memory of both the key and the value never left files, + // so there's no need for a special directive to filesToRemoveOnAbort. + filesToRemoveOnAbort.clear(); + + // Now that any new-since-trans-start files with the same names as + // already-present-at-trans-start files are out of the way, restore each + // file in filesToRestoreOnAbort. + TransFileMap::const_iterator itr = filesToRestoreOnAbort.begin(); + for ( ; itr != filesToRestoreOnAbort.end(); ++itr) { + files.put(itr->first, itr->second); + filesToRestoreOnAbort.remove(itr->first); + } + + CND_CONDITION(filesToRestoreOnAbort.size() == 0, + "filesToRestoreOnAbort should be empty."); + + transResolved(); +} + +bool TransactionalRAMDirectory::doDeleteFile(const QString& name) +{ + if (!transOpen) + return RAMDirectory::doDeleteFile(name); + + bool wasOriginalAndWasArchived = archiveOrigFileIfNecessary(name); + if (!wasOriginalAndWasArchived) { + // The file to be deleted wasn't present at transaction start, so instead + // of archiving it, we delete it the conventional way, making sure to + // erase its record in filesToRemoveOnAbort if it was listed there. + filesToRemoveOnAbort.remove(name); + return RAMDirectory::doDeleteFile(name); + } + return true; +} + +void TransactionalRAMDirectory::renameFile(const QString& from, const QString& to) +{ + // During the review on 2005.03.18, decided not to implement transactional + // renameFile for two reasons: + // a) It's not needed in the limited scenario for which + // TransactionalRAMDirectory was designed (IndexWriter::addDocument and + // subcode). + // b) Supporting renaming during a transaction would add considerable + // bookkeeping overhead, reducing the performance of the overwhelmingly + // typical case (commit) in order to support the rare case (abort). + // + // This was not a thinly disguised punt due to the complication of + // implementing renameFile transactionally; rather, several implementations + // were considered, but it seemed wrongheaded to degrade the performance of + // the typical case based on the mere potential need to support renameFile + // at some future point for the benefit of the atypical case. + if (transOpen) { + _CLTHROWA(CL_ERR_RAMTransaction, + "TransactionalRAMDirectory disallows renameFile during a transaction."); + } + RAMDirectory::renameFile(from, to); +} + +IndexOutput* TransactionalRAMDirectory::createOutput(const QString& name) +{ + if (!transOpen) + return RAMDirectory::createOutput(name); + + bool wasOriginalAndWasArchived = archiveOrigFileIfNecessary(name); + try { + IndexOutput* ret = RAMDirectory::createOutput(name); + // Importantly, we store a pointer to the filename memory managed by + // files, rather than that passed in by the client (name). We don't make + // an additional copy of the filename's memory because the transactional + // metadata container filesToRemoveOnAbort is not at risk of outliving + // files. + filesToRemoveOnAbort.put(files.getKey(name), NULL); + return ret; + } catch (...) { + if (wasOriginalAndWasArchived) { + unarchiveOrigFile(name); + } + throw; + } +} + +void TransactionalRAMDirectory::close() +{ + if (transOpen) + transAbort(); + + RAMDirectory::close(); +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/store/TransactionalRAMDirectory.h b/3rdparty/clucene/src/CLucene/store/TransactionalRAMDirectory.h new file mode 100644 index 000000000..44c5e8e99 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/store/TransactionalRAMDirectory.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#ifndef _lucene_store_TransactionalRAMDirectory_ +#define _lucene_store_TransactionalRAMDirectory_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include + +#include "RAMDirectory.h" +#include "CLucene/util/VoidList.h" + +CL_NS_DEF(store) + +/*** +This transactional in-memory Directory was created to address a specific +situation, and was deliberately pared down to the simplest viable +implementation. For the sake of simplicity, this implementation imposes +restrictions on what operations can be performed in the directory while a +transaction is in progress (documented in TransactionalRAMDirectory.cpp). + +Because the Lucene Directory interface itself is rather simplistic, it +would not be difficult to expand TransactionalRAMDirectory so that it +provided fully general transactionality. However, the developer of this +original implementation was of the opinion that the last thing CLucene +needs is gratuitous features that exceed their required complexity and +haven't been rigorously tested. +*/ +class TransactionalRAMDirectory : public RAMDirectory +{ +private: + typedef CL_NS(util)::CLSet FilenameSet; + FilenameSet filesToRemoveOnAbort; + + typedef CL_NS(util)::CLSet > TransFileMap; + TransFileMap filesToRestoreOnAbort; + + bool transOpen; + + void transResolved(); + bool archiveOrigFileIfNecessary(const QString& name); + void unarchiveOrigFile(const QString& name); + +protected: + bool doDeleteFile(const QString& name); + +public: + TransactionalRAMDirectory(); + virtual ~TransactionalRAMDirectory(); + + bool transIsOpen() const; + void transStart(); + void transCommit(); + void transAbort(); + + // Constrained operations: + void renameFile(const QString& from, const QString& to); + IndexOutput* createOutput(const QString& name); + + void close(); +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/util/Arrays.h b/3rdparty/clucene/src/CLucene/util/Arrays.h new file mode 100644 index 000000000..ba60c5638 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/Arrays.h @@ -0,0 +1,164 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_util_Arrays_ +#define _lucene_util_Arrays_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "VoidList.h" + +CL_NS_DEF(util) + class Arrays{ + public: + template + class _Arrays { + protected: + //used by binarySearch to check for equality + virtual bool equals(_type a,_type b) const = 0; + virtual int32_t compare(_type a,_type b) const = 0; + public: + virtual ~_Arrays(){ + } + + void sort(_type* a, int32_t alen, int32_t fromIndex, int32_t toIndex) const{ + CND_PRECONDITION(fromIndex < toIndex,"fromIndex >= toIndex"); + CND_PRECONDITION(fromIndex >= 0,"fromIndex < 0"); + + // First presort the array in chunks of length 6 with insertion + // sort. A mergesort would give too much overhead for this length. + for (int32_t chunk = fromIndex; chunk < toIndex; chunk += 6) + { + int32_t end = min(chunk + 6, toIndex); + for (int32_t i = chunk + 1; i < end; i++) + { + if (compare(a[i - 1], a[i]) > 0) + { + // not already sorted + int32_t j = i; + _type elem = a[j]; + do + { + a[j] = a[j - 1]; + j--; + } + while (j > chunk && compare(a[j - 1], elem) > 0); + a[j] = elem; + } + } + } + + int32_t len = toIndex - fromIndex; + // If length is smaller or equal 6 we are done. + if (len <= 6) + return; + + _type* src = a; + _type* dest = _CL_NEWARRAY(_type,alen); + _type* t = NULL; // t is used for swapping src and dest + + // The difference of the fromIndex of the src and dest array. + int32_t srcDestDiff = -fromIndex; + + // The merges are done in this loop + for (int32_t size = 6; size < len; size <<= 1) + { + for (int32_t start = fromIndex; start < toIndex; start += size << 1) + { + // mid is the start of the second sublist; + // end the start of the next sublist (or end of array). + int32_t mid = start + size; + int32_t end = min(toIndex, mid + size); + + // The second list is empty or the elements are already in + // order - no need to merge + if (mid >= end || compare(src[mid - 1], src[mid]) <= 0) + { + memcpy(dest + start + srcDestDiff, src+start, (end-start)*sizeof(_type)); + }// The two halves just need swapping - no need to merge + else if (compare(src[start], src[end - 1]) > 0) + { + memcpy(dest+end-size+srcDestDiff, src+start, size * sizeof(_type)); + memcpy(dest+start+srcDestDiff, src+mid, (end-mid) * sizeof(_type)); + + }else{ + // Declare a lot of variables to save repeating + // calculations. Hopefully a decent JIT will put these + // in registers and make this fast + int32_t p1 = start; + int32_t p2 = mid; + int32_t i = start + srcDestDiff; + + // The main merge loop; terminates as soon as either + // half is ended + while (p1 < mid && p2 < end) + { + dest[i++] = src[(compare(src[p1], src[p2]) <= 0 + ? p1++ : p2++)]; + } + + // Finish up by copying the remainder of whichever half + // wasn't finished. + if (p1 < mid) + memcpy(dest+i,src+p1, (mid-p1) * sizeof(_type)); + else + memcpy(dest+i,src+p2, (end-p2) * sizeof(_type)); + } + } + // swap src and dest ready for the next merge + t = src; + src = dest; + dest = t; + fromIndex += srcDestDiff; + toIndex += srcDestDiff; + srcDestDiff = -srcDestDiff; + } + + // make sure the result ends up back in the right place. Note + // that src and dest may have been swapped above, so src + // contains the sorted array. + if (src != a) + { + // Note that fromIndex == 0. + memcpy(a+srcDestDiff,src,toIndex * sizeof(_type)); + } + } + }; + }; + + template + class CLListEquals: + public CL_NS_STD(binary_function) + { + typedef typename class1::const_iterator _itr1; + typedef typename class2::const_iterator _itr2; + public: + CLListEquals(){ + } + bool equals( class1* val1, class2* val2 ) const{ + static _comparator comp; + if ( val1 == val2 ) + return true; + size_t size = val1->size(); + if ( size != val2->size() ) + return false; + + _itr1 itr1 = val1->begin(); + _itr2 itr2 = val2->begin(); + while ( --size >= 0 ){ + if ( !comp(*itr1,*itr2) ) + return false; + itr1++; + itr2++; + } + return true; + } + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/util/BitSet.cpp b/3rdparty/clucene/src/CLucene/util/BitSet.cpp new file mode 100644 index 000000000..3679bd120 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/BitSet.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#include "CLucene/StdHeader.h" +#include "BitSet.h" +#include "CLucene/store/Directory.h" + +CL_NS_USE(store) +CL_NS_DEF(util) + +BitSet::BitSet(const BitSet& copy) + : _size(copy._size) + , _count(-1) +{ + int32_t len = (_size >> 3) + 1; + bits = _CL_NEWARRAY(uint8_t, len); + memcpy(bits, copy.bits, len); +} + +BitSet::BitSet(int32_t size) + : _size(size) + , _count(-1) +{ + int32_t len = (_size >> 3) + 1; + bits = _CL_NEWARRAY(uint8_t, len); + memset(bits, 0, len); +} + +BitSet::BitSet(CL_NS(store)::Directory* d, const QString& name) +{ + _count = -1; + CL_NS(store)::IndexInput* input = d->openInput(name); + try { + _size = input->readInt(); // read size + _count = input->readInt(); // read count + + bits = _CL_NEWARRAY(uint8_t,(_size >> 3) + 1); // allocate bits + input->readBytes(bits, (_size >> 3) + 1); // read bits + } _CLFINALLY ( + input->close(); + _CLDELETE(input ); + ); +} + +void BitSet::write(CL_NS(store)::Directory* d, const QString& name) +{ + CL_NS(store)::IndexOutput* output = d->createOutput(name); + try { + output->writeInt(size()); // write size + output->writeInt(count()); // write count + output->writeBytes(bits, (_size >> 3) + 1); // write bits + } _CLFINALLY ( + output->close(); + _CLDELETE(output); + ); +} + +BitSet::~BitSet() +{ + _CLDELETE_ARRAY(bits); +} + +void BitSet::set(int32_t bit, bool val) +{ + if (val) + bits[bit >> 3] |= 1 << (bit & 7); + else + bits[bit >> 3] &= ~(1 << (bit & 7)); + + _count = -1; +} + +int32_t BitSet::size() const +{ + return _size; +} + +int32_t BitSet::count() +{ + // if the BitSet has been modified + if (_count == -1) { + static const uint8_t BYTE_COUNTS[] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8}; + + int32_t c = 0; + int32_t end = (_size >> 3) + 1; + for (int32_t i = 0; i < end; i++) + c += BYTE_COUNTS[bits[i]]; // sum bits per uint8_t + _count = c; + } + return _count; +} + +BitSet* BitSet::clone() const +{ + return _CLNEW BitSet(*this); +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/util/BitSet.h b/3rdparty/clucene/src/CLucene/util/BitSet.h new file mode 100644 index 000000000..e93847e98 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/BitSet.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#ifndef _lucene_util_BitSet_ +#define _lucene_util_BitSet_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include + +#include "CLucene/store/Directory.h" + +CL_NS_DEF(util) + +class BitSet : LUCENE_BASE +{ +public: + // Create a bitset with the specified size + BitSet (int32_t size); + BitSet(CL_NS(store)::Directory* d, const QString& name); + void write(CL_NS(store)::Directory* d, const QString& name); + + // Destructor for the bit set + ~BitSet(); + + // get the value of the specified bit + inline bool get(const int32_t bit) const + { + return (bits[bit >> 3] & (1 << (bit & 7))) != 0; + } + + // set the value of the specified bit + void set(int32_t bit, bool val = true); + + ///returns the size of the bitset + int32_t size() const; + + // Returns the total number of one bits in this BitSet. This is + // efficiently computed and cached, so that, if the BitSet is not changed, + // no recomputation is done for repeated calls. + int32_t count(); + BitSet *clone() const; + +protected: + BitSet(const BitSet& copy); + +private: + int32_t _size; + int32_t _count; + uint8_t *bits; +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/util/Equators.cpp b/3rdparty/clucene/src/CLucene/util/Equators.cpp new file mode 100644 index 000000000..e112bd234 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/Equators.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#include "CLucene/StdHeader.h" +#include "Equators.h" + +CL_NS_DEF(util) + +bool Equals::Int32::operator()(const int32_t val1, const int32_t val2) const +{ + return (val1)==(val2); +} + +bool Equals::Char::operator()(const char* val1, const char* val2) const +{ + if ( val1 == val2 ) + return true; + return (strcmp(val1, val2) == 0); +} + +#ifdef _UCS2 +bool Equals::WChar::operator()(const wchar_t* val1, const wchar_t* val2) const +{ + if (val1 == val2) + return true; + return (_tcscmp(val1, val2) == 0); +} +#endif + +bool Equals::Qstring::operator()(const QString& val1, const QString& val2) const +{ + return (val1 == val2); +} + +/////////////////////////////////////////////////////////////////////////////// +// Comparors +/////////////////////////////////////////////////////////////////////////////// + +int32_t Compare::Int32::getValue() const +{ + return value; +} + +Compare::Int32::Int32(int32_t val) +{ + value = val; +} + +Compare::Int32::Int32() +{ + value = 0; +} + +int32_t Compare::Int32::compareTo(void* o) +{ + try { + Int32* other = (Int32*)o; + if (value == other->value) + return 0; + // Returns just -1 or 1 on inequality; doing math might overflow. + return value > other->value ? 1 : -1; + } catch(...) { + _CLTHROWA(CL_ERR_Runtime, "Couldnt compare types"); + } +} + +bool Compare::Int32::operator()(int32_t t1, int32_t t2) const +{ + return t1 > t2 ? true : false; +} + +size_t Compare::Int32::operator()(int32_t t) const +{ + return t; +} + +qreal Compare::Float::getValue() const +{ + return value; +} + +Compare::Float::Float(qreal val) +{ + value = val; +} + +int32_t Compare::Float::compareTo(void* o) +{ + try { + Float* other = (Float*)o; + if (value == other->value) + return 0; + // Returns just -1 or 1 on inequality; doing math might overflow. + return value > other->value ? 1 : -1; + } catch(...) { + _CLTHROWA(CL_ERR_Runtime,"Couldnt compare types"); + } +} + +bool Compare::Char::operator()(const char* val1, const char* val2) const +{ + if ( val1 == val2) + return false; + return (strcmp(val1, val2) < 0); +} + +size_t Compare::Char::operator()(const char* val1) const +{ + return CL_NS(util)::Misc::ahashCode(val1); +} + +#ifdef _UCS2 +bool Compare::WChar::operator()(const wchar_t* val1, const wchar_t* val2) const +{ + if ( val1==val2) + return false; + return (_tcscmp(val1, val2) < 0); +} + +size_t Compare::WChar::operator()(const wchar_t* val1) const +{ + return CL_NS(util)::Misc::whashCode(val1); +} +#endif + +const TCHAR* Compare::TChar::getValue() const +{ + return s; +} + +Compare::TChar::TChar() +{ + s = NULL; +} + +Compare::TChar::TChar(const TCHAR* str) +{ + this->s = str; +} + +int32_t Compare::TChar::compareTo(void* o) +{ + try { + TChar* os = (TChar*)o; + return _tcscmp(s, os->s); + } catch(...) { + _CLTHROWA(CL_ERR_Runtime,"Couldnt compare types"); + } + +} + +bool Compare::TChar::operator()(const TCHAR* val1, const TCHAR* val2) const +{ + if (val1 == val2) + return false; + + return (_tcscmp(val1, val2) < 0); +} + +size_t Compare::TChar::operator()(const TCHAR* val1) const +{ + return CL_NS(util)::Misc::thashCode(val1); +} + +bool Compare::Qstring::operator()(const QString& val1, const QString& val2) const +{ + return (val1 < val2); +} + +size_t Compare::Qstring::operator ()(const QString& val1) const +{ + return CL_NS(util)::Misc::qhashCode(val1); +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/util/Equators.h b/3rdparty/clucene/src/CLucene/util/Equators.h new file mode 100644 index 000000000..11fcb0eaf --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/Equators.h @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#ifndef _lucene_util_Equators_ +#define _lucene_util_Equators_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include + +//#ifdef QT_LINUXBASE +// we are going to use qreal now, we basically maintain our own clucene anyway +//// LSB doesn't define float_t - see http://bugs.linuxbase.org/show_bug.cgi?id=2374 +//typedef float float_t; +//#endif + +CL_NS_DEF(util) + +/////////////////////////////////////////////////////////////////////////////// +// Equators +/////////////////////////////////////////////////////////////////////////////// + +class Equals{ +public: + class Int32:public CL_NS_STD(binary_function) + { + public: + bool operator()( const int32_t val1, const int32_t val2 ) const; + }; + + class Char:public CL_NS_STD(binary_function) + { + public: + bool operator()( const char* val1, const char* val2 ) const; + }; +#ifdef _UCS2 + class WChar: public CL_NS_STD(binary_function) + { + public: + bool operator()( const wchar_t* val1, const wchar_t* val2 ) const; + }; + class TChar: public WChar{ + }; +#else + class TChar: public Char{ + }; +#endif + + template + class Void:public CL_NS_STD(binary_function) + { + public: + bool operator()( _cl* val1, _cl* val2 ) const{ + return val1==val2; + } + }; + + class Qstring : public CL_NS_STD(binary_function) + { + public: + bool operator() (const QString& val1, const QString& val2) const; + }; +}; + + +/////////////////////////////////////////////////////////////////////////////// +// Comparors +/////////////////////////////////////////////////////////////////////////////// + +class Comparable : LUCENE_BASE +{ +public: + virtual ~Comparable(){ + } + + virtual int32_t compareTo(void* o) = 0; +}; + +/** @internal */ +class Compare{ +public: + class _base + { // traits class for hash containers + public: + enum + { // parameters for hash table + bucket_size = 4, // 0 < bucket_size + min_buckets = 8 + }; // min_buckets = 2 ^^ N, 0 < N + + _base() + { + } + }; + + class Int32:public _base, public Comparable{ + int32_t value; + public: + int32_t getValue() const; + Int32(int32_t val); + Int32(); + int32_t compareTo(void* o); + bool operator()( int32_t t1, int32_t t2 ) const; + size_t operator()( int32_t t ) const; + }; + + + class Float:public Comparable{ + qreal value; + public: + qreal getValue() const; + Float(qreal val); + int32_t compareTo(void* o); + }; + + + class Char: public _base // + { + public: + bool operator()( const char* val1, const char* val2 ) const; + size_t operator()( const char* val1) const; + }; + +#ifdef _UCS2 + class WChar: public _base // + { + public: + bool operator()( const wchar_t* val1, const wchar_t* val2 ) const; + size_t operator()( const wchar_t* val1) const; + }; +#endif + + class TChar: public _base, public Comparable{ + const TCHAR* s; + public: + const TCHAR* getValue() const; + + TChar(); + TChar(const TCHAR* str); + int32_t compareTo(void* o); + bool operator()( const TCHAR* val1, const TCHAR* val2 ) const; + size_t operator()( const TCHAR* val1) const; + }; + + + template + class Void:public _base // + { + public: + int32_t compareTo(_cl* o){ + if ( this == o ) + return o; + else + return this > o ? 1 : -1; + } + bool operator()( _cl* t1, _cl* t2 ) const{ + return t1 > t2 ? true : false; + } + size_t operator()( _cl* t ) const{ + return (size_t)t; + } + }; + + class Qstring : public _base + { + public: + bool operator() (const QString& val1, const QString& val2) const; + size_t operator() (const QString& val1) const; + }; +}; + +/////////////////////////////////////////////////////////////////////////////// +// allocators +/////////////////////////////////////////////////////////////////////////////// + +class Deletor +{ +public: + + template + class Array{ + public: + static void doDelete(_kt* arr){ + _CLDELETE_LARRAY(arr); + } + }; + class tcArray{ + public: + static void doDelete(const TCHAR* arr){ + _CLDELETE_CARRAY(arr); + } + }; + class acArray{ + public: + static void doDelete(const char* arr){ + _CLDELETE_CaARRAY(arr); + } + }; + + class Unintern{ + public: + static void doDelete(TCHAR* arr); + }; + template + class Object{ + public: + static void doDelete(_kt* obj){ + _CLLDELETE(obj); + } + }; + template + class Void{ + public: + static void doDelete(_kt* obj){ + _CLVDELETE(obj); + } + }; + class Dummy{ + public: + static void doDelete(const void* nothing) + { + // TODO: remove all occurances where it hits this point + // CND_WARNING(false, "Deletor::Dummy::doDelete run, set deleteKey + // or deleteValue to false"); + } + }; + class DummyInt32{ + public: + static void doDelete(const int32_t nothing){ + } + }; + class DummyFloat{ + public: + static void doDelete(const qreal nothing){ + } + }; + template + class ConstNullVal{ + public: + static void doDelete(const _type nothing) + { + // TODO: remove all occurances where it hits this point + // CND_WARNING(false, "Deletor::Dummy::doDelete run, set deleteKey + // or deleteValue to false"); + } + }; + + template + class NullVal{ + public: + static void doDelete(_type nothing) + { + // TODO: remove all occurances where it hits this point + // CND_WARNING(false, "Deletor::Dummy::doDelete run, set deleteKey + // or deleteValue to false"); + } + }; + class DummyQString { + public: + static void doDelete(const QString& nothing) { + } + }; +}; +//////////////////////////////////////////////////////////////////////////////// + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/util/FastCharStream.cpp b/3rdparty/clucene/src/CLucene/util/FastCharStream.cpp new file mode 100644 index 000000000..f9fbe9b10 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/FastCharStream.cpp @@ -0,0 +1,107 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "FastCharStream.h" + +#include "CLucene/util/Reader.h" + +CL_NS_DEF(util) + +const int32_t FastCharStream::maxRewindSize = LUCENE_MAX_WORD_LEN*2; + + FastCharStream::FastCharStream(Reader* reader): + pos(0), + rewindPos(0), + resetPos(0), + col(1), + line(1), + input(reader) + { + input->mark(maxRewindSize); + } + FastCharStream::~FastCharStream(){ + } + void FastCharStream::readChar(TCHAR &c) { + try{ + int32_t r = input->read(); + if ( r == -1 ) + input = NULL; + c = r; + }catch(CLuceneError& err){ + if ( err.number() == CL_ERR_IO ) + input = 0; + throw err; + } + } + int FastCharStream::GetNext() + { + // printf("getnext\n"); + if (input == 0 ) // end of file + { + _CLTHROWA(CL_ERR_IO,"warning : FileReader.GetNext : Read TCHAR over EOS."); + } + // this is rather inefficient + // implementing the functions from the java version of + // charstream will be much more efficient. + ++pos; + if ( pos > resetPos + maxRewindSize && rewindPos == 0) { + // move the marker one position (~expensive) + resetPos = pos-(maxRewindSize/2); + if ( resetPos != input->reset(resetPos) ) + _CLTHROWA(CL_ERR_IO,"Unexpected reset() result"); + input->mark(maxRewindSize); + input->skip((maxRewindSize/2) - 1); + } + TCHAR ch; + readChar(ch); + + if (input == NULL) { // eof + return -1; + } + if (rewindPos == 0) { + col += 1; + if(ch == '\n') { + line++; + col = 1; + } + } else { + rewindPos--; + } + return ch; + } + + void FastCharStream::UnGet(){ +// printf("UnGet \n"); + if (input == 0) + return; + if ( pos == 0 ) { + _CLTHROWA(CL_ERR_IO,"error : No character can be UnGet"); + } + rewindPos++; + + input->reset(pos-1); + pos--; + } + + int FastCharStream::Peek() { + int c = GetNext(); + UnGet(); + return c; + } + + bool FastCharStream::Eos() const { + return input==NULL; + } + + int32_t FastCharStream::Column() const { + return col; + } + + int32_t FastCharStream::Line() const { + return line; + } +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/util/FastCharStream.h b/3rdparty/clucene/src/CLucene/util/FastCharStream.h new file mode 100644 index 000000000..24e5b5612 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/FastCharStream.h @@ -0,0 +1,55 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_util_FastCharStream_ +#define _lucene_util_FastCharStream_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/util/Reader.h" + +CL_NS_DEF(util) + + /** Ported implementation of the FastCharStream class. */ + class FastCharStream:LUCENE_BASE + { + static const int32_t maxRewindSize; + int32_t pos; + int32_t rewindPos; + int64_t resetPos; + int32_t col; + int32_t line; + // read character from stream return false on error + void readChar(TCHAR &); + public: + Reader* input; + + /// Initializes a new instance of the FastCharStream class LUCENE_EXPORT. + FastCharStream(Reader* reader); + ~FastCharStream(); + + /// Returns the next TCHAR from the stream. + int GetNext(); + + void UnGet(); + + /// Returns the current top TCHAR from the input stream without removing it. + int Peek(); + + + /// Returns True if the end of stream was reached. + bool Eos() const; + + /// Gets the current column. + int32_t Column() const; + + /// Gets the current line. + int32_t Line() const; + }; +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/util/Misc.cpp b/3rdparty/clucene/src/CLucene/util/Misc.cpp new file mode 100644 index 000000000..42e3fd0a8 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/Misc.cpp @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#include "CLucene/StdHeader.h" +#include "Misc.h" + +#ifdef _CL_TIME_WITH_SYS_TIME +# include +# include +#else +# if defined(_CL_HAVE_SYS_TIME_H) +# include +# else +# include +# endif +#endif + +#ifdef _CL_HAVE_SYS_TIMEB_H +# include +#endif + +#ifdef UNDER_CE +#include +#endif + +CL_NS_DEF(util) + +uint64_t Misc::currentTimeMillis() +{ +#ifndef UNDER_CE +#if defined(_CLCOMPILER_MSVC) || defined(__MINGW32__) || defined(__BORLANDC__) + struct _timeb tstruct; + _ftime(&tstruct); + + return (((uint64_t) tstruct.time) * 1000) + tstruct.millitm; +#else + struct timeval tstruct; + if (gettimeofday(&tstruct, NULL) < 0) { + _CLTHROWA(CL_ERR_Runtime,"Error in gettimeofday call."); + } + + return (((uint64_t) tstruct.tv_sec) * 1000) + tstruct.tv_usec / 1000; +#endif +#else //UNDER_CE + QT_USE_NAMESPACE + QTime t = QTime::currentTime(); + return t.second() * 1000 + t.msec(); +#endif //UNDER_CE +} + +// #pragma mark -- char related utils + +size_t Misc::ahashCode(const char* str) +{ + // Compute the hash code using a local variable to be reentrant. + size_t hashCode = 0; + while (*str != 0) + hashCode = hashCode * 31 + *str++; + return hashCode; +} + +size_t Misc::ahashCode(const char* str, size_t len) +{ + // Compute the hash code using a local variable to be reentrant. + size_t count = len; + size_t hashCode = 0; + for (size_t i = 0; i < count; i++) + hashCode = hashCode * 31 + *str++; + return hashCode; +} + +char* Misc::ajoin(const char* a, const char* b, const char* c, const char* d, + const char* e, const char* f) +{ +#define aLEN(x) (x == NULL ? 0 : strlen(x)) + const size_t totalLen = aLEN(a) + aLEN(b) + aLEN(c) + aLEN(d) + aLEN(e) + + aLEN(f) + sizeof(char); /* Space for terminator. */ + + char* buf = _CL_NEWARRAY(char, totalLen); + buf[0] = 0; + if (a != NULL) + strcat(buf, a); + + if (b != NULL) + strcat(buf, b); + + if (c != NULL) + strcat(buf, c); + + if (d != NULL) + strcat(buf, d); + + if (e != NULL) + strcat(buf, e); + + if (f != NULL) + strcat(buf, f); + + return buf; +} + +char* Misc::segmentname(const char* segment, const char* ext, int32_t x) +{ + CND_PRECONDITION(ext != NULL, "ext is NULL"); + + char* buf = _CL_NEWARRAY(char, CL_MAX_PATH); + if (x == -1) + _snprintf(buf, CL_MAX_PATH, "%s%s", segment, ext); + else + _snprintf(buf, CL_MAX_PATH, "%s%s%d", segment, ext, x); + return buf; +} + +void Misc::segmentname(char* buffer, int32_t bufferLen, const char* segment, + const char* ext, int32_t x) +{ + CND_PRECONDITION(buffer != NULL, "buffer is NULL"); + CND_PRECONDITION(segment != NULL, "segment is NULL"); + CND_PRECONDITION(ext != NULL, "extention is NULL"); + + if (x == -1) + _snprintf(buffer, bufferLen, "%s%s", segment, ext); + else + _snprintf(buffer, bufferLen, "%s%s%d", segment, ext, x); +} + +// #pragma mark -- qt related utils + +size_t Misc::qhashCode(const QString& str) +{ + size_t hashCode = 0; + for (int i = 0; i < str.count(); ++i) + hashCode = hashCode * 31 + str.at(i).unicode(); + return hashCode; +} + +size_t Misc::qhashCode(const QString& str, size_t len) +{ + size_t count = len; + size_t hashCode = 0; + for (size_t i = 0; i < count; ++i) + hashCode = hashCode * 31 + str.at(i).unicode(); + return hashCode; +} + +QString Misc::qjoin(const QString &a, const QString &b, const QString &c, + const QString &d, const QString &e, const QString &f) +{ + QString buffer; + + if (!a.isNull() && !a.isEmpty()) + buffer.append(a); + + if (!b.isNull() && !b.isEmpty()) + buffer.append(b); + + if (!c.isNull() && !c.isEmpty()) + buffer.append(c); + + if (!d.isNull() && !d.isEmpty()) + buffer.append(d); + + if (!e.isNull() && !e.isEmpty()) + buffer.append(e); + + if (!f.isNull() && !f.isEmpty()) + buffer.append(f); + + return buffer; +} + +QString Misc::segmentname(const QString& segment, const QString& ext, int32_t x) +{ + CND_PRECONDITION(!ext.isEmpty(), "ext is NULL"); + + if (x == -1) + return QString(segment + ext); + + QString buf(QLatin1String("%1%2%3")); + return buf.arg(segment).arg(ext).arg(x); +} + +void Misc::segmentname(QString& buffer, int32_t bufferLen, + const QString& segment, const QString& ext, int32_t x) +{ + CND_PRECONDITION(!segment.isEmpty(), "segment is NULL"); + CND_PRECONDITION(!ext.isEmpty(), "extention is NULL"); + + buffer = segment + ext; + if (x != -1) + buffer += QString::number(x); +} + +// #pragma mark -- TCHAR related utils + +int32_t Misc::stringDifference(const TCHAR* s1, int32_t len1, const TCHAR* s2, + int32_t len2) +{ + int32_t len = len1 < len2 ? len1 : len2; + for (int32_t i = 0; i < len; i++) + if (s1[i] != s2[i]) + return i; + return len; +} + +/* DSR:CL_BUG: (See comment for join method in Misc.h): */ +TCHAR* Misc::join (const TCHAR* a, const TCHAR* b, const TCHAR* c, + const TCHAR* d, const TCHAR* e, const TCHAR* f) +{ +#define LEN(x) (x == NULL ? 0 : _tcslen(x)) + const size_t totalLen = LEN(a) + LEN(b) + LEN(c) + LEN(d) + LEN(e) + LEN(f) + + sizeof(TCHAR); /* Space for terminator. */ + + TCHAR* buf = _CL_NEWARRAY(TCHAR, totalLen); + buf[0] = 0; + if (a != NULL) + _tcscat(buf, a); + + if (b != NULL) + _tcscat(buf, b); + + if (c != NULL) + _tcscat(buf, c); + + if (d != NULL) + _tcscat(buf, d); + + if (e != NULL) + _tcscat(buf, e); + + if (f != NULL) + _tcscat(buf, f); + + return buf; +} + +#ifdef _UCS2 + +size_t Misc::whashCode(const wchar_t* str) +{ + // Compute the hash code using a local variable to be reentrant. + size_t hashCode = 0; + while (*str != 0) + hashCode = hashCode * 31 + *str++; + return hashCode; +} + +size_t Misc::whashCode(const wchar_t* str, size_t len) +{ + // Compute the hash code using a local variable to be reentrant. + size_t count = len; + size_t hashCode = 0; + for (size_t i = 0; i < count; i++) + hashCode = hashCode * 31 + *str++; + return hashCode; +} + +char* Misc::_wideToChar(const wchar_t* s CL_FILELINEPARAM) +{ + size_t len = _tcslen(s); + char* msg = _CL_NEWARRAY(char, len + 1); + _cpywideToChar(s, msg, len + 1); + return msg; +} + +void Misc::_cpywideToChar(const wchar_t* s, char* d, size_t len) +{ + size_t sLen = wcslen(s); + for (uint32_t i = 0; i < len && i < sLen + 1; i++) + d[i] = LUCENE_OOR_CHAR(s[i]); +} + +wchar_t* Misc::_charToWide(const char* s CL_FILELINEPARAM) +{ + size_t len = strlen(s); + wchar_t* msg = _CL_NEWARRAY(wchar_t, len + 1); + _cpycharToWide(s, msg, len + 1); + return msg; +} + +void Misc::_cpycharToWide(const char* s, wchar_t* d, size_t len) +{ + size_t sLen = strlen(s); + for (uint32_t i = 0; i < len && i < sLen + 1; i++) + d[i] = s[i]; +} + +#endif + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/util/Misc.h b/3rdparty/clucene/src/CLucene/util/Misc.h new file mode 100644 index 000000000..561c6e4d9 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/Misc.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team + * + * Distributable under the terms of either the Apache License (Version 2.0) or + * the GNU Lesser General Public License, as specified in the COPYING file. + * + * Changes are Copyright(C) 2007, 2008 by Nokia Corporation and/or its subsidiary(-ies), all rights reserved. +*/ +#ifndef _lucene_util_Misc_H +#define _lucene_util_Misc_H + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include + +CL_NS_DEF(util) + +class Misc +{ +public: + static uint64_t currentTimeMillis(); + + static size_t ahashCode(const char* str); + static size_t ahashCode(const char* str, size_t len); + static char* ajoin(const char* a, const char* b, const char* c = NULL, + const char* d = NULL, const char* e = NULL, const char* f = NULL); + static char* segmentname(const char* segment, const char* ext, int32_t x = -1); + static void segmentname(char* buffer, int32_t bufferLen, const char* segment, + const char* ext, int32_t x = -1); + + static size_t qhashCode(const QString& str); + static size_t qhashCode(const QString& str, size_t len); + static QString qjoin(const QString& a, const QString& b, + const QString& c = QString(), const QString& d = QString(), + const QString& e = QString(), const QString& f = QString()); + static QString segmentname(const QString& segment, const QString& ext, + int32_t x = -1 ); + static void segmentname(QString& buffer, int32_t bufferLen, + const QString& Segment, const QString& ext, int32_t x = -1); + + // Compares two strings, character by character, and returns the + // first position where the two strings differ from one another. + // + // @param s1 The first string to compare + // @param s1Len The length of the first string to compare + // @param s2 The second string to compare + // @param s2Len The length of the second string to compare + // @return The first position where the two strings differ. + static int32_t stringDifference(const TCHAR* s1, int32_t s1Len, + const TCHAR* s2, int32_t s2Len); + static TCHAR* join (const TCHAR* a, const TCHAR* b, const TCHAR* c = NULL, + const TCHAR* d = NULL, const TCHAR* e = NULL, const TCHAR* f = NULL ); + +#ifdef _UCS2 + static size_t whashCode(const wchar_t* str); + static size_t whashCode(const wchar_t* str, size_t len); + +# define thashCode whashCode + + static char* _wideToChar(const wchar_t* s CL_FILELINEPARAM); + static void _cpywideToChar(const wchar_t* s, char* d, size_t len); + + static wchar_t* _charToWide(const char* s CL_FILELINEPARAM); + static void _cpycharToWide(const char* s, wchar_t* d, size_t len); + +#else +# define thashCode ahashCode +#endif +}; + +CL_NS_END + +#endif diff --git a/3rdparty/clucene/src/CLucene/util/PriorityQueue.h b/3rdparty/clucene/src/CLucene/util/PriorityQueue.h new file mode 100644 index 000000000..45649ee7f --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/PriorityQueue.h @@ -0,0 +1,177 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_util_PriorityQueue_ +#define _lucene_util_PriorityQueue_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif +CL_NS_DEF(util) + +// A PriorityQueue maintains a partial ordering of its elements such that the +// least element can always be found in constant time. Put()'s and pop()'s +// require log(size) time. +template class PriorityQueue:LUCENE_BASE { + private: + _type* heap; //(was object[]) + size_t _size; + bool dk; + size_t maxSize; + + void upHeap(){ + size_t i = _size; + _type node = heap[i]; // save bottom node (WAS object) + int32_t j = ((uint32_t)i) >> 1; + while (j > 0 && lessThan(node,heap[j])) { + heap[i] = heap[j]; // shift parents down + i = j; + j = ((uint32_t)j) >> 1; + } + heap[i] = node; // install saved node + } + void downHeap(){ + size_t i = 1; + _type node = heap[i]; // save top node + size_t j = i << 1; // find smaller child + size_t k = j + 1; + if (k <= _size && lessThan(heap[k], heap[j])) { + j = k; + } + while (j <= _size && lessThan(heap[j],node)) { + heap[i] = heap[j]; // shift up child + i = j; + j = i << 1; + k = j + 1; + if (k <= _size && lessThan(heap[k], heap[j])) { + j = k; + } + } + heap[i] = node; // install saved node + } + + protected: + PriorityQueue(){ + this->_size = 0; + this->dk = false; + this->heap = NULL; + this->maxSize = 0; + } + + // Determines the ordering of objects in this priority queue. Subclasses + // must define this one method. + virtual bool lessThan(_type a, _type b)=0; + + // Subclass constructors must call this. + void initialize(const int32_t maxSize, bool deleteOnClear){ + _size = 0; + dk = deleteOnClear; + int32_t heapSize = maxSize + 1; + heap = _CL_NEWARRAY(_type,heapSize); + this->maxSize = maxSize; + } + + public: + virtual ~PriorityQueue(){ + clear(); + _CLDELETE_ARRAY(heap); + } + + /** + * Adds an Object to a PriorityQueue in log(size) time. + * If one tries to add more objects than maxSize from initialize + * a RuntimeException (ArrayIndexOutOfBound) is thrown. + */ + void put(_type element){ + if ( _size>=maxSize ) + _CLTHROWA(CL_ERR_IndexOutOfBounds,"add is out of bounds"); + + ++_size; + heap[_size] = element; + upHeap(); + } + + /** + * Adds element to the PriorityQueue in log(size) time if either + * the PriorityQueue is not full, or not lessThan(element, top()). + * @param element + * @return true if element is added, false otherwise. + */ + bool insert(_type element){ + if(_size < maxSize){ + put(element); + return true; + }else if(_size > 0 && !lessThan(element, top())){ + if ( dk ){ + _valueDeletor::doDelete(heap[1]); + } + heap[1] = element; + adjustTop(); + return true; + }else + return false; + } + + /** + * Returns the least element of the PriorityQueue in constant time. + */ + _type top(){ + if (_size > 0) + return heap[1]; + else + return NULL; + } + + /** Removes and returns the least element of the PriorityQueue in log(size) + * time. + */ + _type pop(){ + if (_size > 0) { + _type result = heap[1]; // save first value + heap[1] = heap[_size]; // move last to first + + heap[_size] = (_type)0; // permit GC of objects + --_size; + downHeap(); // adjust heap + return result; + } else + return (_type)NULL; + } + + /**Should be called when the object at top changes values. Still log(n) + worst case, but it's at least twice as fast to

+		    { pq.top().change(); pq.adjustTop(); }
+		   
instead of
+		    { o = pq.pop(); o.change(); pq.push(o); }
+		   
+ */ + void adjustTop(){ + downHeap(); + } + + + /** + * Returns the number of elements currently stored in the PriorityQueue. + */ + size_t size(){ + return _size; + } + + /** + * Removes all entries from the PriorityQueue. + */ + void clear(){ + for (size_t i = 1; i <= _size; ++i){ + if ( dk ){ + _valueDeletor::doDelete(heap[i]); + } + } + _size = 0; + } + }; + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/util/Reader.cpp b/3rdparty/clucene/src/CLucene/util/Reader.cpp new file mode 100644 index 000000000..1ce97106d --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/Reader.cpp @@ -0,0 +1,186 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "Reader.h" + +CL_NS_DEF(util) + +StringReader::StringReader ( const TCHAR* value ): + Reader(NULL,true){ + reader = new jstreams::StringReader(value); +} +StringReader::StringReader ( const TCHAR* value, const int32_t length ): + Reader(NULL,true){ + reader = new jstreams::StringReader(value,length); +} +StringReader::StringReader ( const TCHAR* value, const int32_t length, bool copyData ): + Reader(NULL,true){ + reader = new jstreams::StringReader(value,length, copyData); +} +StringReader::~StringReader(){ +} + + +FileReader::FileReader ( const char* path, const char* enc, + const int32_t cachelen, const int32_t /*cachebuff*/ ): + Reader(NULL, true) +{ + this->input = new jstreams::FileInputStream(path, cachelen); + this->reader = new SimpleInputStreamReader(this->input,enc); //(this is a jstream object) +} + +FileReader::~FileReader (){ + if (input) + delete input; +} +int32_t FileReader::read(const TCHAR*& start, int32_t _min, int32_t _max) { + return reader->read(start, _min, _max); +} +int64_t FileReader::mark(int32_t readlimit) { + return reader->mark(readlimit); +} +int64_t FileReader::reset(int64_t newpos) { + return reader->reset(newpos); +} + + + +SimpleInputStreamReader::SimpleInputStreamReader(jstreams::StreamBase *i, const char* enc) +{ + finishedDecoding = false; + input = i; + charbuf.setSize(262); + + if ( strcmp(enc,"ASCII")==0 ) + encoding = ASCII; +#ifdef _UCS2 + else if ( strcmp(enc,"UTF-8")==0 ) + encoding = UTF8; + else if ( strcmp(enc,"UCS-2LE")==0 ) + encoding = UCS2_LE; +#endif + else + _CLTHROWA(CL_ERR_IllegalArgument,"Unsupported encoding, use jstreams iconv based instead"); + + mark(262); + charsLeft = 0; +} +SimpleInputStreamReader::~SimpleInputStreamReader(){ + input = NULL; +} +int32_t SimpleInputStreamReader::decode(TCHAR* start, int32_t space){ + // decode from charbuf + const char *inbuf = charbuf.readPos; + const char *inbufend = charbuf.readPos + charbuf.avail; + TCHAR *outbuf = start; + const TCHAR *outbufend = outbuf + space; + + if ( encoding == ASCII ){ + while ( outbuf inbufend ){ + break; //character incomplete + }else{ + size_t rd = lucene_utf8towc(outbuf,inbuf,inbufend-inbuf); + if ( rd == 0 ){ + error = "Invalid multibyte sequence."; + status = jstreams::Error; + return -1; + }else{ + inbuf+=rd; + outbuf++; + } + } + } +#endif //_UCS2 + }else + _CLTHROWA(CL_ERR_Runtime,"Unexpected encoding"); + + if ( outbuf < outbufend ) { + //we had enough room to convert the entire input + if ( inbuf < inbufend ) { + // last character is incomplete + // move from inbuf to the end to the start of + // the buffer + memmove(charbuf.start, inbuf, inbufend-inbuf); + charbuf.readPos = charbuf.start; + charbuf.avail = inbufend-inbuf; + } else if ( outbuf < outbufend ) { //input sequence was completely converted + charbuf.readPos = charbuf.start; + charbuf.avail = 0; + if (input == NULL) { + finishedDecoding = true; + } + } + } else { + charbuf.readPos += charbuf.avail - (inbufend-inbuf); + charbuf.avail = inbufend-inbuf; + } + return outbuf-start; +} + +int32_t SimpleInputStreamReader::fillBuffer(TCHAR* start, int32_t space) { + // fill up charbuf + if (input && charbuf.readPos == charbuf.start) { + const char *begin; + int32_t numRead; + numRead = input->read(begin, 1, charbuf.size - charbuf.avail); + //printf("filled up charbuf\n"); + if (numRead < -1) { + error = input->getError(); + status = jstreams::Error; + input = 0; + return numRead; + } + if (numRead < 1) { + // signal end of input buffer + input = 0; + if (charbuf.avail) { + error = "stream ends on incomplete character"; + status = jstreams::Error; + } + return -1; + } + // copy data into other buffer + memmove( charbuf.start + charbuf.avail, begin, numRead * sizeof(char)); + charbuf.avail = numRead + charbuf.avail; + } + // decode + int32_t n = decode(start, space); + //printf("decoded %i\n", n); + return n; +} + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/util/Reader.h b/3rdparty/clucene/src/CLucene/util/Reader.h new file mode 100644 index 000000000..6b018b3aa --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/Reader.h @@ -0,0 +1,138 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_util_Reader_ +#define _lucene_util_Reader_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "streambase.h" +#include "stringreader.h" +#include "fileinputstream.h" +#include "bufferedstream.h" + +CL_NS_DEF(util) +/** +* An inline wrapper that reads from Jos van den Oever's jstreams +*/ +class Reader:LUCENE_BASE { +typedef jstreams::StreamBase jsReader; +public: + bool deleteReader; + jsReader* reader; + + Reader(jsReader* reader, bool deleteReader){ + this->reader = reader; + this->deleteReader = deleteReader; + } + virtual ~Reader(){ + if ( deleteReader ) + delete reader; + reader = NULL; + } + inline int read(){ + const TCHAR*b; + int32_t nread = reader->read(b, 1,1); + if ( nread < -1 ) //if not eof + _CLTHROWA(CL_ERR_IO,reader->getError() ); + else if ( nread == -1 ) + return -1; + else + return b[0]; + } + /** + * Read at least 1 character, and as much as is conveniently available + */ + inline int32_t read(const TCHAR*& start){ + int32_t nread = reader->read(start,1,0); + if ( nread < -1 ) //if not eof + _CLTHROWA(CL_ERR_IO,reader->getError()); + else + return nread; + } + inline int32_t read(const TCHAR*& start, int32_t len){ + int32_t nread = reader->read(start, len, len); + if ( nread < -1 ) //if not eof + _CLTHROWA(CL_ERR_IO,reader->getError()); + else + return nread; + } + inline int64_t skip(int64_t ntoskip){ + int64_t skipped = reader->skip(ntoskip); + if ( skipped < 0 ) + _CLTHROWA(CL_ERR_IO,reader->getError()); + else + return skipped; + } + inline int64_t mark(int32_t readAheadlimit){ + int64_t pos = reader->mark(readAheadlimit); + if ( pos < 0 ) + _CLTHROWA(CL_ERR_IO,reader->getError()); + else + return pos; + } + int64_t reset(int64_t pos){ + int64_t r = reader->reset(pos); + if ( r < 0 ) + _CLTHROWA(CL_ERR_IO,reader->getError()); + else + return r; + } +}; + +///A helper class which constructs a the jstreams StringReader. +class StringReader: public Reader{ +public: + StringReader ( const TCHAR* value ); + StringReader ( const TCHAR* value, const int32_t length ); + StringReader ( const TCHAR* value, const int32_t length, bool copyData ); + ~StringReader(); +}; + +/** A very simple inputstreamreader implementation. For a +* more complete InputStreamReader, use the jstreams version +* located in the contrib package +*/ +class SimpleInputStreamReader: public jstreams::BufferedInputStream{ + int32_t decode(TCHAR* start, int32_t space); + int encoding; + enum{ + ASCII=1, + UTF8=2, + UCS2_LE=3 + }; + bool finishedDecoding; + jstreams::StreamBase* input; + int32_t charsLeft; + + jstreams::InputStreamBuffer charbuf; + int32_t fillBuffer(TCHAR* start, int32_t space); +public: + SimpleInputStreamReader(jstreams::StreamBase *i, const char* encoding); + ~SimpleInputStreamReader(); +}; + +/** +* A helper class which constructs a FileReader with a specified +* simple encodings, or a given inputstreamreader +*/ +class FileReader: public Reader{ + jstreams::FileInputStream* input; +public: + FileReader ( const char* path, const char* enc, + const int32_t cachelen = 13, + const int32_t cachebuff = 14 ); //todo: optimise these cache values + ~FileReader (); + + int32_t read(const TCHAR*& start, int32_t _min, int32_t _max); + int64_t mark(int32_t readlimit); + int64_t reset(int64_t); +}; + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/util/StringBuffer.cpp b/3rdparty/clucene/src/CLucene/util/StringBuffer.cpp new file mode 100644 index 000000000..b5f1ca238 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/StringBuffer.cpp @@ -0,0 +1,335 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "StringBuffer.h" +#include "Misc.h" + +CL_NS_DEF(util) + + StringBuffer::StringBuffer(TCHAR* buf,int32_t maxlen, const bool consumeBuffer){ + buffer = buf; + bufferLength = maxlen; + bufferOwner = !consumeBuffer; + len = 0; + } + StringBuffer::StringBuffer(){ + //Func - Constructor. Allocates a buffer with the default length. + //Pre - true + //Post - buffer of length bufferLength has been allocated + + //Initialize + bufferLength = LUCENE_DEFAULT_TOKEN_BUFFER_SIZE; + len = 0; + //Allocate a buffer of length bufferLength + buffer = _CL_NEWARRAY(TCHAR,bufferLength); + bufferOwner = true; + } + + StringBuffer::StringBuffer(const int32_t initSize){ + //Func - Constructor. Allocates a buffer of length initSize + 1 + //Pre - initSize > 0 + //Post - A buffer has been allocated of length initSize + 1 + + //Initialize the bufferLength to initSize + 1 The +1 is for the terminator '\0' + bufferLength = initSize + 1; + len = 0; + //Allocate a buffer of length bufferLength + buffer = _CL_NEWARRAY(TCHAR,bufferLength); + bufferOwner = true; + } + + StringBuffer::StringBuffer(const TCHAR* value){ + //Func - Constructor. + // Creates an instance of Stringbuffer containing a copy of the string value + //Pre - value != NULL + //Post - An instance of StringBuffer has been created containing the copy of the string value + + //Initialize the length of the string to be stored in buffer + len = (int32_t) _tcslen(value); + + //Calculate the space occupied in buffer by a copy of value + const int32_t occupiedLength = len + 1; + + // Minimum allocated buffer length is LUCENE_DEFAULT_TOKEN_BUFFER_SIZE. + bufferLength = (occupiedLength >= LUCENE_DEFAULT_TOKEN_BUFFER_SIZE + ? occupiedLength : LUCENE_DEFAULT_TOKEN_BUFFER_SIZE); + + //Allocate a buffer of length bufferLength + buffer = _CL_NEWARRAY(TCHAR,bufferLength); + bufferOwner = true; + //Copy the string value into buffer + _tcsncpy(buffer, value, occupiedLength); + //Assert that the buffer has been terminated at the end of the string + CND_PRECONDITION (buffer[len] == '\0', "Buffer was not correctly terminated"); + } + + StringBuffer::~StringBuffer() { + // Func - Destructor + // Pre - true + // Post - Instanc has been destroyed + + if( bufferOwner ){ + _CLDELETE_CARRAY(buffer); + }else + buffer = NULL; + } + void StringBuffer::clear(){ + //Func - Clears the Stringbuffer and resets it to it default empty state + //Pre - true + //Post - pre(buffer) has been destroyed and a new one has been allocated + + //Destroy the current buffer if present + _CLDELETE_CARRAY(buffer); + + //Initialize + len = 0; + bufferLength = LUCENE_DEFAULT_TOKEN_BUFFER_SIZE; + //Allocate a buffer of length bufferLength + buffer = _CL_NEWARRAY(TCHAR,bufferLength); + } + + void StringBuffer::appendChar(const TCHAR character) { + //Func - Appends a single character + //Pre - true + //Post - The character has been appended to the string in the buffer + + //Check if the current buffer length is sufficient to have the string value appended + if (len + 1 > bufferLength){ + //Have the size of the current string buffer increased because it is too small + growBuffer(len + 1); + } + //Put character at position len which is the end of the string in the buffer + //Note that this action might overwrite the terminator of the string '\0', which + //is kind of tricky + buffer[len] = character; + //Increase the len by to represent the correct length of the string in the buffer + len++; + } + + void StringBuffer::append(const TCHAR* value) { + //Func - Appends a copy of the string value + //Pre - value != NULL + //Post - value has been copied and appended to the string in buffer + + append(value, _tcslen(value)); + } + void StringBuffer::append(const TCHAR* value, size_t appendedLength) { + //Func - Appends a copy of the string value + //Pre - value != NULL + // appendedLength contains the length of the string value which is to be appended + //Post - value has been copied and appended to the string in buffer + + //Check if the current buffer length is sufficient to have the string value appended + if (len + appendedLength + 1 > bufferLength){ + //Have the size of the current string buffer increased because it is too small + growBuffer(len + appendedLength + 1); + } + + //Copy the string value into the buffer at postion len + _tcsncpy(buffer + len, value, appendedLength); + + //Add the length of the copied string to len to reflect the new length of the string in + //the buffer (Note: len is not the bufferlength!) + len += appendedLength; + } + + void StringBuffer::appendInt(const int32_t value) { + //Func - Appends an integer (after conversion to a character string) + //Pre - true + //Post - The converted integer value has been appended to the string in buffer + + //instantiate a buffer of 30 charactes for the conversion of the integer + TCHAR buf[30]; + //Convert the integer value to a string buf using the radix 10 (duh) + _i64tot(value, buf, 10); + //Have the converted integer now stored in buf appended to the string in buffer + append(buf); + } + + void StringBuffer::appendFloat(const qreal value, const int32_t digits){ + //Func - Appends a qreal (after conversion to a character string) + //Pre - digits > 0. Indicates the minimum number of characters printed + //Post - The converted qreal value has been appended to the string in buffer + + //using sprintf("%f" was not reliable on other plaforms... we use a custom float convertor + //bvk: also, using sprintf and %f seems excessivelly slow + if(digits>8) + _CLTHROWA(CL_ERR_IllegalArgument,"Too many digits..."); + + //the maximum number of characters that int64 will hold is 23. so we need 23*2+2 + TCHAR buf[48]; //the buffer to hold + int64_t v = (int64_t)value; //the integer value of the float + _i64tot(v,buf,10); //add the whole number + + size_t len = 99-_tcslen(buf); //how many digits we have to work with? + size_t dig = len< (size_t)digits ? len : digits; + if ( dig > 0 ){ + _tcscat(buf,_T(".")); //add a decimal point + + int64_t remi=(int64_t)((value-v)*pow((qreal)10,(qreal)(dig+1))); //take the remainder and make a whole number + if ( remi<0 ) remi*=-1; + int64_t remadj=remi/10; + if ( remi-(remadj*10) >=5 ) + remadj++; //adjust remainder + + // add as many zeros as necessary between the decimal point and the + // significant part of the number. Fixes a bug when trying to print + // numbers that have zeros right after the decimal point + if (remadj) { + int32_t numZeros = dig - (int32_t)log10((qreal)remadj) - 1; + while(numZeros-- > 0) + _tcscat(buf,_T("0")); //add a zero before the decimal point + } + + _i64tot(remadj,buf+_tcslen(buf),10); //add the remainder + } + + append(buf); + } + + void StringBuffer::prepend(const TCHAR* value){ + //Func - Puts a copy of the string value infront of the current string in the StringBuffer + //Pre - value != NULL + //Post - The string in pre(buffer) has been shifted n positions where n equals the length of value. + // The string value was then copied to the beginning of stringbuffer + + prepend(value, _tcslen(value)); + } + + void StringBuffer::prepend(const TCHAR* value, const size_t prependedLength) { + //Func - Puts a copy of the string value in front of the string in the StringBuffer + //Pre - value != NULL + // prependedLength contains the length of the string value which is to be prepended + //Post - A copy of the string value is has been in front of the string in buffer + //todo: something is wrong with this code, i'm sure... it only grows (and therefore moves if the buffer is to small) + //Check if the current buffer length is sufficient to have the string value prepended + if (prependedLength + len + 1 > bufferLength){ + //Have the size of the current string buffer increased because it is too small + //Because prependedLength is passed as the second argument to growBuffer, + //growBuffer will have left the first prependedLength characters empty + //when it recopied buffer during reallocation. + growBuffer(prependedLength + len + 1, prependedLength); + } + + //Copy the string value into the buffer at postion 0 + _tcsncpy(buffer, value, prependedLength); + //Add the length of the copied string to len to reflect the new length of the string in + //the buffer (Note: len is not the bufferlength!) + len += prependedLength; + } + + int32_t StringBuffer::length() const{ + //Func - Returns the length of the string in the StringBuffer + //Pre - true + //Post - The length len of the string in the buffer has been returned + + return len; + } + TCHAR* StringBuffer::toString(){ + //Func - Returns a copy of the current string in the StringBuffer sized equal to the length of the string + // in the StringBuffer. + //Pre - true + //Post - The copied string has been returned + + //Instantiate a buffer equal to the length len + 1 + TCHAR* ret = _CL_NEWARRAY(TCHAR,len + 1); + if (ret){ + //Copy the string in buffer + _tcsncpy(ret, buffer, len); + //terminate the string + ret[len] = '\0'; + } + //return the the copy + return ret; + } + TCHAR* StringBuffer::getBuffer() { + //Func - '\0' terminates the buffer and returns its pointer + //Pre - true + //Post - buffer has been '\0' terminated and returned + + // Check if the current buffer is '\0' terminated + if (len == bufferLength){ + //Make space for terminator, if necessary. + growBuffer(len + 1); + } + //'\0' buffer so it can be returned properly + buffer[len] = '\0'; + + return buffer; + } + + void StringBuffer::reserve(const int32_t size){ + if ( bufferLength >= size ) + return; + bufferLength = size; + + //Allocate a new buffer of length bufferLength + TCHAR* tmp = _CL_NEWARRAY(TCHAR,bufferLength); + _tcsncpy(tmp, buffer, len); + tmp[len] = '\0'; + + //destroy the old buffer + if (buffer){ + _CLDELETE_CARRAY(buffer); + } + //Assign the new buffer tmp to buffer + buffer = tmp; + } + + void StringBuffer::growBuffer(const int32_t minLength) { + //Func - Has the buffer grown to a minimum length of minLength or bigger + //Pre - minLength >= len + 1 + //Post - The buffer has been grown to a minimum length of minLength or bigger + + growBuffer(minLength, 0); + } + void StringBuffer::growBuffer(const int32_t minLength, const int32_t skippingNInitialChars) { + //Func - Has the buffer grown to a minimum length of minLength or bigger and shifts the + // current string in buffer by skippingNInitialChars forward + //Pre - After growth, must have at least enough room for contents + terminator so + // minLength >= skippingNInitialChars + len + 1 + // skippingNInitialChars >= 0 + //Post - The buffer has been grown to a minimum length of minLength or bigger and + // if skippingNInitialChars > 0, the contents of the buffer has beeen shifted + // forward by skippingNInitialChars positions as the buffer is reallocated, + // leaving the first skippingNInitialChars uninitialized (presumably to be + // filled immediately thereafter by the caller). + + CND_PRECONDITION (skippingNInitialChars >= 0, "skippingNInitialChars is less than zero"); + CND_PRECONDITION (minLength >= skippingNInitialChars + len + 1,"skippingNInitialChars is not large enough"); + + //More aggressive growth strategy to offset smaller default buffer size: + if ( !bufferOwner ){ + if ( bufferLength 0 ){ + printf("ERROR: stringaPool still contains intern'd strings (refcounts):\n"); + __strintrntype::iterator itr = stringaPool.begin(); + while ( itr != stringaPool.end() ){ + printf(" %s (%d)\n",(itr->first), (itr->second)); + ++itr; + } + } + + if ( stringPool.size() > 0 ){ + printf("ERROR: stringPool still contains intern'd strings (refcounts):\n"); + __wcsintrntype::iterator itr = stringPool.begin(); + while ( itr != stringPool.end() ){ + _tprintf(_T(" %s (%d)\n"),(itr->first), (itr->second)); + ++itr; + } + } + #endif + } + + const TCHAR* CLStringIntern::intern(const TCHAR* str CL_FILELINEPARAM){ + if ( str == NULL ) + return NULL; + if ( str[0] == 0 ) + return LUCENE_BLANK_STRING; + + SCOPED_LOCK_MUTEX(THIS_LOCK) + + __wcsintrntype::iterator itr = stringPool.find(str); + if ( itr==stringPool.end() ){ +#ifdef _UCS2 + TCHAR* ret = lucenewcsdup(str CL_FILELINEREF); +#else + TCHAR* ret = lucenestrdup(str CL_FILELINEREF); +#endif + stringPool[ret]= 1; + return ret; + }else{ + (itr->second)++; + return itr->first; + } + } + + bool CLStringIntern::unintern(const TCHAR* str){ + if ( str == NULL ) + return false; + if ( str[0] == 0 ) + return false; + + SCOPED_LOCK_MUTEX(THIS_LOCK) + + __wcsintrntype::iterator itr = stringPool.find(str); + if ( itr != stringPool.end() ){ + if ( (itr->second) == 1 ){ + stringPool.removeitr(itr); + return true; + }else + (itr->second)--; + } + return false; + } + + const char* CLStringIntern::internA(const char* str CL_FILELINEPARAM){ + if ( str == NULL ) + return NULL; + if ( str[0] == 0 ) + return _LUCENE_BLANK_ASTRING; + + SCOPED_LOCK_MUTEX(THIS_LOCK) + + __strintrntype::iterator itr = stringaPool.find(str); + if ( itr==stringaPool.end() ){ + char* ret = lucenestrdup(str CL_FILELINE); + stringaPool[ret] = 1; + return ret; + }else{ + (itr->second)++; + return itr->first; + } + } + + bool CLStringIntern::uninternA(const char* str){ + if ( str == NULL ) + return false; + if ( str[0] == 0 ) + return false; + + SCOPED_LOCK_MUTEX(THIS_LOCK) + + __strintrntype::iterator itr = stringaPool.find(str); + if ( itr!=stringaPool.end() ){ + if ( (itr->second) == 1 ){ + stringaPool.removeitr(itr); + return true; + }else + (itr->second)--; + } + return false; + } + + /* removed because of multi-threading problems... + __wcsintrntype::iterator CLStringIntern::internitr(const TCHAR* str CL_FILELINEPARAM){ + if ( str[0] == 0 ){ + if ( !blanksinitd ){ + CLStringIntern::stringPool.put(LUCENE_BLANK_STRING,1); + wblank=stringPool.find(str); + blanksinitd=true; + } + return wblank; + } + __wcsintrntype::iterator itr = stringPool.find(str); + if (itr==stringPool.end()){ +#ifdef _UCS2 + TCHAR* ret = lucenewcsdup(str CL_FILELINEREF); +#else + TCHAR* ret = lucenestrdup(str CL_FILELINEREF); +#endif + stringPool.put(ret,1); + return stringPool.find(str); + }else{ + (itr->second)++; + return itr; + } + } + bool CLStringIntern::uninternitr(__wcsintrntype::iterator itr){ + if ( itr!=stringPool.end() ){ + if ( itr==wblank ) + return false; + if ( (itr->second) == 1 ){ + stringPool.removeitr(itr); + return true; + }else + (itr->second)--; + } + return false; + } +*/ + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/util/StringIntern.h b/3rdparty/clucene/src/CLucene/util/StringIntern.h new file mode 100644 index 000000000..ded060c64 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/StringIntern.h @@ -0,0 +1,61 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_util_StringIntern_H +#define _lucene_util_StringIntern_H + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "VoidMap.h" +CL_NS_DEF(util) +typedef CL_NS(util)::CLHashMap __wcsintrntype; +typedef CL_NS(util)::CLHashMap __strintrntype; + + /** Functions for intern'ing strings. This + * is a process of pooling strings thus using less memory, + * and furthermore allows intern'd strings to be directly + * compared: + * string1==string2, rather than _tcscmp(string1,string2) + */ + class CLStringIntern{ + static __wcsintrntype stringPool; + static __strintrntype stringaPool; + STATIC_DEFINE_MUTEX(THIS_LOCK) + public: + /** + * Internalise the specified string. + * \return Returns a pointer to the internalised string + */ + static const char* internA(const char* str CL_FILELINEPARAM); + /** + * Uninternalise the specified string. Decreases + * the reference count and frees the string if + * reference count is zero + * \returns true if string was destroyed, otherwise false + */ + static bool uninternA(const char* str); + + /** + * Internalise the specified string. + * \return Returns a pointer to the internalised string + */ + static const TCHAR* intern(const TCHAR* str CL_FILELINEPARAM); + + /** + * Uninternalise the specified string. Decreases + * the reference count and frees the string if + * reference count is zero + * \returns true if string was destroyed, otherwise false + */ + static bool unintern(const TCHAR* str); + + static void shutdown(); + }; + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/util/ThreadLocal.cpp b/3rdparty/clucene/src/CLucene/util/ThreadLocal.cpp new file mode 100644 index 000000000..a54c86916 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/ThreadLocal.cpp @@ -0,0 +1,55 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" +#include "CLucene/LuceneThreads.h" +#include "ThreadLocal.h" + +CL_NS_DEF(util) + +DEFINE_MUTEX(ThreadLocalBase::ThreadLocalBase_THIS_LOCK) + +ThreadLocalBase::ShutdownHooksType ThreadLocalBase::shutdownHooks(false); +ThreadLocalBase::ThreadLocalsType ThreadLocalBase::threadLocals(false,false); + +ThreadLocalBase::ThreadLocalBase(){ +} +ThreadLocalBase::~ThreadLocalBase(){ +} + +void ThreadLocalBase::UnregisterCurrentThread(){ + _LUCENE_THREADID_TYPE id = _LUCENE_CURRTHREADID; + SCOPED_LOCK_MUTEX(ThreadLocalBase_THIS_LOCK) + + ThreadLocalsType::iterator itr = threadLocals.lower_bound(id); + ThreadLocalsType::iterator end = threadLocals.upper_bound(id); + while ( itr != end ){ + itr->second->setNull(); + ++itr; + } +} +void ThreadLocalBase::shutdown(){ + SCOPED_LOCK_MUTEX(ThreadLocalBase_THIS_LOCK) + + ThreadLocalsType::iterator itr = threadLocals.begin(); + while ( itr != threadLocals.end() ){ + itr->second->setNull(); + ++itr; + } + + ShutdownHooksType::iterator itr2 = shutdownHooks.begin(); + while ( itr2 != shutdownHooks.end() ){ + ShutdownHook* hook = *itr2; + hook(false); + } +} +void ThreadLocalBase::registerShutdownHook(ShutdownHook* hook){ + SCOPED_LOCK_MUTEX(ThreadLocalBase_THIS_LOCK) + shutdownHooks.insert(hook); +} + + +CL_NS_END diff --git a/3rdparty/clucene/src/CLucene/util/ThreadLocal.h b/3rdparty/clucene/src/CLucene/util/ThreadLocal.h new file mode 100644 index 000000000..f67c76ca9 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/ThreadLocal.h @@ -0,0 +1,143 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +* +* Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +------------------------------------------------------------------------------*/ +#ifndef _lucene_util_ThreadLocal_H +#define _lucene_util_ThreadLocal_H + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "CLucene/util/VoidMap.h" + +CL_NS_DEF(util) + +class ThreadLocalBase: LUCENE_BASE{ +public: + /** + * A hook called when CLucene is starting or shutting down, + * this can be used for setting up and tearing down static + * variables + */ + typedef void ShutdownHook(bool startup); + +protected: + STATIC_DEFINE_MUTEX(ThreadLocalBase_THIS_LOCK) + typedef CL_NS(util)::CLMultiMap<_LUCENE_THREADID_TYPE, ThreadLocalBase*, + CL_NS(util)::CLuceneThreadIdCompare, + CL_NS(util)::Deletor::ConstNullVal<_LUCENE_THREADID_TYPE>, + CL_NS(util)::Deletor::ConstNullVal > ThreadLocalsType; + static ThreadLocalsType threadLocals; + //todo: using http://en.wikipedia.org/wiki/Thread-local_storage#Pthreads_implementation + //would work better... but lots of testing would be needed first... + typedef CL_NS(util)::CLSetList, + CL_NS(util)::Deletor::ConstNullVal > ShutdownHooksType; + static ShutdownHooksType shutdownHooks; + + ThreadLocalBase(); +public: + virtual ~ThreadLocalBase(); + + /** + * Call this function to clear the local thread data for this + * ThreadLocal. Calling set(NULL) does the same thing, except + * this function is virtual and can be called without knowing + * the template. + */ + virtual void setNull() = 0; + + /** + * If you want to clean up thread specific memory, then you should + * make sure this thread is called when the thread is not going to be used + * again. This will clean up threadlocal data which can contain quite a lot + * of data, so if you are creating lots of new threads, then it is a good idea + * to use this function, otherwise there will be many memory leaks. + */ + static void UnregisterCurrentThread(); + + /** + * Call this function to shutdown CLucene + */ + static void shutdown(); + + /** + * Add this function to the shutdown hook list. This function will be called + * when CLucene is shutdown. + */ + static void registerShutdownHook(ShutdownHook* hook); +}; + +template +class ThreadLocal: public ThreadLocalBase{ + typedef CL_NS(util)::CLSet<_LUCENE_THREADID_TYPE, T, + CL_NS(util)::CLuceneThreadIdCompare, + CL_NS(util)::Deletor::ConstNullVal<_LUCENE_THREADID_TYPE>, + _deletor > LocalsType; + LocalsType locals; + DEFINE_MUTEX(locals_LOCK) +public: + ThreadLocal(); + ~ThreadLocal(); + T get(); + void setNull(); + void set(T t); +}; + +template +ThreadLocal::ThreadLocal(): + locals(false,true) +{ + //add this object to the base's list of threadlocals to be + //notified in case of UnregisterThread() + _LUCENE_THREADID_TYPE id = _LUCENE_CURRTHREADID; + SCOPED_LOCK_MUTEX(ThreadLocalBase_THIS_LOCK) + threadLocals.insert( CL_NS_STD(pair)(id, this) ); +} + +template +ThreadLocal::~ThreadLocal(){ + //remove this object to the base's list of threadlocals + _LUCENE_THREADID_TYPE id = _LUCENE_CURRTHREADID; + SCOPED_LOCK_MUTEX(ThreadLocalBase_THIS_LOCK) + + //remove all the thread local data for this object + locals.clear(); + + //remove this object from the ThreadLocalBase threadLocal list + ThreadLocalsType::iterator itr = threadLocals.lower_bound(id); + ThreadLocalsType::iterator end = threadLocals.upper_bound(id); + while ( itr != end ){ + if ( itr->second == this){ + threadLocals.erase(itr); + break; + } + ++itr; + } +} + +template +T ThreadLocal::get(){ + return locals.get(_LUCENE_CURRTHREADID); +} + +template +void ThreadLocal::setNull(){ + set(NULL); +} + +template +void ThreadLocal::set(T t){ + _LUCENE_THREADID_TYPE id = _LUCENE_CURRTHREADID; + locals.remove(id); + if ( t != NULL ) + locals.insert( CL_NS_STD(pair)(id, t) ); +} + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/util/VoidList.h b/3rdparty/clucene/src/CLucene/util/VoidList.h new file mode 100644 index 000000000..cd6908876 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/VoidList.h @@ -0,0 +1,175 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_util_VoidList_ +#define _lucene_util_VoidList_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#include "Equators.h" + +CL_NS_DEF(util) + +/** +* A template to encapsulate various list type classes +* @internal +*/ +template +class __CLList:public _base,LUCENE_BASE { +private: + bool dv; + typedef _base base; +public: + DEFINE_MUTEX(THIS_LOCK) + + typedef typename _base::const_iterator const_iterator; + typedef typename _base::iterator iterator; + + virtual ~__CLList(){ + clear(); + } + + __CLList ( const bool deleteValue ): + dv(deleteValue) + { + } + + void setDoDelete(bool val){ dv=val; } + + //sets array to the contents of this array. + //array must be size+1, otherwise memory may be overwritten + void toArray(_kt* into) const{ + int i=0; + for ( const_iterator itr=base::begin();itr!=base::end();itr++ ){ + into[i] = *itr; + i++; + } + into[i] = NULL; + } + + void set(int32_t i, _kt val) { + if ( dv ) + _valueDeletor::doDelete((*this)[i]); + (*this)[i] = val; + } + + //todo: check this + void delete_back(){ + if ( base::size() > 0 ){ + iterator itr = base::end(); + if ( itr != base::begin()) + itr --; + _kt key = *itr; + base::erase(itr); + if ( dv ) + _valueDeletor::doDelete(key); + } + } + + void delete_front(){ + if ( base::size() > 0 ){ + iterator itr = base::begin(); + _kt key = *itr; + base::erase(itr); + if ( dv ) + _valueDeletor::doDelete(key); + } + } + + void clear(){ + if ( dv ){ + iterator itr = base::begin(); + while ( itr != base::end() ){ + _valueDeletor::doDelete(*itr); + ++itr; + } + } + base::clear(); + } + + void remove(int32_t i, bool dontDelete=false){ + iterator itr=base::begin(); + itr+=i; + _kt key = *itr; + base::erase( itr ); + if ( dv && !dontDelete ) + _valueDeletor::doDelete(key); + } + void remove(iterator itr, bool dontDelete=false){ + _kt key = *itr; + base::erase( itr ); + if ( dv && !dontDelete ) + _valueDeletor::doDelete(key); + } + +}; + +//growable arrays of Objects (like a collection or list) +//a list, so can contain duplicates +//it grows in chunks... todo: check jlucene for initial size of array, and growfactors +template +class CLVector:public __CLList<_kt, CL_NS_STD(vector)<_kt> , _valueDeletor> +{ +public: + CLVector ( const bool deleteValue=true ): + __CLList<_kt, CL_NS_STD(vector)<_kt> , _valueDeletor>(deleteValue) + { + } +}; + +//An array-backed implementation of the List interface +//a list, so can contain duplicates +//*** a very simple list - use +//(This class is roughly equivalent to Vector, except that it is unsynchronized.) +#define CLArrayList CLVector +#define CLHashSet CLHashList + +//implementation of the List interface, provides access to the first and last list elements in O(1) +//no comparator is required... and so can contain duplicates +//a simple list with no comparator +//*** a very simple list - use +#ifdef LUCENE_DISABLE_HASHING + #define CLHashList CLSetList +#else + +template +class CLHashList:public __CLList<_kt, CL_NS_HASHING(hash_set)<_kt,_Comparator> , _valueDeletor> +{ +public: + CLHashList ( const bool deleteValue=true ): + __CLList<_kt, CL_NS_HASHING(hash_set)<_kt,_Comparator> , _valueDeletor>(deleteValue) + { + } +}; +#endif + +template +class CLLinkedList:public __CLList<_kt, CL_NS_STD(list)<_kt> , _valueDeletor> +{ +public: + CLLinkedList ( const bool deleteValue=true ): + __CLList<_kt, CL_NS_STD(list)<_kt> , _valueDeletor>(deleteValue) + { + } +}; +template +class CLSetList:public __CLList<_kt, CL_NS_STD(set)<_kt,_Comparator> , _valueDeletor> +{ +public: + CLSetList ( const bool deleteValue=true ): + __CLList<_kt, CL_NS_STD(set)<_kt,_Comparator> , _valueDeletor>(deleteValue) + { + } +}; + +CL_NS_END +#endif diff --git a/3rdparty/clucene/src/CLucene/util/VoidMap.h b/3rdparty/clucene/src/CLucene/util/VoidMap.h new file mode 100644 index 000000000..b22b507e9 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/VoidMap.h @@ -0,0 +1,270 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef _lucene_util_VoidMap_ +#define _lucene_util_VoidMap_ + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + + +CL_NS_DEF(util) + +/** +* A template to encapsulate various map type classes +* @internal +*/ +template +class __CLMap:public _base,LUCENE_BASE { +private: + bool dk; + bool dv; + typedef _base base; +public: + DEFINE_MUTEX(THIS_LOCK) + + typedef typename _base::iterator iterator; + typedef typename _base::const_iterator const_iterator; + typedef CL_NS_STD(pair)<_kt, _vt> _pair; + + ///Default constructor for the __CLMap + __CLMap (): + dk(true), + dv(true) + { + } + + ///Deconstructor for the __CLMap + ~__CLMap (){ + clear(); + } + + void setDeleteKey(bool val){ dk = val; } + void setDeleteValue(bool val){ dv = val; } + + ///Construct the VoidMap and set the deleteTypes to the specified values + ///\param deleteKey if true then the key variable is deleted when an object is deleted + ///\param keyDelType delete the key variable using the specified type + ///\param deleteValue if true then the value variable is deleted when an object is deleted + ///\param valueDelType delete the value variable using the specified type + /*__CLMap ( const bool deleteKey, const bool deleteValue ): + dk(deleteKey), + dv(deleteValue) + { + }*/ + + ///checks to see if the specified key exists + ///\param k the key to check for + ///\returns true if the key exists + bool exists(_kt k)const{ + const_iterator itr = base::find(k); + bool ret = itr!=base::end(); + return ret; + } + + ///put the specified pair into the map. remove any old items first + ///\param k the key + ///\param v the value + void put(_kt k,_vt v){ + //todo: check if this is always right! + //must should look through code, for + //cases where map is not unique!!! + if ( dk || dv ) + remove(k); + + //todo: replacing the old item might be quicker... + + base::insert(_pair(k,v)); + } + + + ///using a non-const key, get a non-const value + _vt get( _kt k) const { + const_iterator itr = base::find(k); + if ( itr==base::end() ) + return _vt(); + else + return itr->second; + } + ///using a non-const key, get the actual key + _kt getKey( _kt k) const { + const_iterator itr = base::find(k); + if ( itr==base::end() ) + return _kt(); + else + return itr->first; + } + + void removeitr (iterator itr, const bool dontDeleteKey = false, const bool dontDeleteValue = false){ + //delete key&val first. This prevents potential loops (deleting object removes itself) + _kt key = itr->first; + _vt val = itr->second; + base::erase(itr); + + //keys & vals need to be deleted after erase, because the hashvalue is still needed + if ( dk && !dontDeleteKey ) + _KeyDeletor::doDelete(key); + if ( dv && !dontDeleteValue ) + _ValueDeletor::doDelete(val); + } + ///delete and optionally delete the specified key and associated value + void remove(_kt key, const bool dontDeleteKey = false, const bool dontDeleteValue = false){ + iterator itr = base::find(key); + if ( itr!=base::end() ) + removeitr(itr,dontDeleteKey,dontDeleteValue); + } + + ///clear all keys and values in the map + void clear(){ + if ( dk || dv ){ + iterator itr = base::begin(); + while ( itr!=base::end() ){ + #ifdef _CL_HAVE_EXT_HASH_MAP + removeitr(itr); + itr = base::begin(); + + #else + if ( dk ) + _KeyDeletor::doDelete(itr->first); + if ( dv ) + _ValueDeletor::doDelete(itr->second); + ++itr; + + #endif + } + } + base::clear(); + } +}; + +// makes no guarantees as to the order of the map +// cannot contain duplicate keys; each key can map to at most one value +#define CLHashtable CLHashMap + +#if defined(_CL_HAVE_GOOGLE_DENSE_HASH_MAP) +//do nothing +#elif defined(LUCENE_DISABLE_HASHING) + + //a CLSet with CLHashMap traits +template +class CLHashMap:public __CLMap<_kt,_vt, + CL_NS_STD(map)<_kt,_vt, _Compare>, + _KeyDeletor,_ValueDeletor> +{ + typedef typename CL_NS_STD(map)<_kt,_vt,_Compare> _base; + typedef __CLMap<_kt, _vt, CL_NS_STD(map)<_kt,_vt, _Compare>, + _KeyDeletor,_ValueDeletor> _this; +public: + CLHashMap ( const bool deleteKey=false, const bool deleteValue=false ) + { + _this::setDeleteKey(deleteKey); + _this::setDeleteValue(deleteValue); + } +}; +#elif defined(_CL_HAVE_EXT_HASH_MAP) + //ext/hash_map syntax +//HashMap class is roughly equivalent to Hashtable, except that it is unsynchronized +template +class CLHashMap:public __CLMap<_kt,_vt, + CL_NS_HASHING(hash_map)<_kt,_vt, _Hasher,_Equals>, + _KeyDeletor,_ValueDeletor> +{ + typedef __CLMap<_kt,_vt, CL_NS_HASHING(hash_map)<_kt,_vt, _Hasher,_Equals>, + _KeyDeletor,_ValueDeletor> _this; +public: + CLHashMap ( const bool deleteKey=false, const bool deleteValue=false ) + { + _this::setDeleteKey(deleteKey); + _this::setDeleteValue(deleteValue); + } +}; + +#else +//HashMap class is roughly equivalent to Hashtable, except that it is unsynchronized +template +class CLHashMap:public __CLMap<_kt,_vt, + CL_NS_HASHING(hash_map)<_kt,_vt, _Hasher>, + _KeyDeletor,_ValueDeletor> +{ + typedef __CLMap<_kt,_vt, CL_NS_HASHING(hash_map)<_kt,_vt, _Hasher>, + _KeyDeletor,_ValueDeletor> _this; +public: + CLHashMap ( const bool deleteKey=false, const bool deleteValue=false ) + { + _this::setDeleteKey(deleteKey); + _this::setDeleteValue(deleteValue); + } +}; +#endif + +//A collection that contains no duplicates +//does not guarantee that the order will remain constant over time +template +class CLSet:public __CLMap<_kt,_vt, + CL_NS_STD(map)<_kt,_vt, _Compare>, + _KeyDeletor,_ValueDeletor> +{ + typedef typename CL_NS_STD(map)<_kt,_vt,_Compare> _base; + typedef __CLMap<_kt, _vt, CL_NS_STD(map)<_kt,_vt, _Compare>, + _KeyDeletor,_ValueDeletor> _this; +public: + CLSet ( const bool deleteKey=false, const bool deleteValue=false ) + { + _this::setDeleteKey(deleteKey); + _this::setDeleteValue(deleteValue); + } +}; + + +//A collection that can contains duplicates +template +class CLMultiMap:public __CLMap<_kt,_vt, + CL_NS_STD(multimap)<_kt,_vt>, + _KeyDeletor,_ValueDeletor> +{ + typedef typename CL_NS_STD(multimap)<_kt,_vt> _base; + typedef __CLMap<_kt, _vt, CL_NS_STD(multimap)<_kt,_vt>, + _KeyDeletor,_ValueDeletor> _this; +public: + CLMultiMap ( const bool deleteKey=false, const bool deleteValue=false ) + { + _this::setDeleteKey(deleteKey); + _this::setDeleteValue(deleteValue); + } +}; + + +//*** need to create a class that allows duplicates - use +//#define CLSet __CLMap +CL_NS_END + +#ifdef _CL_HAVE_GOOGLE_DENSE_HASH_MAP +#include "GoogleSparseMap.h" +#endif + +#endif diff --git a/3rdparty/clucene/src/CLucene/util/bufferedstream.h b/3rdparty/clucene/src/CLucene/util/bufferedstream.h new file mode 100644 index 000000000..d905955b1 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/bufferedstream.h @@ -0,0 +1,157 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Jos van den Oever +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +/* This file is part of Strigi Desktop Search + * + * Copyright (C) 2006 Jos van den Oever + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef BUFFEREDSTREAM_H +#define BUFFEREDSTREAM_H + +#include "streambase.h" +#include "inputstreambuffer.h" + +#include +#include + +namespace jstreams { + +template +class BufferedInputStream : public StreamBase { +private: + bool finishedWritingToBuffer; + InputStreamBuffer buffer; + + void writeToBuffer(int32_t minsize); + int32_t read_(const T*& start, int32_t min, int32_t max); +protected: + /** + * This function must be implemented by the subclasses. + * It should write a maximum of @p space characters at the buffer + * position pointed to by @p start. If no more data is available due to + * end of file, -1 should be returned. If an error occurs, the status + * should be set to Error, an error message should be set and the function + * must return -1. + **/ + virtual int32_t fillBuffer(T* start, int32_t space) = 0; + // this function might be useful if you want to reuse a bufferedstream + void resetBuffer() {printf("implement 'resetBuffer'\n");} + BufferedInputStream(); +public: + int32_t read(const T*& start, int32_t min, int32_t max); + int64_t reset(int64_t); + virtual int64_t skip(int64_t ntoskip); +}; + +template +BufferedInputStream::BufferedInputStream() { + finishedWritingToBuffer = false; +} + +template +void +BufferedInputStream::writeToBuffer(int32_t ntoread) { + int32_t missing = ntoread - buffer.avail; + int32_t nwritten = 0; + while (missing > 0 && nwritten >= 0) { + int32_t space; + space = buffer.makeSpace(missing); + T* start = buffer.readPos + buffer.avail; + nwritten = fillBuffer(start, space); + assert(StreamBase::status != Eof); + if (nwritten > 0) { + buffer.avail += nwritten; + missing = ntoread - buffer.avail; + } + } + if (nwritten < 0) { + finishedWritingToBuffer = true; + } +} +template +int32_t +BufferedInputStream::read(const T*& start, int32_t min, int32_t max) { + if (StreamBase::status == Error) return -2; + if (StreamBase::status == Eof) return -1; + + // do we need to read data into the buffer? + if (!finishedWritingToBuffer && min > buffer.avail) { + // do we have enough space in the buffer? + writeToBuffer(min); + if (StreamBase::status == Error) return -2; + } + + int32_t nread = buffer.read(start, max); + + BufferedInputStream::position += nread; + if (BufferedInputStream::position > BufferedInputStream::size + && BufferedInputStream::size > 0) { + // error: we read more than was specified in size + // this is an error because all dependent code might have been labouring + // under a misapprehension + BufferedInputStream::status = Error; + BufferedInputStream::error = "Stream is longer than specified."; + nread = -2; + } else if (BufferedInputStream::status == Ok && buffer.avail == 0 + && finishedWritingToBuffer) { + BufferedInputStream::status = Eof; + if (BufferedInputStream::size == -1) { + BufferedInputStream::size = BufferedInputStream::position; + } + // save one call to read() by already returning -1 if no data is there + if (nread == 0) nread = -1; + } + return nread; +} +template +int64_t +BufferedInputStream::reset(int64_t newpos) { + if (StreamBase::status == Error) return -2; + // check to see if we have this position + int64_t d = BufferedInputStream::position - newpos; + if (buffer.readPos - d >= buffer.start && -d < buffer.avail) { + BufferedInputStream::position -= d; + buffer.avail += (int32_t)d; + buffer.readPos -= d; + StreamBase::status = Ok; + } + return StreamBase::position; +} +template +int64_t +BufferedInputStream::skip(int64_t ntoskip) { + const T *begin; + int32_t nread; + int64_t skipped = 0; + while (ntoskip) { + int32_t step = (int32_t)((ntoskip > buffer.size) ?buffer.size :ntoskip); + nread = read(begin, 1, step); + if (nread <= 0) { + return skipped; + } + ntoskip -= nread; + skipped += nread; + } + return skipped; +} +} + +#endif diff --git a/3rdparty/clucene/src/CLucene/util/dirent.cpp b/3rdparty/clucene/src/CLucene/util/dirent.cpp new file mode 100644 index 000000000..3c5c54200 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/dirent.cpp @@ -0,0 +1,221 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Matt J. Weinstein +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#include "CLucene/StdHeader.h" + +#if !defined(_CL_HAVE_DIRENT_H) && !defined(_CL_HAVE_SYS_NDIR_H) && !defined(_CL_HAVE_SYS_DIR_H) && !defined(_CL_HAVE_NDIR_H) +#include "dirent.h" + +DIR * +opendir (const char *szPath) +{ + DIR *nd; + char szFullPath[CL_MAX_PATH]; + + errno = 0; + + if (!szPath) + { + errno = EFAULT; + return NULL; + } + + if (szPath[0] == '\0') + { + errno = ENOTDIR; + return NULL; + } + + /* Attempt to determine if the given path really is a directory. */ + struct _stat rcs; + if ( _stat(szPath,&rcs) == -1) + { + /* call GetLastError for more error info */ + errno = ENOENT; + return NULL; + } + if (!(rcs.st_mode & _S_IFDIR)) + { + /* Error, entry exists but not a directory. */ + errno = ENOTDIR; + return NULL; + } + + /* Make an absolute pathname. */ + _realpath(szPath,szFullPath); + + /* Allocate enough space to store DIR structure and the complete + * directory path given. */ + //nd = (DIR *) malloc (sizeof (DIR) + _tcslen (szFullPath) + _tcslen (DIRENT_SLASH) + + // _tcslen (DIRENT_SEARCH_SUFFIX)+1); + nd = new DIR; + + if (!nd) + { + /* Error, out of memory. */ + errno = ENOMEM; + return NULL; + } + + /* Create the search expression. */ + strcpy (nd->dd_name, szFullPath); + + /* Add on a slash if the path does not end with one. */ + if (nd->dd_name[0] != '\0' && + nd->dd_name[strlen (nd->dd_name) - 1] != '/' && + nd->dd_name[strlen (nd->dd_name) - 1] != '\\') + { + strcat (nd->dd_name, DIRENT_SLASH); + } + + /* Add on the search pattern */ + strcat (nd->dd_name, DIRENT_SEARCH_SUFFIX); + + /* Initialize handle to -1 so that a premature closedir doesn't try + * to call _findclose on it. */ + nd->dd_handle = -1; + + /* Initialize the status. */ + nd->dd_stat = 0; + + /* Initialize the dirent structure. ino and reclen are invalid under + * Win32, and name simply points at the appropriate part of the + * findfirst_t structure. */ + //nd->dd_dir.d_ino = 0; + //nd->dd_dir.d_reclen = 0; + nd->dd_dir.d_namlen = 0; + nd->dd_dir.d_name = nd->dd_dta.name; + + return nd; +} + + +struct dirent * readdir (DIR * dirp) +{ + errno = 0; + + /* Check for valid DIR struct. */ + if (!dirp) + { + errno = EFAULT; + return NULL; + } + + if (dirp->dd_dir.d_name != dirp->dd_dta.name) + { + /* The structure does not seem to be set up correctly. */ + errno = EINVAL; + return NULL; + } + + bool bCallFindNext = true; + + if (dirp->dd_stat < 0) + { + /* We have already returned all files in the directory + * (or the structure has an invalid dd_stat). */ + return NULL; + } + else if (dirp->dd_stat == 0) + { + /* We haven't started the search yet. */ + /* Start the search */ + dirp->dd_handle = _findfirst (dirp->dd_name, &(dirp->dd_dta)); + + if (dirp->dd_handle == -1) + { + /* Whoops! Seems there are no files in that + * directory. */ + dirp->dd_stat = -1; + } + else + { + dirp->dd_stat = 1; + } + + /* Dont call _findnext first time. */ + bCallFindNext = false; + } + + while (dirp->dd_stat > 0) + { + if (bCallFindNext) + { + /* Get the next search entry. */ + if (_findnext (dirp->dd_handle, &(dirp->dd_dta))) + { + /* We are off the end or otherwise error. */ + _findclose (dirp->dd_handle); + dirp->dd_handle = -1; + dirp->dd_stat = -1; + return NULL; + } + else + { + /* Update the status to indicate the correct + * number. */ + dirp->dd_stat++; + } + } + + /* Successfully got an entry. Everything about the file is + * already appropriately filled in except the length of the + * file name. */ + dirp->dd_dir.d_namlen = strlen (dirp->dd_dir.d_name); + + bool bThisFolderOrUpFolder = dirp->dd_dir.d_name[0] == '.' && + (dirp->dd_dir.d_name[1] == 0 || (dirp->dd_dir.d_name[1] == '.' && dirp->dd_dir.d_name[2] == 0)); + + if (!bThisFolderOrUpFolder) + { + struct _stat buf; + char buffer[CL_MAX_DIR]; + size_t bl = strlen(dirp->dd_name)-strlen(DIRENT_SEARCH_SUFFIX); + strncpy(buffer,dirp->dd_name,bl); + buffer[bl]=0; + strcat(buffer, dirp->dd_dir.d_name); + if ( _stat(buffer,&buf) == 0 ) + { + /* Finally we have a valid entry. */ + return &dirp->dd_dir; + } + } + + /* Allow to find next file. */ + bCallFindNext = true; + } + + return NULL; +} + + + +int32_t +closedir (DIR * dirp) +{ + int32_t rc; + + errno = 0; + rc = 0; + + if (!dirp) + { + errno = EFAULT; + return -1; + } + + if (dirp->dd_handle != -1) + { + rc = _findclose (dirp->dd_handle); + } + + /* Delete the dir structure. */ + _CLVDELETE(dirp); + + return rc; +} +#endif //HAVE_DIRENT_H + diff --git a/3rdparty/clucene/src/CLucene/util/dirent.h b/3rdparty/clucene/src/CLucene/util/dirent.h new file mode 100644 index 000000000..71cd34c0a --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/dirent.h @@ -0,0 +1,105 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Matt J. Weinstein +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +#ifndef lucene_util_dirent_H +#define lucene_util_dirent_H + +#if defined(_LUCENE_PRAGMA_ONCE) +# pragma once +#endif + +#if !defined(_CL_HAVE_DIRENT_H) && !defined(_CL_HAVE_SYS_NDIR_H) && !defined(_CL_HAVE_SYS_DIR_H) && !defined(_CL_HAVE_NDIR_H) + +/** +\unit + * dirent.c + * + * Derived from DIRLIB.C by Matt J. Weinstein + * This note appears in the DIRLIB.H + * DIRLIB.H by M. J. Weinstein Released to public domain 1-Jan-89 + * + * Updated by Jeremy Bettis + * Significantly revised and rewinddir, seekdir and telldir added by Colin + * Cut down again & changed by Ben van Klinken + * Peters + * + */ + +/** dirent structure - used by the dirent.h directory iteration functions */ +struct dirent +{ + unsigned short d_namlen; /* Length of name in d_name. */ + char *d_name; /* File name. */ +}; + +/** DIR structure - used by the dirent.h directory iteration functions*/ +struct DIR +{ + /** disk transfer area for this dir */ + struct _finddata_t dd_dta; + + /* dirent struct to return from dir (NOTE: this makes this thread + * safe as long as only one thread uses a particular DIR struct at + * a time) */ + struct dirent dd_dir; + + /** _findnext handle */ + intptr_t dd_handle; + + /** + * Status of search: + * 0 = not started yet (next entry to read is first entry) + * -1 = off the end + * positive = 0 based index of next entry + */ + int32_t dd_stat; + + /** given path for dir with search pattern (struct is extended) */ + char dd_name[CL_MAX_DIR]; + +}; + +#define DIRENT_SEARCH_SUFFIX "*" +#define DIRENT_SLASH PATH_DELIMITERA + + +/** +* Returns a pointer to a DIR structure appropriately filled in to begin +* searching a directory. +*/ +DIR* opendir (const char* filespec); + +/** +* Return a pointer to a dirent structure filled with the information on the +* next entry in the directory. +*/ +struct dirent* readdir (DIR* dir); + +/** +* Frees up resources allocated by opendir. +*/ +int32_t closedir (DIR* dir); + + +#elif defined (_CL_HAVE_DIRENT_H) +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) + +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# if defined(_CL_HAVE_SYS_NDIR_H) +# include +# endif +# if defined(_CL_HHAVE_SYS_DIR_H) +# include +# endif +# if defined(_CL_HHAVE_NDIR_H) +# include +# endif + +#endif //HAVE_DIRENT_H +#endif diff --git a/3rdparty/clucene/src/CLucene/util/fileinputstream.cpp b/3rdparty/clucene/src/CLucene/util/fileinputstream.cpp new file mode 100644 index 000000000..9125d8478 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/fileinputstream.cpp @@ -0,0 +1,103 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Jos van den Oever +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +/* This file is part of Strigi Desktop Search + * + * Copyright (C) 2006 Jos van den Oever + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include "jstreamsconfig.h" +#include "fileinputstream.h" + +#ifndef UNDER_CE +#include +#endif +#include +namespace jstreams { + +const int32_t FileInputStream::defaultBufferSize = 1048576; +FileInputStream::FileInputStream(const char *filepath, int32_t buffersize) { + // try to open the file for reading + file = fopen(filepath, "rb"); + this->filepath = filepath; + if (file == 0) { + // handle error + error = "Could not read file '"; + error += filepath; + error += "': "; +#ifndef UNDER_CE + error += strerror(errno); +#endif + status = Error; + return; + } + // determine file size. if the stream is not seekable, the size will be -1 + fseek(file, 0, SEEK_END); + size = ftell(file); + fseek(file, 0, SEEK_SET); + + // if the file has size 0, make sure that it's really empty + // this is useful for filesystems like /proc that report files as size 0 + // for files that do contain content + if (size == 0) { + char dummy[1]; + size_t n = fread(dummy, 1, 1, file); + if (n == 1) { + size = -1; + fseek(file, 0, SEEK_SET); + } else { + fclose(file); + file = 0; + return; + } + } + + // allocate memory in the buffer + int32_t bufsize = (size <= buffersize) ?size+1 :buffersize; + mark(bufsize); +} +FileInputStream::~FileInputStream() { + if (file) { + if (fclose(file)) { + // handle error + error = "Could not close file '" + filepath + "'."; + } + } +} +int32_t +FileInputStream::fillBuffer(char* start, int32_t space) { + if (file == 0) return -1; + // read into the buffer + int32_t nwritten = fread(start, 1, space, file); + // check the file stream status + if (ferror(file)) { + error = "Could not read from file '" + filepath + "'."; + fclose(file); + file = 0; + status = Error; + return -1; + } + if (feof(file)) { + fclose(file); + file = 0; + } + return nwritten; +} +} diff --git a/3rdparty/clucene/src/CLucene/util/fileinputstream.h b/3rdparty/clucene/src/CLucene/util/fileinputstream.h new file mode 100644 index 000000000..144423da8 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/fileinputstream.h @@ -0,0 +1,38 @@ +/** + * Copyright 2003-2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef FILEINPUTSTREAM_H +#define FILEINPUTSTREAM_H + +#include "bufferedstream.h" + +namespace jstreams { + +class FileInputStream : public BufferedInputStream { +private: + FILE *file; + std::string filepath; + +public: + static const int32_t defaultBufferSize; + FileInputStream(const char *filepath, int32_t buffersize=defaultBufferSize); + ~FileInputStream(); + int32_t fillBuffer(char* start, int32_t space); +}; + +} // end namespace jstreams + +#endif + diff --git a/3rdparty/clucene/src/CLucene/util/inputstreambuffer.h b/3rdparty/clucene/src/CLucene/util/inputstreambuffer.h new file mode 100644 index 000000000..873e811cd --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/inputstreambuffer.h @@ -0,0 +1,126 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Jos van den Oever +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +/* This file is part of Strigi Desktop Search + * + * Copyright (C) 2006 Jos van den Oever + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef INPUTSTREAMBUFFER_H +#define INPUTSTREAMBUFFER_H + +#include + +namespace jstreams { + +template +class InputStreamBuffer { +private: +public: + T* start; + int32_t size; + T* readPos; + int32_t avail; + + InputStreamBuffer(); + ~InputStreamBuffer(); + void setSize(int32_t size); + int32_t read(const T*& start, int32_t max=0); + + /** + * This function prepares the buffer for a new write. + * returns the number of available places. + **/ + int32_t makeSpace(int32_t needed); +}; + +template +InputStreamBuffer::InputStreamBuffer() { + readPos = start = 0; + size = avail = 0; +} +template +InputStreamBuffer::~InputStreamBuffer() { + free(start); +} +template +void +InputStreamBuffer::setSize(int32_t size) { + // store pointer information + int32_t offset = (int32_t)(readPos - start); + + // allocate memory in the buffer + if ( start == 0 ) + start = (T*)malloc(size*sizeof(T)); + else + start = (T*)realloc(start, size*sizeof(T)); + this->size = size; + + // restore pointer information + readPos = start + offset; +} +template +int32_t +InputStreamBuffer::makeSpace(int32_t needed) { + // determine how much space is available for writing + int32_t space = size - ((int32_t)(readPos - start)) - avail; + if (space >= needed) { + // there's enough space + return space; + } + + if (avail) { + if (readPos != start) { +// printf("moving\n"); + // move data to the start of the buffer + memmove(start, readPos, avail*sizeof(T)); + space += (int32_t)(readPos - start); + readPos = start; + } + } else { + // we may start writing at the start of the buffer + readPos = start; + space = size; + } + if (space >= needed) { + // there's enough space now + return space; + } + + // still not enough space, we have to allocate more +// printf("resize %i %i %i %i %i\n", avail, needed, space, size + needed - space, size); + setSize(size + needed - space); + return needed; +} +template +int32_t +InputStreamBuffer::read(const T*& start, int32_t max) { + start = readPos; + if (max <= 0 || max > avail) { + max = avail; + } + readPos += max; + avail -= max; + return max; +} + +} // end namespace jstreams + +#endif diff --git a/3rdparty/clucene/src/CLucene/util/jstreamsconfig.h b/3rdparty/clucene/src/CLucene/util/jstreamsconfig.h new file mode 100644 index 000000000..2a6ce9f8d --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/jstreamsconfig.h @@ -0,0 +1,9 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ + +//this is just a compatibility header for jstreams +#include "CLucene/StdHeader.h" diff --git a/3rdparty/clucene/src/CLucene/util/streambase.h b/3rdparty/clucene/src/CLucene/util/streambase.h new file mode 100644 index 000000000..b0d9dc167 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/streambase.h @@ -0,0 +1,148 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Jos van den Oever +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +* +* Changes are Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +------------------------------------------------------------------------------*/ +/* This file is part of Strigi Desktop Search + * + * Copyright (C) 2006 Jos van den Oever + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef STREAMBASE_H +#define STREAMBASE_H + +#include + +#if defined(_BUILD_FOR_QT_) + #include "StdHeader.h" +#endif + +#define INT32MAX 0x7FFFFFFFL + +namespace jstreams { + +enum StreamStatus { Ok, Eof, Error }; + +/** + * @short Base class for stream read access to many different file types. + * + * This class is based on the interface java.io.InputStream. It allows + * for uniform access to streamed resources. + * The main difference with the java equivalent is a performance improvement. + * When reading data, data is not copied into a buffer provided by the caller, + * but a pointer to the read data is provided. This makes this interface + * especially useful for deriving from it and implementing filterers or + * transformers. + */ +// java mapping: long=int64, int=int32, byte=uint8_t +template +class StreamBase { +protected: + int64_t size; + int64_t position; + std::string error; + StreamStatus status; +public: + StreamBase() :size(-1), position(0), status(Ok){ } + virtual ~StreamBase(){} + /** + * @brief Return a string representation of the last error. + * If no error has occurred, an empty string is returned. + **/ + const char* getError() const { return error.c_str(); } + StreamStatus getStatus() const { return status; } + /** + * @brief Get the current position in the stream. + * The value obtained from this function can be used to reset the stream. + **/ + int64_t getPosition() const { return position; } + /** + * @brief Return the size of the stream. + * If the size of the stream is unknown, -1 + * is returned. If the end of the stream has been reached the size is + * always known. + **/ + int64_t getSize() const { return size; } + /** + * @brief Reads characters from the stream and sets \a start to + * the first character that was read. + * + * If @p ntoread is @c 0, then at least one character will be read. + * + * @param start Pointer passed by reference that will be set to point to + * the retrieved array of characters. If the end of the stream + * is encountered or an error occurs, the value of @p start + * is undefined. + * @param min The number of characters to read from the stream. + * @param max The maximum number of characters to read from the stream. + * @return the number of characters that were read. If -1 is returned, the + * end of the stream has been reached. If -2 is returned, an error + * has occurred. + **/ + virtual int32_t read(const T*& start, int32_t min, int32_t max) = 0; + /** + * Skip @param ntoskip bytes. Unless an error occurs or the end of file is + * encountered, this amount of bytes is skipped. + * This function returns new position in the stream. + **/ + virtual int64_t skip(int64_t ntoskip); + /** + * @brief Repositions this stream to given requested position. + * Reset is guaranteed to work after a successful call to read(), + * when the new position is in the range of the data returned by read(). + * This means that @p pos must lie between than the position + * corresponding to the start parameter (x) of the read function + * and the position corresponding to the last position in the returned + * buffer (x + nread). + **/ + virtual int64_t reset(int64_t pos) = 0; + int64_t mark(int32_t readlimit) { + int64_t p = getPosition(); + const T* ptr; + read(ptr, readlimit, -1); + return reset(p); + } +}; +#define SKIPSTEP 1024 +template +int64_t +StreamBase::skip(int64_t ntoskip) { + const T *begin; + int32_t nread; + int64_t skipped = 0; + while (ntoskip) { + int32_t step = (int32_t)((ntoskip > SKIPSTEP) ?SKIPSTEP :ntoskip); + nread = read(begin, 1, step); + if (nread < -1 ) { + // an error occurred + return nread; + } else if (nread < 1) { + ntoskip = 0; + } else { + skipped += nread; + ntoskip -= nread; + } + } + return skipped; +} + +} // end namespace jstreams + +#endif diff --git a/3rdparty/clucene/src/CLucene/util/stringreader.h b/3rdparty/clucene/src/CLucene/util/stringreader.h new file mode 100644 index 000000000..698d07e37 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/stringreader.h @@ -0,0 +1,124 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Jos van den Oever +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +/* This file is part of Strigi Desktop Search + * + * Copyright (C) 2006 Jos van den Oever + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef STRINGREADER_H +#define STRINGREADER_H + +/** + * Author: Jos van den Oever + * Ben van Klinken + **/ + + +#include "streambase.h" + +namespace jstreams { + +template +class StringReader : public StreamBase { +private: + int64_t markpt; + T* data; + bool dataowner; + StringReader(const StringReader&); + void operator=(const StringReader&); +public: + StringReader(const T* value, int32_t length = -1, bool copy = true); + ~StringReader(); + int32_t read(const T*& start, int32_t min, int32_t max); + int64_t skip(int64_t ntoskip); + int64_t reset(int64_t pos); +}; + +typedef StringReader StringInputStream; + +template +StringReader::StringReader(const T* value, int32_t length, bool copy) + : markpt(0), dataowner(copy) { + if (length < 0) { + length = 0; + while (value[length] != '\0') { + length++; + } + } + StreamBase::size = length; + if (copy) { + data = new T[length+1]; + size_t s = (size_t)(length*sizeof(T)); + memcpy(data, value, s); + data[length] = 0; + } else { + // casting away const is ok, because we don't write anyway + data = (T*)value; + } +} +template +StringReader::~StringReader() { + if (dataowner) { + delete [] data; + } +} +template +int32_t +StringReader::read(const T*& start, int32_t min, int32_t max) { + int64_t left = StreamBase::size - StreamBase::position; + if (left == 0) { + StreamBase::status = Eof; + return -1; + } + if (min < 0) min = 0; + int32_t nread = (int32_t)((max > left || max < 1) ?left :max); + start = data + StreamBase::position; + StreamBase::position += nread; + if (StreamBase::position == StreamBase::size) { + StreamBase::status = Eof; + } + return nread; +} +template +int64_t +StringReader::skip(int64_t ntoskip) { + const T* start; + return read(start, ntoskip, ntoskip); +} +template +int64_t +StringReader::reset(int64_t newpos) { + if (newpos < 0) { + StreamBase::status = Ok; + StreamBase::position = 0; + } else if (newpos < StreamBase::size) { + StreamBase::status = Ok; + StreamBase::position = newpos; + } else { + StreamBase::position = StreamBase::size; + StreamBase::status = Eof; + } + return StreamBase::position; +} + +} // end namespace jstreams + +#endif diff --git a/3rdparty/clucene/src/CLucene/util/subinputstream.h b/3rdparty/clucene/src/CLucene/util/subinputstream.h new file mode 100644 index 000000000..8ae3e33c7 --- /dev/null +++ b/3rdparty/clucene/src/CLucene/util/subinputstream.h @@ -0,0 +1,141 @@ +/*------------------------------------------------------------------------------ +* Copyright (C) 2003-2006 Jos van den Oever +* +* Distributable under the terms of either the Apache License (Version 2.0) or +* the GNU Lesser General Public License, as specified in the COPYING file. +------------------------------------------------------------------------------*/ +/* This file is part of Strigi Desktop Search + * + * Copyright (C) 2006 Jos van den Oever + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifndef SUBINPUTSTREAM_H +#define SUBINPUTSTREAM_H + +#include "streambase.h" + +namespace jstreams { + +template +class SubInputStream : public StreamBase { +private: + const int64_t offset; + StreamBase *input; +public: + SubInputStream(StreamBase *input, int64_t size=-1); + int32_t read(const T*& start, int32_t min, int32_t max); + int64_t reset(int64_t newpos); + int64_t skip(int64_t ntoskip); +}; +template +SubInputStream::SubInputStream(StreamBase *i, int64_t length) + : offset(i->getPosition()), input(i) { + assert(length >= -1); +// printf("substream offset: %lli\n", offset); + StreamBase::size = length; +} + +template +int32_t SubInputStream::read(const T*& start, int32_t min, int32_t max) { + if (StreamBase::size != -1) { + const int64_t left = StreamBase::size - StreamBase::position; + if (left == 0) { + return -1; + } + // restrict the amount of data that can be read + if (max <= 0 || max > left) { + max = (int32_t)left; + } + if (min > max) min = max; + if (left < min) min = (int32_t)left; + } + int32_t nread = input->read(start, min, max); + if (nread < -1) { + fprintf(stderr, "substream too short.\n"); + StreamBase::status = Error; + StreamBase::error = input->getError(); + } else if (nread < min) { + if (StreamBase::size == -1) { + StreamBase::status = Eof; + if (nread > 0) { + StreamBase::position += nread; + StreamBase::size = StreamBase::position; + } + } else { +// fprintf(stderr, "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! nread %i min %i max %i size %lli\n", nread, min, max, size); +// fprintf(stderr, "pos %lli parentpos %lli\n", position, input->getPosition()); +// fprintf(stderr, "status: %i error: %s\n", input->getStatus(), input->getError()); + // we expected data but didn't get enough so that's an error + StreamBase::status = Error; + StreamBase::error = "Premature end of stream\n"; + nread = -2; + } + } else { + StreamBase::position += nread; + if (StreamBase::position == StreamBase::size) { + StreamBase::status = Eof; + } + } + return nread; +} + +template +int64_t SubInputStream::reset(int64_t newpos) { +// fprintf(stderr, "subreset pos: %lli newpos: %lli offset: %lli\n", position, +// newpos, offset); + StreamBase::position = input->reset(newpos + offset); + if (StreamBase::position < offset) { + printf("###########\n"); + StreamBase::status = Error; + StreamBase::error = input->getError(); + } else { + StreamBase::position -= offset; + StreamBase::status = input->getStatus(); + } + return StreamBase::position; +} + +template +int64_t SubInputStream::skip(int64_t ntoskip) { +// printf("subskip pos: %lli ntoskip: %lli offset: %lli\n", position, ntoskip, offset); + if (StreamBase::size == StreamBase::position) { + StreamBase::status = Eof; + return -1; + } + if (StreamBase::size != -1) { + const int64_t left = StreamBase::size - StreamBase::position; + // restrict the amount of data that can be skipped + if (ntoskip > left) { + ntoskip = left; + } + } + int64_t skipped = input->skip(ntoskip); + if (input->getStatus() == Error) { + StreamBase::status = Error; + StreamBase::error = input->getError(); + } else { + StreamBase::position += skipped; + if (StreamBase::position == StreamBase::size) { + StreamBase::status = Eof; + } + } + return skipped; +} + +} //end namespace jstreams + +#endif diff --git a/demos/arthurplugin/arthur_plugin.qrc b/demos/arthurplugin/arthur_plugin.qrc new file mode 100644 index 000000000..e5170e63c --- /dev/null +++ b/demos/arthurplugin/arthur_plugin.qrc @@ -0,0 +1,7 @@ + + + bg1.jpg + flower.jpg + flower_alpha.jpg + + diff --git a/demos/arthurplugin/arthurplugin.pro b/demos/arthurplugin/arthurplugin.pro new file mode 100644 index 000000000..c5132b469 --- /dev/null +++ b/demos/arthurplugin/arthurplugin.pro @@ -0,0 +1,54 @@ + +QTDIR = $$QT_SOURCE_TREE + +CONFIG += designer plugin +TEMPLATE = lib +TARGET = $$qtLibraryTarget(arthurplugin) +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/designer + +contains(QT_CONFIG, opengl) { + DEFINES += QT_OPENGL_SUPPORT + QT += opengl +} + +SHARED_FOLDER = ../shared +include(../shared/shared.pri) + +DEMO_DEFORM_DIR = ../deform +DEMO_AFFINE_DIR = ../affine +DEMO_GRADIENT_DIR = ../gradients +DEMO_STROKE_DIR = ../pathstroke +DEMO_COMPOSITION_DIR = ../composition + +INCLUDEPATH += $$DEMO_DEFORM_DIR $$DEMO_AFFINE_DIR $$DEMO_GRADIENT_DIR $$DEMO_STROKE_DIR $$DEMO_COMPOSITION_DIR + +SOURCES = plugin.cpp \ + $$DEMO_COMPOSITION_DIR/composition.cpp \ + $$DEMO_AFFINE_DIR/xform.cpp \ + $$DEMO_DEFORM_DIR/pathdeform.cpp \ + $$DEMO_GRADIENT_DIR/gradients.cpp \ + $$DEMO_STROKE_DIR/pathstroke.cpp \ + + +HEADERS = \ + $$DEMO_COMPOSITION_DIR/composition.h \ + $$DEMO_AFFINE_DIR/xform.h \ + $$DEMO_DEFORM_DIR/pathdeform.h \ + $$DEMO_GRADIENT_DIR/gradients.h \ + $$DEMO_STROKE_DIR/pathstroke.h \ + +RESOURCES += arthur_plugin.qrc + +# install +target.path = $$[QT_INSTALL_PLUGINS]/designer +sources.files = $$SOURCES $$HEADERS $$RESOURCES *.pro *.jpg *.png +sources.path = $$[QT_INSTALL_DEMOS]/qttools/arthurplugin +INSTALLS += target sources + +symbian: include($$QT_SOURCE_TREE/demos/symbianpkgrules.pri) + +win32-msvc* { + QMAKE_CFLAGS += /Zm500 + QMAKE_CXXFLAGS += /Zm500 +} + diff --git a/demos/arthurplugin/bg1.jpg b/demos/arthurplugin/bg1.jpg new file mode 100644 index 000000000..dfc7cee6a Binary files /dev/null and b/demos/arthurplugin/bg1.jpg differ diff --git a/demos/arthurplugin/flower.jpg b/demos/arthurplugin/flower.jpg new file mode 100644 index 000000000..f8e022c98 Binary files /dev/null and b/demos/arthurplugin/flower.jpg differ diff --git a/demos/arthurplugin/flower_alpha.jpg b/demos/arthurplugin/flower_alpha.jpg new file mode 100644 index 000000000..6a3c2a02e Binary files /dev/null and b/demos/arthurplugin/flower_alpha.jpg differ diff --git a/demos/arthurplugin/plugin.cpp b/demos/arthurplugin/plugin.cpp new file mode 100644 index 000000000..336e88da6 --- /dev/null +++ b/demos/arthurplugin/plugin.cpp @@ -0,0 +1,296 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include +#include +#include + +#include "xform.h" +#include "pathdeform.h" +#include "gradients.h" +#include "pathstroke.h" +#include "hoverpoints.h" +#include "composition.h" + +QT_FORWARD_DECLARE_CLASS(QDesignerFormEditorInterface) + +// Specify "text" to be a singleline property (no richtext) +static inline QString textSingleLinePropertyDeclaration(const QString &className) +{ + QString rc = QLatin1String( + "\n" + " \n" + " "); + rc += className; + rc += QLatin1String("\n" + " \n" + " \n" + " \n" + " \n" + "\n"); + return rc; +} + +// Plain XML for a custom widget +static inline QString customWidgetDomXml(const QString &className, + const QString &customSection = QString()) +{ + QString rc = QLatin1String(""); + rc += customSection; + rc += QLatin1String(""); + return rc; +} + +class PathDeformRendererEx : public PathDeformRenderer +{ + Q_OBJECT +public: + PathDeformRendererEx(QWidget *parent) : PathDeformRenderer(parent) { } + QSize sizeHint() const { return QSize(300, 200); } +}; + +class DemoPlugin : public QDesignerCustomWidgetInterface +{ + Q_INTERFACES(QDesignerCustomWidgetInterface) + +protected: + explicit DemoPlugin(const QString &className, const QString &customSection = QString()); + +public: + QString name() const { return m_className; } + bool isContainer() const { return false; } + bool isInitialized() const { return m_initialized; } + QIcon icon() const { return QIcon(); } + QString codeTemplate() const { return QString(); } + QString whatsThis() const { return QString(); } + QString toolTip() const { return QString(); } + QString group() const { return "Arthur Widgets [Demo]"; } + void initialize(QDesignerFormEditorInterface *) + { + if (m_initialized) + return; + m_initialized = true; + } + QString domXml() const { return m_domXml; } + +private: + const QString m_className; + const QString m_domXml; + bool m_initialized; +}; + +DemoPlugin::DemoPlugin(const QString &className, const QString &customSection) : + m_className(className), + m_domXml(customWidgetDomXml(className, customSection)), + m_initialized(false) +{ +} + +class DeformPlugin : public QObject, public DemoPlugin +{ + Q_OBJECT + +public: + explicit DeformPlugin(QObject *parent = 0); + QString includeFile() const { return QLatin1String("deform.h"); } + + QWidget *createWidget(QWidget *parent) + { + PathDeformRenderer *deform = new PathDeformRendererEx(parent); + deform->setRadius(70); + deform->setAnimated(false); + deform->setFontSize(20); + deform->setText(QLatin1String("Arthur Widgets Demo")); + + return deform; + } +}; + +DeformPlugin::DeformPlugin(QObject *parent) : + QObject(parent), + DemoPlugin(QLatin1String("PathDeformRendererEx"), + textSingleLinePropertyDeclaration(QLatin1String("PathDeformRendererEx"))) +{ +} + +class XFormRendererEx : public XFormView +{ + Q_OBJECT +public: + XFormRendererEx(QWidget *parent) : XFormView(parent) {} + QSize sizeHint() const { return QSize(300, 200); } +}; + +class XFormPlugin : public QObject, public DemoPlugin +{ + Q_OBJECT +public: + explicit XFormPlugin(QObject *parent = 0); + QString includeFile() const { return QLatin1String("xform.h"); } + + QWidget *createWidget(QWidget *parent) + { + XFormRendererEx *xform = new XFormRendererEx(parent); + xform->setText(QLatin1String("Qt - Hello World!!")); + xform->setPixmap(QPixmap(QLatin1String(":/trolltech/arthurplugin/bg1.jpg"))); + return xform; + } +}; + +XFormPlugin::XFormPlugin(QObject *parent) : + QObject(parent), + DemoPlugin(QLatin1String("XFormRendererEx"), + textSingleLinePropertyDeclaration(QLatin1String("XFormRendererEx"))) +{ +} + +class GradientEditorPlugin : public QObject, public DemoPlugin +{ + Q_OBJECT +public: + explicit GradientEditorPlugin(QObject *parent = 0) : QObject(parent), DemoPlugin(QLatin1String("GradientEditor")) { } + QString includeFile() const { return "gradients.h"; } + + QWidget *createWidget(QWidget *parent) + { + GradientEditor *editor = new GradientEditor(parent); + return editor; + } +}; + +class GradientRendererEx : public GradientRenderer +{ + Q_OBJECT +public: + GradientRendererEx(QWidget *p) : GradientRenderer(p) { } + QSize sizeHint() const { return QSize(300, 200); } +}; + +class GradientRendererPlugin : public QObject, public DemoPlugin +{ + Q_OBJECT +public: + GradientRendererPlugin(QObject *parent = 0) : QObject(parent), DemoPlugin(QLatin1String("GradientRendererEx")) { } + QString includeFile() const { return QLatin1String("gradients.h"); } + + QWidget *createWidget(QWidget *parent) + { + GradientRenderer *renderer = new GradientRendererEx(parent); + renderer->setConicalGradient(); + return renderer; + } +}; + +class PathStrokeRendererEx : public PathStrokeRenderer +{ + Q_OBJECT +public: + explicit PathStrokeRendererEx(QWidget *p) : PathStrokeRenderer(p) { } + QSize sizeHint() const { return QSize(300, 200); } +}; + +class StrokeRenderPlugin : public QObject, public DemoPlugin +{ + Q_OBJECT +public: + explicit StrokeRenderPlugin(QObject *parent = 0) : QObject(parent), DemoPlugin(QLatin1String("PathStrokeRendererEx")) { } + QString includeFile() const { return QLatin1String("pathstroke.h"); } + + QWidget *createWidget(QWidget *parent) + { + PathStrokeRenderer *stroke = new PathStrokeRendererEx(parent); + return stroke; + } +}; + + +class CompositionModePlugin : public QObject, public DemoPlugin +{ + Q_OBJECT +public: + explicit CompositionModePlugin(QObject *parent = 0) : QObject(parent), DemoPlugin(QLatin1String("CompositionRenderer")) { } + QString includeFile() const { return QLatin1String("composition.h"); } + + QWidget *createWidget(QWidget *parent) + { + CompositionRenderer *renderer = new CompositionRenderer(parent); + renderer->setAnimationEnabled(false); + return renderer; + } +}; + + +class ArthurPlugins : public QObject, public QDesignerCustomWidgetCollectionInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetCollectionInterface) + +public: + explicit ArthurPlugins(QObject *parent = 0); + QList customWidgets() const { return m_plugins; } + +private: + QList m_plugins; +}; + +ArthurPlugins::ArthurPlugins(QObject *parent) : + QObject(parent) +{ + m_plugins << new DeformPlugin(this) + << new XFormPlugin(this) + << new GradientEditorPlugin(this) + << new GradientRendererPlugin(this) + << new StrokeRenderPlugin(this) + << new CompositionModePlugin(this); +} + +#include "plugin.moc" + +Q_EXPORT_PLUGIN2(ArthurPlugins, ArthurPlugins) diff --git a/demos/shared/arthurstyle.cpp b/demos/shared/arthurstyle.cpp new file mode 100644 index 000000000..e8e8a0201 --- /dev/null +++ b/demos/shared/arthurstyle.cpp @@ -0,0 +1,452 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "arthurstyle.h" +#include "arthurwidgets.h" +#include +#include +#include +#include +#include +#include +#include +#include + +QPixmap cached(const QString &img) +{ + if (QPixmap *p = QPixmapCache::find(img)) + return *p; + + QPixmap pm; + pm = QPixmap::fromImage(QImage(img), Qt::OrderedDither | Qt::OrderedAlphaDither); + if (pm.isNull()) + return QPixmap(); + + QPixmapCache::insert(img, pm); + return pm; +} + + +ArthurStyle::ArthurStyle() + : QWindowsStyle() +{ + Q_INIT_RESOURCE(shared); +} + + +void ArthurStyle::drawHoverRect(QPainter *painter, const QRect &r) const +{ + qreal h = r.height(); + qreal h2 = r.height() / qreal(2); + QPainterPath path; + path.addRect(r.x() + h2, r.y() + 0, r.width() - h2 * 2, r.height()); + path.addEllipse(r.x(), r.y(), h, h); + path.addEllipse(r.x() + r.width() - h, r.y(), h, h); + path.setFillRule(Qt::WindingFill); + painter->setPen(Qt::NoPen); + painter->setBrush(QColor(191, 215, 191)); + painter->setRenderHint(QPainter::Antialiasing); + painter->drawPath(path); +} + + +void ArthurStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, + QPainter *painter, const QWidget *widget) const +{ + + Q_ASSERT(option); + switch (element) { + case PE_FrameFocusRect: + break; + + case PE_IndicatorRadioButton: + if (const QStyleOptionButton *button = qstyleoption_cast(option)) { + bool hover = (button->state & State_Enabled) && (button->state & State_MouseOver); + painter->save(); + QPixmap radio; + if (hover) + drawHoverRect(painter, widget->rect()); + + if (button->state & State_Sunken) + radio = cached(":res/images/radiobutton-on.png"); + else if (button->state & State_On) + radio = cached(":res/images/radiobutton_on.png"); + else + radio = cached(":res/images/radiobutton_off.png"); + painter->drawPixmap(button->rect.topLeft(), radio); + + painter->restore(); + } + break; + + case PE_PanelButtonCommand: + if (const QStyleOptionButton *button = qstyleoption_cast(option)) { + bool hover = (button->state & State_Enabled) && (button->state & State_MouseOver); + + painter->save(); + const QPushButton *pushButton = qobject_cast(widget); + Q_ASSERT(pushButton); + QWidget *parent = pushButton->parentWidget(); + if (parent && qobject_cast(parent)) { + QLinearGradient lg(0, 0, 0, parent->height()); + lg.setColorAt(0, QColor(224,224,224)); + lg.setColorAt(1, QColor(255,255,255)); + painter->setPen(Qt::NoPen); + painter->setBrush(lg); + painter->setBrushOrigin(-widget->mapToParent(QPoint(0,0))); + painter->drawRect(button->rect); + painter->setBrushOrigin(0,0); + } + + bool down = (button->state & State_Sunken) || (button->state & State_On); + + QPixmap left, right, mid; + if (down) { + left = cached(":res/images/button_pressed_cap_left.png"); + right = cached(":res/images/button_pressed_cap_right.png"); + mid = cached(":res/images/button_pressed_stretch.png"); + } else { + left = cached(":res/images/button_normal_cap_left.png"); + right = cached(":res/images/button_normal_cap_right.png"); + mid = cached(":res/images/button_normal_stretch.png"); + } + painter->drawPixmap(button->rect.topLeft(), left); + painter->drawTiledPixmap(QRect(button->rect.x() + left.width(), + button->rect.y(), + button->rect.width() - left.width() - right.width(), + left.height()), + mid); + painter->drawPixmap(button->rect.x() + button->rect.width() - right.width(), + button->rect.y(), + right); + if (hover) + painter->fillRect(widget->rect().adjusted(3,5,-3,-5), QColor(31,127,31,63)); + painter->restore(); + } + break; + + case PE_FrameGroupBox: + if (const QStyleOptionFrameV2 *group + = qstyleoption_cast(option)) { + const QRect &r = group->rect; + + painter->save(); + int radius = 14; + int radius2 = radius*2; + QPainterPath clipPath; + clipPath.moveTo(radius, 0); + clipPath.arcTo(r.right() - radius2, 0, radius2, radius2, 90, -90); + clipPath.arcTo(r.right() - radius2, r.bottom() - radius2, radius2, radius2, 0, -90); + clipPath.arcTo(r.left(), r.bottom() - radius2, radius2, radius2, 270, -90); + clipPath.arcTo(r.left(), r.top(), radius2, radius2, 180, -90); + painter->setClipPath(clipPath); + QPixmap titleStretch = cached(":res/images/title_stretch.png"); + QPixmap topLeft = cached(":res/images/groupframe_topleft.png"); + QPixmap topRight = cached(":res/images/groupframe_topright.png"); + QPixmap bottomLeft = cached(":res/images/groupframe_bottom_left.png"); + QPixmap bottomRight = cached(":res/images/groupframe_bottom_right.png"); + QPixmap leftStretch = cached(":res/images/groupframe_left_stretch.png"); + QPixmap topStretch = cached(":res/images/groupframe_top_stretch.png"); + QPixmap rightStretch = cached(":res/images/groupframe_right_stretch.png"); + QPixmap bottomStretch = cached(":res/images/groupframe_bottom_stretch.png"); + QLinearGradient lg(0, 0, 0, r.height()); + lg.setColorAt(0, QColor(224,224,224)); + lg.setColorAt(1, QColor(255,255,255)); + painter->setPen(Qt::NoPen); + painter->setBrush(lg); + painter->drawRect(r.adjusted(0, titleStretch.height()/2, 0, 0)); + painter->setClipping(false); + + int topFrameOffset = titleStretch.height()/2 - 2; + painter->drawPixmap(r.topLeft() + QPoint(0, topFrameOffset), topLeft); + painter->drawPixmap(r.topRight() - QPoint(topRight.width()-1, 0) + + QPoint(0, topFrameOffset), topRight); + painter->drawPixmap(r.bottomLeft() - QPoint(0, bottomLeft.height()-1), bottomLeft); + painter->drawPixmap(r.bottomRight() - QPoint(bottomRight.width()-1, + bottomRight.height()-1), bottomRight); + + QRect left = r; + left.setY(r.y() + topLeft.height() + topFrameOffset); + left.setWidth(leftStretch.width()); + left.setHeight(r.height() - topLeft.height() - bottomLeft.height() - topFrameOffset); + painter->drawTiledPixmap(left, leftStretch); + + QRect top = r; + top.setX(r.x() + topLeft.width()); + top.setY(r.y() + topFrameOffset); + top.setWidth(r.width() - topLeft.width() - topRight.width()); + top.setHeight(topLeft.height()); + painter->drawTiledPixmap(top, topStretch); + + QRect right = r; + right.setX(r.right() - rightStretch.width()+1); + right.setY(r.y() + topRight.height() + topFrameOffset); + right.setWidth(rightStretch.width()); + right.setHeight(r.height() - topRight.height() + - bottomRight.height() - topFrameOffset); + painter->drawTiledPixmap(right, rightStretch); + + QRect bottom = r; + bottom.setX(r.x() + bottomLeft.width()); + bottom.setY(r.bottom() - bottomStretch.height()+1); + bottom.setWidth(r.width() - bottomLeft.width() - bottomRight.width()); + bottom.setHeight(bottomLeft.height()); + painter->drawTiledPixmap(bottom, bottomStretch); + painter->restore(); + } + break; + + default: + QWindowsStyle::drawPrimitive(element, option, painter, widget); + break; + } + return; +} + + +void ArthurStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, + QPainter *painter, const QWidget *widget) const +{ + switch (control) { + case CC_Slider: + if (const QStyleOptionSlider *slider = qstyleoption_cast(option)) { + QRect groove = subControlRect(CC_Slider, option, SC_SliderGroove, widget); + QRect handle = subControlRect(CC_Slider, option, SC_SliderHandle, widget); + + painter->save(); + + bool hover = (slider->state & State_Enabled) && (slider->state & State_MouseOver); + if (hover) { + QRect moderated = widget->rect().adjusted(0, 4, 0, -4); + drawHoverRect(painter, moderated); + } + + if ((option->subControls & SC_SliderGroove) && groove.isValid()) { + QPixmap grv = cached(":res/images/slider_bar.png"); + painter->drawPixmap(QRect(groove.x() + 5, groove.y(), + groove.width() - 10, grv.height()), + grv); + } + if ((option->subControls & SC_SliderHandle) && handle.isValid()) { + QPixmap hndl = cached(":res/images/slider_thumb_on.png"); + painter->drawPixmap(handle.topLeft(), hndl); + } + + painter->restore(); + } + break; + case CC_GroupBox: + if (const QStyleOptionGroupBox *groupBox + = qstyleoption_cast(option)) { + QStyleOptionGroupBox groupBoxCopy(*groupBox); + groupBoxCopy.subControls &= ~SC_GroupBoxLabel; + QWindowsStyle::drawComplexControl(control, &groupBoxCopy, painter, widget); + + if (groupBox->subControls & SC_GroupBoxLabel) { + const QRect &r = groupBox->rect; + QPixmap titleLeft = cached(":res/images/title_cap_left.png"); + QPixmap titleRight = cached(":res/images/title_cap_right.png"); + QPixmap titleStretch = cached(":res/images/title_stretch.png"); + int txt_width = groupBox->fontMetrics.width(groupBox->text) + 20; + painter->drawPixmap(r.center().x() - txt_width/2, 0, titleLeft); + QRect tileRect = subControlRect(control, groupBox, SC_GroupBoxLabel, widget); + painter->drawTiledPixmap(tileRect, titleStretch); + painter->drawPixmap(tileRect.x() + tileRect.width(), 0, titleRight); + int opacity = 31; + painter->setPen(QColor(0, 0, 0, opacity)); + painter->drawText(tileRect.translated(0, 1), + Qt::AlignVCenter | Qt::AlignHCenter, groupBox->text); + painter->drawText(tileRect.translated(2, 1), + Qt::AlignVCenter | Qt::AlignHCenter, groupBox->text); + painter->setPen(QColor(0, 0, 0, opacity * 2)); + painter->drawText(tileRect.translated(1, 1), + Qt::AlignVCenter | Qt::AlignHCenter, groupBox->text); + painter->setPen(Qt::white); + painter->drawText(tileRect, Qt::AlignVCenter | Qt::AlignHCenter, groupBox->text); + } + } + break; + default: + QWindowsStyle::drawComplexControl(control, option, painter, widget); + break; + } + return; +} + +QRect ArthurStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option, + SubControl subControl, const QWidget *widget) const +{ + QRect rect; + + switch (control) { + default: + rect = QWindowsStyle::subControlRect(control, option, subControl, widget); + break; + case CC_GroupBox: + if (const QStyleOptionGroupBox *group + = qstyleoption_cast(option)) { + switch (subControl) { + default: + rect = QWindowsStyle::subControlRect(control, option, subControl, widget); + break; + case SC_GroupBoxContents: + rect = QWindowsStyle::subControlRect(control, option, subControl, widget); + rect.adjust(0, -8, 0, 0); + break; + case SC_GroupBoxFrame: + rect = group->rect; + break; + case SC_GroupBoxLabel: + QPixmap titleLeft = cached(":res/images/title_cap_left.png"); + QPixmap titleRight = cached(":res/images/title_cap_right.png"); + QPixmap titleStretch = cached(":res/images/title_stretch.png"); + int txt_width = group->fontMetrics.width(group->text) + 20; + rect = QRect(group->rect.center().x() - txt_width/2 + titleLeft.width(), 0, + txt_width - titleLeft.width() - titleRight.width(), + titleStretch.height()); + break; + } + } + break; + } + + if (control == CC_Slider && subControl == SC_SliderHandle) { + rect.setWidth(13); + rect.setHeight(27); + } else if (control == CC_Slider && subControl == SC_SliderGroove) { + rect.setHeight(9); + rect.moveTop(27/2 - 9/2); + } + return rect; +} + +QSize ArthurStyle::sizeFromContents(ContentsType type, const QStyleOption *option, + const QSize &size, const QWidget *widget) const +{ + QSize newSize = QWindowsStyle::sizeFromContents(type, option, size, widget); + + + switch (type) { + case CT_RadioButton: + newSize += QSize(20, 0); + break; + + case CT_PushButton: + newSize.setHeight(26); + break; + + case CT_Slider: + newSize.setHeight(27); + break; + + default: + break; + } + + return newSize; +} + +int ArthurStyle::pixelMetric(PixelMetric pm, const QStyleOption *opt, const QWidget *widget) const +{ + if (pm == PM_SliderLength) + return 13; + return QWindowsStyle::pixelMetric(pm, opt, widget); +} + +void ArthurStyle::polish(QWidget *widget) +{ + if (widget->layout() && qobject_cast(widget)) { + if (widget->findChildren().size() == 0) { + widget->layout()->setSpacing(0); + widget->layout()->setMargin(12); + } else { + widget->layout()->setMargin(13); + } + } + + if (qobject_cast(widget) + || qobject_cast(widget) + || qobject_cast(widget)) { + widget->setAttribute(Qt::WA_Hover); + } + + QPalette pal = widget->palette(); + if (widget->isWindow()) { + pal.setColor(QPalette::Background, QColor(241, 241, 241)); + widget->setPalette(pal); + } + +} + +void ArthurStyle::unpolish(QWidget *widget) +{ + if (qobject_cast(widget) + || qobject_cast(widget) + || qobject_cast(widget)) { + widget->setAttribute(Qt::WA_Hover, false); + } +} + +void ArthurStyle::polish(QPalette &palette) +{ + palette.setColor(QPalette::Background, QColor(241, 241, 241)); +} + +QRect ArthurStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const +{ + QRect r; + switch(element) { + case SE_RadioButtonClickRect: + r = widget->rect(); + break; + case SE_RadioButtonContents: + r = widget->rect().adjusted(20, 0, 0, 0); + break; + default: + r = QWindowsStyle::subElementRect(element, option, widget); + break; + } + + if (qobject_cast(widget)) + r = r.adjusted(5, 0, -5, 0); + + return r; +} diff --git a/demos/shared/arthurstyle.h b/demos/shared/arthurstyle.h new file mode 100644 index 000000000..9e3ada9b9 --- /dev/null +++ b/demos/shared/arthurstyle.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ARTHURSTYLE_H +#define ARTHURSTYLE_H + +#include + +QT_USE_NAMESPACE + +class ArthurStyle : public QWindowsStyle +{ +public: + ArthurStyle(); + + void drawHoverRect(QPainter *painter, const QRect &rect) const; + + void drawPrimitive(PrimitiveElement element, const QStyleOption *option, + QPainter *painter, const QWidget *widget = 0) const; +// void drawControl(ControlElement element, const QStyleOption *option, +// QPainter *painter, const QWidget *widget) const; + void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, + QPainter *painter, const QWidget *widget) const; + QSize sizeFromContents(ContentsType type, const QStyleOption *option, + const QSize &size, const QWidget *widget) const; + + QRect subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const; + QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, + SubControl sc, const QWidget *widget) const; + +// SubControl hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option, +// const QPoint &pos, const QWidget *widget = 0) const; + + int pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const; + + void polish(QPalette &palette); + void polish(QWidget *widget); + void unpolish(QWidget *widget); +}; + +#endif diff --git a/demos/shared/arthurwidgets.cpp b/demos/shared/arthurwidgets.cpp new file mode 100644 index 000000000..d6b8ccaba --- /dev/null +++ b/demos/shared/arthurwidgets.cpp @@ -0,0 +1,371 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "arthurwidgets.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +extern QPixmap cached(const QString &img); + +ArthurFrame::ArthurFrame(QWidget *parent) + : QWidget(parent) + , m_prefer_image(false) +{ +#ifdef QT_OPENGL_SUPPORT + glw = 0; + m_use_opengl = false; + QGLFormat f = QGLFormat::defaultFormat(); + f.setSampleBuffers(true); + f.setStencil(true); + f.setAlpha(true); + f.setAlphaBufferSize(8); + QGLFormat::setDefaultFormat(f); +#endif + m_document = 0; + m_show_doc = false; + + m_tile = QPixmap(128, 128); + m_tile.fill(Qt::white); + QPainter pt(&m_tile); + QColor color(230, 230, 230); + pt.fillRect(0, 0, 64, 64, color); + pt.fillRect(64, 64, 64, 64, color); + pt.end(); + +// QPalette pal = palette(); +// pal.setBrush(backgroundRole(), m_tile); +// setPalette(pal); + +#ifdef Q_WS_X11 + QPixmap xRenderPixmap(1, 1); + m_prefer_image = xRenderPixmap.pixmapData()->classId() == QPixmapData::X11Class && !xRenderPixmap.x11PictureHandle(); +#endif +} + + +#ifdef QT_OPENGL_SUPPORT +void ArthurFrame::enableOpenGL(bool use_opengl) +{ + m_use_opengl = use_opengl; + + if (!glw) { + glw = new GLWidget(this); + glw->setAutoFillBackground(false); + glw->disableAutoBufferSwap(); + QApplication::postEvent(this, new QResizeEvent(size(), size())); + } + + if (use_opengl) { + glw->show(); + } else { + glw->hide(); + } + + update(); +} +#endif + +void ArthurFrame::paintEvent(QPaintEvent *e) +{ +#ifdef Q_WS_QWS + static QPixmap *static_image = 0; +#else + static QImage *static_image = 0; +#endif + QPainter painter; + if (preferImage() +#ifdef QT_OPENGL_SUPPORT + && !m_use_opengl +#endif + ) { + if (!static_image || static_image->size() != size()) { + delete static_image; +#ifdef Q_WS_QWS + static_image = new QPixmap(size()); +#else + static_image = new QImage(size(), QImage::Format_RGB32); +#endif + } + painter.begin(static_image); + + int o = 10; + + QBrush bg = palette().brush(QPalette::Background); + painter.fillRect(0, 0, o, o, bg); + painter.fillRect(width() - o, 0, o, o, bg); + painter.fillRect(0, height() - o, o, o, bg); + painter.fillRect(width() - o, height() - o, o, o, bg); + } else { +#ifdef QT_OPENGL_SUPPORT + if (m_use_opengl) { + painter.begin(glw); + painter.fillRect(QRectF(0, 0, glw->width(), glw->height()), palette().color(backgroundRole())); + } else { + painter.begin(this); + } +#else + painter.begin(this); +#endif + } + + painter.setClipRect(e->rect()); + + painter.setRenderHint(QPainter::Antialiasing); + + QPainterPath clipPath; + + QRect r = rect(); + qreal left = r.x() + 1; + qreal top = r.y() + 1; + qreal right = r.right(); + qreal bottom = r.bottom(); + qreal radius2 = 8 * 2; + + clipPath.moveTo(right - radius2, top); + clipPath.arcTo(right - radius2, top, radius2, radius2, 90, -90); + clipPath.arcTo(right - radius2, bottom - radius2, radius2, radius2, 0, -90); + clipPath.arcTo(left, bottom - radius2, radius2, radius2, 270, -90); + clipPath.arcTo(left, top, radius2, radius2, 180, -90); + clipPath.closeSubpath(); + + painter.save(); + painter.setClipPath(clipPath, Qt::IntersectClip); + + painter.drawTiledPixmap(rect(), m_tile); + + // client painting + + paint(&painter); + + painter.restore(); + + painter.save(); + if (m_show_doc) + paintDescription(&painter); + painter.restore(); + + int level = 180; + painter.setPen(QPen(QColor(level, level, level), 2)); + painter.setBrush(Qt::NoBrush); + painter.drawPath(clipPath); + + if (preferImage() +#ifdef QT_OPENGL_SUPPORT + && !m_use_opengl +#endif + ) { + painter.end(); + painter.begin(this); +#ifdef Q_WS_QWS + painter.drawPixmap(e->rect(), *static_image, e->rect()); +#else + painter.drawImage(e->rect(), *static_image, e->rect()); +#endif + } + +#ifdef QT_OPENGL_SUPPORT + if (m_use_opengl && (inherits("PathDeformRenderer") || inherits("PathStrokeRenderer") || inherits("CompositionRenderer") || m_show_doc)) + glw->swapBuffers(); +#endif +} + +void ArthurFrame::resizeEvent(QResizeEvent *e) +{ +#ifdef QT_OPENGL_SUPPORT + if (glw) + glw->setGeometry(0, 0, e->size().width()-1, e->size().height()-1); +#endif + QWidget::resizeEvent(e); +} + +void ArthurFrame::setDescriptionEnabled(bool enabled) +{ + if (m_show_doc != enabled) { + m_show_doc = enabled; + emit descriptionEnabledChanged(m_show_doc); + update(); + } +} + +void ArthurFrame::loadDescription(const QString &fileName) +{ + QFile textFile(fileName); + QString text; + if (!textFile.open(QFile::ReadOnly)) + text = QString("Unable to load resource file: '%1'").arg(fileName); + else + text = textFile.readAll(); + setDescription(text); +} + + +void ArthurFrame::setDescription(const QString &text) +{ + m_document = new QTextDocument(this); + m_document->setHtml(text); +} + +void ArthurFrame::paintDescription(QPainter *painter) +{ + if (!m_document) + return; + + int pageWidth = qMax(width() - 100, 100); + int pageHeight = qMax(height() - 100, 100); + if (pageWidth != m_document->pageSize().width()) { + m_document->setPageSize(QSize(pageWidth, pageHeight)); + } + + QRect textRect(width() / 2 - pageWidth / 2, + height() / 2 - pageHeight / 2, + pageWidth, + pageHeight); + int pad = 10; + QRect clearRect = textRect.adjusted(-pad, -pad, pad, pad); + painter->setPen(Qt::NoPen); + painter->setBrush(QColor(0, 0, 0, 63)); + int shade = 10; + painter->drawRect(clearRect.x() + clearRect.width() + 1, + clearRect.y() + shade, + shade, + clearRect.height() + 1); + painter->drawRect(clearRect.x() + shade, + clearRect.y() + clearRect.height() + 1, + clearRect.width() - shade + 1, + shade); + + painter->setRenderHint(QPainter::Antialiasing, false); + painter->setBrush(QColor(255, 255, 255, 220)); + painter->setPen(Qt::black); + painter->drawRect(clearRect); + + painter->setClipRegion(textRect, Qt::IntersectClip); + painter->translate(textRect.topLeft()); + + QAbstractTextDocumentLayout::PaintContext ctx; + + QLinearGradient g(0, 0, 0, textRect.height()); + g.setColorAt(0, Qt::black); + g.setColorAt(0.9, Qt::black); + g.setColorAt(1, Qt::transparent); + + QPalette pal = palette(); + pal.setBrush(QPalette::Text, g); + + ctx.palette = pal; + ctx.clip = QRect(0, 0, textRect.width(), textRect.height()); + m_document->documentLayout()->draw(painter, ctx); +} + +void ArthurFrame::loadSourceFile(const QString &sourceFile) +{ + m_sourceFileName = sourceFile; +} + +void ArthurFrame::showSource() +{ + // Check for existing source + if (findChild()) + return; + + QString contents; + if (m_sourceFileName.isEmpty()) { + contents = QString("No source for widget: '%1'").arg(objectName()); + } else { + QFile f(m_sourceFileName); + if (!f.open(QFile::ReadOnly)) + contents = QString("Could not open file: '%1'").arg(m_sourceFileName); + else + contents = f.readAll(); + } + + contents.replace('&', "&"); + contents.replace('<', "<"); + contents.replace('>', ">"); + + QStringList keywords; + keywords << "for " << "if " << "switch " << " int " << "#include " << "const" + << "void " << "uint " << "case " << "double " << "#define " << "static" + << "new" << "this"; + + foreach (QString keyword, keywords) + contents.replace(keyword, QLatin1String("") + keyword + QLatin1String("")); + contents.replace("(int ", "(int "); + + QStringList ppKeywords; + ppKeywords << "#ifdef" << "#ifndef" << "#if" << "#endif" << "#else"; + + foreach (QString keyword, ppKeywords) + contents.replace(keyword, QLatin1String("") + keyword + QLatin1String("")); + + contents.replace(QRegExp("(\\d\\d?)"), QLatin1String("\\1")); + + QRegExp commentRe("(//.+)\\n"); + commentRe.setMinimal(true); + contents.replace(commentRe, QLatin1String("\\1\n")); + + QRegExp stringLiteralRe("(\".+\")"); + stringLiteralRe.setMinimal(true); + contents.replace(stringLiteralRe, QLatin1String("\\1")); + + QString html = contents; + html.prepend("
");
+    html.append("
"); + + QTextBrowser *sourceViewer = new QTextBrowser(0); + sourceViewer->setWindowTitle("Source: " + m_sourceFileName.mid(5)); + sourceViewer->setParent(this, Qt::Dialog); + sourceViewer->setAttribute(Qt::WA_DeleteOnClose); + sourceViewer->setLineWrapMode(QTextEdit::NoWrap); + sourceViewer->setHtml(html); + sourceViewer->resize(600, 600); + sourceViewer->show(); +} diff --git a/demos/shared/arthurwidgets.h b/demos/shared/arthurwidgets.h new file mode 100644 index 000000000..67571119f --- /dev/null +++ b/demos/shared/arthurwidgets.h @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ARTHURWIDGETS_H +#define ARTHURWIDGETS_H + +#include "arthurstyle.h" +#include +#include +#include + +#if defined(QT_OPENGL_SUPPORT) +#include +#include +class GLWidget : public QGLWidget +{ +public: + GLWidget(QWidget *parent) + : QGLWidget(QGLFormat(QGL::SampleBuffers), parent) + { + setAttribute(Qt::WA_AcceptTouchEvents); + } + void disableAutoBufferSwap() { setAutoBufferSwap(false); } + void paintEvent(QPaintEvent *) { parentWidget()->update(); } +protected: + bool event(QEvent *event) + { + switch (event->type()) { + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + event->ignore(); + return false; + break; + default: + break; + } + return QGLWidget::event(event); + } +}; +#endif + +QT_FORWARD_DECLARE_CLASS(QTextDocument) +QT_FORWARD_DECLARE_CLASS(QTextEdit) +QT_FORWARD_DECLARE_CLASS(QVBoxLayout) + +class ArthurFrame : public QWidget +{ + Q_OBJECT +public: + ArthurFrame(QWidget *parent); + virtual void paint(QPainter *) {} + + + void paintDescription(QPainter *p); + + void loadDescription(const QString &filename); + void setDescription(const QString &htmlDesc); + + void loadSourceFile(const QString &fileName); + + bool preferImage() const { return m_prefer_image; } + +#if defined(QT_OPENGL_SUPPORT) + QGLWidget *glWidget() const { return glw; } +#endif + +public slots: + void setPreferImage(bool pi) { m_prefer_image = pi; } + void setDescriptionEnabled(bool enabled); + void showSource(); + +#if defined(QT_OPENGL_SUPPORT) + void enableOpenGL(bool use_opengl); + bool usesOpenGL() { return m_use_opengl; } +#endif + +signals: + void descriptionEnabledChanged(bool); + +protected: + void paintEvent(QPaintEvent *); + void resizeEvent(QResizeEvent *); + +#if defined(QT_OPENGL_SUPPORT) + GLWidget *glw; + bool m_use_opengl; +#endif + QPixmap m_tile; + + bool m_show_doc; + bool m_prefer_image; + QTextDocument *m_document; + + QString m_sourceFileName; + +}; + +#endif diff --git a/demos/shared/hoverpoints.cpp b/demos/shared/hoverpoints.cpp new file mode 100644 index 000000000..272f89540 --- /dev/null +++ b/demos/shared/hoverpoints.cpp @@ -0,0 +1,415 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the demonstration applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifdef QT_OPENGL_SUPPORT +#include +#endif + +#include "arthurwidgets.h" +#include "hoverpoints.h" + +#define printf + +HoverPoints::HoverPoints(QWidget *widget, PointShape shape) + : QObject(widget) +{ + m_widget = widget; + widget->installEventFilter(this); + widget->setAttribute(Qt::WA_AcceptTouchEvents); + + m_connectionType = CurveConnection; + m_sortType = NoSort; + m_shape = shape; + m_pointPen = QPen(QColor(255, 255, 255, 191), 1); + m_connectionPen = QPen(QColor(255, 255, 255, 127), 2); + m_pointBrush = QBrush(QColor(191, 191, 191, 127)); + m_pointSize = QSize(11, 11); + m_currentIndex = -1; + m_editable = true; + m_enabled = true; + + connect(this, SIGNAL(pointsChanged(QPolygonF)), + m_widget, SLOT(update())); +} + + +void HoverPoints::setEnabled(bool enabled) +{ + if (m_enabled != enabled) { + m_enabled = enabled; + m_widget->update(); + } +} + + +bool HoverPoints::eventFilter(QObject *object, QEvent *event) +{ + if (object == m_widget && m_enabled) { + switch (event->type()) { + + case QEvent::MouseButtonPress: + { + if (!m_fingerPointMapping.isEmpty()) + return true; + QMouseEvent *me = (QMouseEvent *) event; + + QPointF clickPos = me->pos(); + int index = -1; + for (int i=0; ibutton() == Qt::LeftButton) { + if (index == -1) { + if (!m_editable) + return false; + int pos = 0; + // Insert sort for x or y + if (m_sortType == XSort) { + for (int i=0; i clickPos.x()) { + pos = i; + break; + } + } else if (m_sortType == YSort) { + for (int i=0; i clickPos.y()) { + pos = i; + break; + } + } + + m_points.insert(pos, clickPos); + m_locks.insert(pos, 0); + m_currentIndex = pos; + firePointChange(); + } else { + m_currentIndex = index; + } + return true; + + } else if (me->button() == Qt::RightButton) { + if (index >= 0 && m_editable) { + if (m_locks[index] == 0) { + m_locks.remove(index); + m_points.remove(index); + } + firePointChange(); + return true; + } + } + + } + break; + + case QEvent::MouseButtonRelease: + if (!m_fingerPointMapping.isEmpty()) + return true; + m_currentIndex = -1; + break; + + case QEvent::MouseMove: + if (!m_fingerPointMapping.isEmpty()) + return true; + if (m_currentIndex >= 0) + movePoint(m_currentIndex, ((QMouseEvent *)event)->pos()); + break; + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + { + const QTouchEvent *const touchEvent = static_cast(event); + const QList points = touchEvent->touchPoints(); + const qreal pointSize = qMax(m_pointSize.width(), m_pointSize.height()); + foreach (const QTouchEvent::TouchPoint &touchPoint, points) { + const int id = touchPoint.id(); + switch (touchPoint.state()) { + case Qt::TouchPointPressed: + { + // find the point, move it + QSet activePoints = QSet::fromList(m_fingerPointMapping.values()); + int activePoint = -1; + qreal distance = -1; + const int pointsCount = m_points.size(); + const int activePointCount = activePoints.size(); + if (pointsCount == 2 && activePointCount == 1) { // only two points + activePoint = activePoints.contains(0) ? 1 : 0; + } else { + for (int i=0; i::iterator it = m_fingerPointMapping.find(id); + movePoint(it.value(), touchPoint.pos()); + m_fingerPointMapping.erase(it); + } + break; + case Qt::TouchPointMoved: + { + // move the point + const int pointIdx = m_fingerPointMapping.value(id, -1); + if (pointIdx >= 0) // do we track this point? + movePoint(pointIdx, touchPoint.pos()); + } + break; + default: + break; + } + } + if (m_fingerPointMapping.isEmpty()) { + event->ignore(); + return false; + } else { + return true; + } + } + break; + case QEvent::TouchEnd: + if (m_fingerPointMapping.isEmpty()) { + event->ignore(); + return false; + } + return true; + break; + + case QEvent::Resize: + { + QResizeEvent *e = (QResizeEvent *) event; + if (e->oldSize().width() == 0 || e->oldSize().height() == 0) + break; + qreal stretch_x = e->size().width() / qreal(e->oldSize().width()); + qreal stretch_y = e->size().height() / qreal(e->oldSize().height()); + for (int i=0; i(that_widget); + if (af && af->usesOpenGL()) + af->glWidget()->swapBuffers(); +#endif + return true; + } + default: + break; + } + } + + return false; +} + + +void HoverPoints::paintPoints() +{ + QPainter p; +#ifdef QT_OPENGL_SUPPORT + ArthurFrame *af = qobject_cast(m_widget); + if (af && af->usesOpenGL()) + p.begin(af->glWidget()); + else + p.begin(m_widget); +#else + p.begin(m_widget); +#endif + + p.setRenderHint(QPainter::Antialiasing); + + if (m_connectionPen.style() != Qt::NoPen && m_connectionType != NoConnection) { + p.setPen(m_connectionPen); + + if (m_connectionType == CurveConnection) { + QPainterPath path; + path.moveTo(m_points.at(0)); + for (int i=1; i right || (lock & HoverPoints::LockToRight)) p.setX(right); + + if (p.y() < top || (lock & HoverPoints::LockToTop)) p.setY(top); + else if (p.y() > bottom || (lock & HoverPoints::LockToBottom)) p.setY(bottom); + + return p; +} + +void HoverPoints::setPoints(const QPolygonF &points) +{ + if (points.size() != m_points.size()) + m_fingerPointMapping.clear(); + m_points.clear(); + for (int i=0; i 0) { + m_locks.resize(m_points.size()); + + m_locks.fill(0); + } +} + + +void HoverPoints::movePoint(int index, const QPointF &point, bool emitUpdate) +{ + m_points[index] = bound_point(point, boundingRect(), m_locks.at(index)); + if (emitUpdate) + firePointChange(); +} + + +inline static bool x_less_than(const QPointF &p1, const QPointF &p2) +{ + return p1.x() < p2.x(); +} + + +inline static bool y_less_than(const QPointF &p1, const QPointF &p2) +{ + return p1.y() < p2.y(); +} + +void HoverPoints::firePointChange() +{ +// printf("HoverPoints::firePointChange(), current=%d\n", m_currentIndex); + + if (m_sortType != NoSort) { + + QPointF oldCurrent; + if (m_currentIndex != -1) { + oldCurrent = m_points[m_currentIndex]; + } + + if (m_sortType == XSort) + qSort(m_points.begin(), m_points.end(), x_less_than); + else if (m_sortType == YSort) + qSort(m_points.begin(), m_points.end(), y_less_than); + + // Compensate for changed order... + if (m_currentIndex != -1) { + for (int i=0; i + +QT_FORWARD_DECLARE_CLASS(QBypassWidget) + +class HoverPoints : public QObject +{ + Q_OBJECT +public: + enum PointShape { + CircleShape, + RectangleShape + }; + + enum LockType { + LockToLeft = 0x01, + LockToRight = 0x02, + LockToTop = 0x04, + LockToBottom = 0x08 + }; + + enum SortType { + NoSort, + XSort, + YSort + }; + + enum ConnectionType { + NoConnection, + LineConnection, + CurveConnection + }; + + HoverPoints(QWidget *widget, PointShape shape); + + bool eventFilter(QObject *object, QEvent *event); + + void paintPoints(); + + inline QRectF boundingRect() const; + void setBoundingRect(const QRectF &boundingRect) { m_bounds = boundingRect; } + + QPolygonF points() const { return m_points; } + void setPoints(const QPolygonF &points); + + QSizeF pointSize() const { return m_pointSize; } + void setPointSize(const QSizeF &size) { m_pointSize = size; } + + SortType sortType() const { return m_sortType; } + void setSortType(SortType sortType) { m_sortType = sortType; } + + ConnectionType connectionType() const { return m_connectionType; } + void setConnectionType(ConnectionType connectionType) { m_connectionType = connectionType; } + + void setConnectionPen(const QPen &pen) { m_connectionPen = pen; } + void setShapePen(const QPen &pen) { m_pointPen = pen; } + void setShapeBrush(const QBrush &brush) { m_pointBrush = brush; } + + void setPointLock(int pos, LockType lock) { m_locks[pos] = lock; } + + void setEditable(bool editable) { m_editable = editable; } + bool editable() const { return m_editable; } + +public slots: + void setEnabled(bool enabled); + void setDisabled(bool disabled) { setEnabled(!disabled); } + +signals: + void pointsChanged(const QPolygonF &points); + +public: + void firePointChange(); + +private: + inline QRectF pointBoundingRect(int i) const; + void movePoint(int i, const QPointF &newPos, bool emitChange = true); + + QWidget *m_widget; + + QPolygonF m_points; + QRectF m_bounds; + PointShape m_shape; + SortType m_sortType; + ConnectionType m_connectionType; + + QVector m_locks; + + QSizeF m_pointSize; + int m_currentIndex; + bool m_editable; + bool m_enabled; + + QHash m_fingerPointMapping; + + QPen m_pointPen; + QBrush m_pointBrush; + QPen m_connectionPen; +}; + + +inline QRectF HoverPoints::pointBoundingRect(int i) const +{ + QPointF p = m_points.at(i); + qreal w = m_pointSize.width(); + qreal h = m_pointSize.height(); + qreal x = p.x() - w / 2; + qreal y = p.y() - h / 2; + return QRectF(x, y, w, h); +} + +inline QRectF HoverPoints::boundingRect() const +{ + if (m_bounds.isEmpty()) + return m_widget->rect(); + else + return m_bounds; +} + +#endif // HOVERPOINTS_H diff --git a/demos/shared/images/bg_pattern.png b/demos/shared/images/bg_pattern.png new file mode 100644 index 000000000..ee670266f Binary files /dev/null and b/demos/shared/images/bg_pattern.png differ diff --git a/demos/shared/images/button_normal_cap_left.png b/demos/shared/images/button_normal_cap_left.png new file mode 100644 index 000000000..db31dd971 Binary files /dev/null and b/demos/shared/images/button_normal_cap_left.png differ diff --git a/demos/shared/images/button_normal_cap_right.png b/demos/shared/images/button_normal_cap_right.png new file mode 100644 index 000000000..38ead1c71 Binary files /dev/null and b/demos/shared/images/button_normal_cap_right.png differ diff --git a/demos/shared/images/button_normal_stretch.png b/demos/shared/images/button_normal_stretch.png new file mode 100644 index 000000000..87abe67ac Binary files /dev/null and b/demos/shared/images/button_normal_stretch.png differ diff --git a/demos/shared/images/button_pressed_cap_left.png b/demos/shared/images/button_pressed_cap_left.png new file mode 100644 index 000000000..66bfc13cb Binary files /dev/null and b/demos/shared/images/button_pressed_cap_left.png differ diff --git a/demos/shared/images/button_pressed_cap_right.png b/demos/shared/images/button_pressed_cap_right.png new file mode 100644 index 000000000..3d4cfe25b Binary files /dev/null and b/demos/shared/images/button_pressed_cap_right.png differ diff --git a/demos/shared/images/button_pressed_stretch.png b/demos/shared/images/button_pressed_stretch.png new file mode 100644 index 000000000..4dd4ad11e Binary files /dev/null and b/demos/shared/images/button_pressed_stretch.png differ diff --git a/demos/shared/images/curve_thing_edit-6.png b/demos/shared/images/curve_thing_edit-6.png new file mode 100644 index 000000000..034b474d0 Binary files /dev/null and b/demos/shared/images/curve_thing_edit-6.png differ diff --git a/demos/shared/images/frame_bottom.png b/demos/shared/images/frame_bottom.png new file mode 100644 index 000000000..889b40d30 Binary files /dev/null and b/demos/shared/images/frame_bottom.png differ diff --git a/demos/shared/images/frame_bottomleft.png b/demos/shared/images/frame_bottomleft.png new file mode 100644 index 000000000..0b3023f39 Binary files /dev/null and b/demos/shared/images/frame_bottomleft.png differ diff --git a/demos/shared/images/frame_bottomright.png b/demos/shared/images/frame_bottomright.png new file mode 100644 index 000000000..0021e3586 Binary files /dev/null and b/demos/shared/images/frame_bottomright.png differ diff --git a/demos/shared/images/frame_left.png b/demos/shared/images/frame_left.png new file mode 100644 index 000000000..40f331c29 Binary files /dev/null and b/demos/shared/images/frame_left.png differ diff --git a/demos/shared/images/frame_right.png b/demos/shared/images/frame_right.png new file mode 100644 index 000000000..023af8c70 Binary files /dev/null and b/demos/shared/images/frame_right.png differ diff --git a/demos/shared/images/frame_top.png b/demos/shared/images/frame_top.png new file mode 100644 index 000000000..001f3a714 Binary files /dev/null and b/demos/shared/images/frame_top.png differ diff --git a/demos/shared/images/frame_topleft.png b/demos/shared/images/frame_topleft.png new file mode 100644 index 000000000..58c68d407 Binary files /dev/null and b/demos/shared/images/frame_topleft.png differ diff --git a/demos/shared/images/frame_topright.png b/demos/shared/images/frame_topright.png new file mode 100644 index 000000000..6a7e8d3eb Binary files /dev/null and b/demos/shared/images/frame_topright.png differ diff --git a/demos/shared/images/groupframe_bottom_left.png b/demos/shared/images/groupframe_bottom_left.png new file mode 100644 index 000000000..af2fe061e Binary files /dev/null and b/demos/shared/images/groupframe_bottom_left.png differ diff --git a/demos/shared/images/groupframe_bottom_right.png b/demos/shared/images/groupframe_bottom_right.png new file mode 100644 index 000000000..fdf2e97b1 Binary files /dev/null and b/demos/shared/images/groupframe_bottom_right.png differ diff --git a/demos/shared/images/groupframe_bottom_stretch.png b/demos/shared/images/groupframe_bottom_stretch.png new file mode 100644 index 000000000..f47b67d7c Binary files /dev/null and b/demos/shared/images/groupframe_bottom_stretch.png differ diff --git a/demos/shared/images/groupframe_left_stretch.png b/demos/shared/images/groupframe_left_stretch.png new file mode 100644 index 000000000..c122f462e Binary files /dev/null and b/demos/shared/images/groupframe_left_stretch.png differ diff --git a/demos/shared/images/groupframe_right_stretch.png b/demos/shared/images/groupframe_right_stretch.png new file mode 100644 index 000000000..1056b7812 Binary files /dev/null and b/demos/shared/images/groupframe_right_stretch.png differ diff --git a/demos/shared/images/groupframe_top_stretch.png b/demos/shared/images/groupframe_top_stretch.png new file mode 100644 index 000000000..5746ef96f Binary files /dev/null and b/demos/shared/images/groupframe_top_stretch.png differ diff --git a/demos/shared/images/groupframe_topleft.png b/demos/shared/images/groupframe_topleft.png new file mode 100644 index 000000000..98d9cd96b Binary files /dev/null and b/demos/shared/images/groupframe_topleft.png differ diff --git a/demos/shared/images/groupframe_topright.png b/demos/shared/images/groupframe_topright.png new file mode 100644 index 000000000..1a0a328c2 Binary files /dev/null and b/demos/shared/images/groupframe_topright.png differ diff --git a/demos/shared/images/line_dash_dot.png b/demos/shared/images/line_dash_dot.png new file mode 100644 index 000000000..1c61442d9 Binary files /dev/null and b/demos/shared/images/line_dash_dot.png differ diff --git a/demos/shared/images/line_dash_dot_dot.png b/demos/shared/images/line_dash_dot_dot.png new file mode 100644 index 000000000..0d9bb972f Binary files /dev/null and b/demos/shared/images/line_dash_dot_dot.png differ diff --git a/demos/shared/images/line_dashed.png b/demos/shared/images/line_dashed.png new file mode 100644 index 000000000..d5bc7ea5f Binary files /dev/null and b/demos/shared/images/line_dashed.png differ diff --git a/demos/shared/images/line_dotted.png b/demos/shared/images/line_dotted.png new file mode 100644 index 000000000..a2f9a3592 Binary files /dev/null and b/demos/shared/images/line_dotted.png differ diff --git a/demos/shared/images/line_solid.png b/demos/shared/images/line_solid.png new file mode 100644 index 000000000..60ef3f948 Binary files /dev/null and b/demos/shared/images/line_solid.png differ diff --git a/demos/shared/images/radiobutton-off.png b/demos/shared/images/radiobutton-off.png new file mode 100644 index 000000000..af1753a3e Binary files /dev/null and b/demos/shared/images/radiobutton-off.png differ diff --git a/demos/shared/images/radiobutton-on.png b/demos/shared/images/radiobutton-on.png new file mode 100644 index 000000000..f875838bb Binary files /dev/null and b/demos/shared/images/radiobutton-on.png differ diff --git a/demos/shared/images/radiobutton_off.png b/demos/shared/images/radiobutton_off.png new file mode 100644 index 000000000..400906ebf Binary files /dev/null and b/demos/shared/images/radiobutton_off.png differ diff --git a/demos/shared/images/radiobutton_on.png b/demos/shared/images/radiobutton_on.png new file mode 100644 index 000000000..50a049ec5 Binary files /dev/null and b/demos/shared/images/radiobutton_on.png differ diff --git a/demos/shared/images/slider_bar.png b/demos/shared/images/slider_bar.png new file mode 100644 index 000000000..1b3d62c00 Binary files /dev/null and b/demos/shared/images/slider_bar.png differ diff --git a/demos/shared/images/slider_thumb_off.png b/demos/shared/images/slider_thumb_off.png new file mode 100644 index 000000000..d7f141dae Binary files /dev/null and b/demos/shared/images/slider_thumb_off.png differ diff --git a/demos/shared/images/slider_thumb_on.png b/demos/shared/images/slider_thumb_on.png new file mode 100644 index 000000000..8e1f51081 Binary files /dev/null and b/demos/shared/images/slider_thumb_on.png differ diff --git a/demos/shared/images/title_cap_left.png b/demos/shared/images/title_cap_left.png new file mode 100644 index 000000000..2d475070c Binary files /dev/null and b/demos/shared/images/title_cap_left.png differ diff --git a/demos/shared/images/title_cap_right.png b/demos/shared/images/title_cap_right.png new file mode 100644 index 000000000..dc3ff8536 Binary files /dev/null and b/demos/shared/images/title_cap_right.png differ diff --git a/demos/shared/images/title_stretch.png b/demos/shared/images/title_stretch.png new file mode 100644 index 000000000..11043345d Binary files /dev/null and b/demos/shared/images/title_stretch.png differ diff --git a/demos/shared/shared.pri b/demos/shared/shared.pri new file mode 100644 index 000000000..fb7b04c0b --- /dev/null +++ b/demos/shared/shared.pri @@ -0,0 +1,21 @@ +INCLUDEPATH += $$SHARED_FOLDER + +build_all:!build_pass { + CONFIG -= build_all + CONFIG += release +} +contains(CONFIG, debug_and_release_target) { + CONFIG(debug, debug|release) { + QMAKE_LIBDIR += $$SHARED_FOLDER/debug + } else { + QMAKE_LIBDIR += $$SHARED_FOLDER/release + } +} else { + QMAKE_LIBDIR += $$SHARED_FOLDER +} + +hpux-acc*:LIBS += $$SHARED_FOLDER/libdemo_shared.a +hpuxi-acc*:LIBS += $$SHARED_FOLDER/libdemo_shared.a +symbian:LIBS += -ldemo_shared.lib +!hpuxi-acc*:!hpux-acc*:!symbian:LIBS += -ldemo_shared + diff --git a/demos/shared/shared.pro b/demos/shared/shared.pro new file mode 100644 index 000000000..ab31b32b5 --- /dev/null +++ b/demos/shared/shared.pro @@ -0,0 +1,38 @@ +TEMPLATE = lib +CONFIG += static + +contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, opengles2) { + DEFINES += QT_OPENGL_SUPPORT + QT += opengl +} + +build_all:!build_pass { + CONFIG -= build_all + CONFIG += release +} +TARGET = demo_shared + +SOURCES += \ + arthurstyle.cpp\ + arthurwidgets.cpp \ + hoverpoints.cpp + +HEADERS += \ + arthurstyle.h \ + arthurwidgets.h \ + hoverpoints.h + +RESOURCES += shared.qrc + +# install +target.path = $$[QT_INSTALL_DEMOS]/qttools/shared +sources.files = $$SOURCES $$HEADERS $$RESOURCES *.pro *.pri images +sources.path = $$[QT_INSTALL_DEMOS]/qttools/shared +INSTALLS += sources + +!cross_compile:INSTALLS += target + +symbian { + TARGET.UID3 = 0xA000A63C + include($$QT_SOURCE_TREE/demos/symbianpkgrules.pri) +} diff --git a/demos/shared/shared.qrc b/demos/shared/shared.qrc new file mode 100644 index 000000000..17336ecf8 --- /dev/null +++ b/demos/shared/shared.qrc @@ -0,0 +1,39 @@ + + + images/button_normal_cap_left.png + images/button_normal_cap_right.png + images/button_normal_stretch.png + images/button_pressed_cap_left.png + images/button_pressed_cap_right.png + images/button_pressed_stretch.png + images/radiobutton-on.png + images/radiobutton_on.png + images/radiobutton_off.png + images/slider_bar.png + images/slider_thumb_on.png + images/groupframe_topleft.png + images/groupframe_topright.png + images/groupframe_bottom_left.png + images/groupframe_bottom_right.png + images/groupframe_top_stretch.png + images/groupframe_bottom_stretch.png + images/groupframe_left_stretch.png + images/groupframe_right_stretch.png + images/frame_topleft.png + images/frame_topright.png + images/frame_bottomleft.png + images/frame_bottomright.png + images/frame_left.png + images/frame_top.png + images/frame_right.png + images/frame_bottom.png + images/title_cap_left.png + images/title_cap_right.png + images/title_stretch.png + images/line_dash_dot.png + images/line_dotted.png + images/line_dashed.png + images/line_solid.png + images/line_dash_dot_dot.png + + diff --git a/examples/designer/README b/examples/designer/README new file mode 100644 index 000000000..fb9443cae --- /dev/null +++ b/examples/designer/README @@ -0,0 +1,37 @@ +Qt Designer is a capable graphical user interface designer that lets you +create and configure forms without writing code. GUIs created with +Qt Designer can be compiled into an application or created at run-time. + + +Some of the examples in this directory can be run from the example launcher; +others can only be used from within Qt Designer. + +Documentation for these examples can be found via the "Tutorial and Examples" +link in the main Qt documentation. + +Finding the Qt Examples and Demos launcher +========================================== + +On Windows: + +The launcher can be accessed via the Windows Start menu. Select the menu +entry entitled "Qt Examples and Demos" entry in the submenu containing +the Qt tools. + +On Mac OS X: + +For the binary distribution, the qtdemo executable is installed in the +/Developer/Applications/Qt directory. For the source distribution, it is +installed alongside the other Qt tools on the path specified when Qt is +configured. + +On Unix/Linux: + +The qtdemo executable is installed alongside the other Qt tools on the path +specified when Qt is configured. + +On all platforms: + +The source code for the launcher can be found in the demos/qtdemo directory +in the Qt package. This example is built at the same time as the Qt libraries, +tools, examples, and demonstrations. diff --git a/examples/designer/calculatorbuilder/calculatorbuilder.pro b/examples/designer/calculatorbuilder/calculatorbuilder.pro new file mode 100644 index 000000000..ca4a3ea15 --- /dev/null +++ b/examples/designer/calculatorbuilder/calculatorbuilder.pro @@ -0,0 +1,16 @@ +#! [0] +CONFIG += uitools + +HEADERS = calculatorform.h +RESOURCES = calculatorbuilder.qrc +SOURCES = calculatorform.cpp \ + main.cpp +#! [0] + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/qttools/designer/calculatorbuilder +sources.files = $$SOURCES $$HEADERS $$RESOURCES *.ui *.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/qttools/designer/calculatorbuilder +INSTALLS += target sources + +symbian: include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) diff --git a/examples/designer/calculatorbuilder/calculatorbuilder.qrc b/examples/designer/calculatorbuilder/calculatorbuilder.qrc new file mode 100644 index 000000000..19b39059e --- /dev/null +++ b/examples/designer/calculatorbuilder/calculatorbuilder.qrc @@ -0,0 +1,5 @@ + + + calculatorform.ui + + diff --git a/examples/designer/calculatorbuilder/calculatorform.cpp b/examples/designer/calculatorbuilder/calculatorform.cpp new file mode 100644 index 000000000..e14efa497 --- /dev/null +++ b/examples/designer/calculatorbuilder/calculatorform.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] +#include +//! [0] +#include + +#include "calculatorform.h" + +//! [1] +CalculatorForm::CalculatorForm(QWidget *parent) + : QWidget(parent) +{ + QUiLoader loader; + + QFile file(":/forms/calculatorform.ui"); + file.open(QFile::ReadOnly); + QWidget *formWidget = loader.load(&file, this); + file.close(); +//! [1] + +//! [2] + ui_inputSpinBox1 = findChild("inputSpinBox1"); + ui_inputSpinBox2 = findChild("inputSpinBox2"); + ui_outputWidget = findChild("outputWidget"); +//! [2] + +//! [3] + QMetaObject::connectSlotsByName(this); +//! [3] + +//! [4] + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(formWidget); + setLayout(layout); + + setWindowTitle(tr("Calculator Builder")); +} +//! [4] + +//! [5] +void CalculatorForm::on_inputSpinBox1_valueChanged(int value) +{ + ui_outputWidget->setText(QString::number(value + ui_inputSpinBox2->value())); +} +//! [5] //! [6] + +//! [6] //! [7] +void CalculatorForm::on_inputSpinBox2_valueChanged(int value) +{ + ui_outputWidget->setText(QString::number(value + ui_inputSpinBox1->value())); +} +//! [7] diff --git a/examples/designer/calculatorbuilder/calculatorform.h b/examples/designer/calculatorbuilder/calculatorform.h new file mode 100644 index 000000000..f891823fc --- /dev/null +++ b/examples/designer/calculatorbuilder/calculatorform.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CALCULATORFORM_H +#define CALCULATORFORM_H + +#include + +QT_BEGIN_NAMESPACE +class QLabel; +class QSpinBox; +QT_END_NAMESPACE + +//! [0] +class CalculatorForm : public QWidget +{ + Q_OBJECT + +public: + CalculatorForm(QWidget *parent = 0); + +private slots: + void on_inputSpinBox1_valueChanged(int value); + void on_inputSpinBox2_valueChanged(int value); + +private: + QSpinBox *ui_inputSpinBox1; + QSpinBox *ui_inputSpinBox2; + QLabel *ui_outputWidget; +}; +//! [0] + +#endif diff --git a/examples/designer/calculatorbuilder/calculatorform.ui b/examples/designer/calculatorbuilder/calculatorform.ui new file mode 100644 index 000000000..dda0e62dd --- /dev/null +++ b/examples/designer/calculatorbuilder/calculatorform.ui @@ -0,0 +1,303 @@ + + + + + CalculatorForm + + + CalculatorForm + + + + 0 + 0 + 276 + 98 + + + + + 5 + 5 + 0 + 0 + + + + Calculator Builder + + + + + + + 9 + + + 6 + + + + + + + + 1 + + + 6 + + + + + + + + 1 + + + 6 + + + + + label + + + + 1 + 1 + 45 + 19 + + + + Input 1 + + + + + + + inputSpinBox1 + + + + 1 + 26 + 45 + 25 + + + + true + + + + + + + + + label_3 + + + + 54 + 1 + 7 + 52 + + + + + + + + Qt::AlignCenter + + + + + + + + + + 1 + + + 6 + + + + + label_2 + + + + 1 + 1 + 45 + 19 + + + + Input 2 + + + + + + + inputSpinBox2 + + + + 1 + 26 + 45 + 25 + + + + true + + + + + + + + + label_3_2 + + + + 120 + 1 + 7 + 52 + + + + = + + + Qt::AlignCenter + + + + + + + + + + 1 + + + 6 + + + + + label_2_2_2 + + + + 1 + 1 + 37 + 17 + + + + Output + + + + + + + outputWidget + + + + 1 + 24 + 37 + 27 + + + + QFrame::Box + + + QFrame::Sunken + + + 0 + + + Qt::AlignAbsolute|Qt::AlignBottom|Qt::AlignCenter|Qt::AlignHCenter|Qt::AlignHorizontal_Mask|Qt::AlignJustify|Qt::AlignLeading|Qt::AlignLeft|Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing|Qt::AlignVCenter|Qt::AlignVertical_Mask + + + + + + + + + + + verticalSpacer + + + + 85 + 69 + 20 + 20 + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + horizontalSpacer + + + + 188 + 26 + 79 + 20 + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + diff --git a/examples/designer/calculatorbuilder/main.cpp b/examples/designer/calculatorbuilder/main.cpp new file mode 100644 index 000000000..b5cab6bad --- /dev/null +++ b/examples/designer/calculatorbuilder/main.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "calculatorform.h" + +int main(int argc, char *argv[]) +{ + Q_INIT_RESOURCE(calculatorbuilder); + + QApplication app(argc, argv); + CalculatorForm calculator; + calculator.show(); + return app.exec(); +} diff --git a/examples/designer/calculatorform/calculatorform.cpp b/examples/designer/calculatorform/calculatorform.cpp new file mode 100644 index 000000000..ef9022f1f --- /dev/null +++ b/examples/designer/calculatorform/calculatorform.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "calculatorform.h" + +//! [0] +CalculatorForm::CalculatorForm(QWidget *parent) + : QWidget(parent) +{ + ui.setupUi(this); +} +//! [0] + +//! [1] +void CalculatorForm::on_inputSpinBox1_valueChanged(int value) +{ + ui.outputWidget->setText(QString::number(value + ui.inputSpinBox2->value())); +} +//! [1] + +//! [2] +void CalculatorForm::on_inputSpinBox2_valueChanged(int value) +{ + ui.outputWidget->setText(QString::number(value + ui.inputSpinBox1->value())); +} +//! [2] diff --git a/examples/designer/calculatorform/calculatorform.h b/examples/designer/calculatorform/calculatorform.h new file mode 100644 index 000000000..940699571 --- /dev/null +++ b/examples/designer/calculatorform/calculatorform.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CALCULATORFORM_H +#define CALCULATORFORM_H + +//! [0] +#include "ui_calculatorform.h" +//! [0] + +//! [1] +class CalculatorForm : public QWidget +{ + Q_OBJECT + +public: + CalculatorForm(QWidget *parent = 0); + +private slots: + void on_inputSpinBox1_valueChanged(int value); + void on_inputSpinBox2_valueChanged(int value); + +private: + Ui::CalculatorForm ui; +}; +//! [1] + +#endif diff --git a/examples/designer/calculatorform/calculatorform.pro b/examples/designer/calculatorform/calculatorform.pro new file mode 100644 index 000000000..65a8cfe6f --- /dev/null +++ b/examples/designer/calculatorform/calculatorform.pro @@ -0,0 +1,15 @@ +#! [0] +HEADERS = calculatorform.h +#! [0] #! [1] +FORMS = calculatorform.ui +#! [1] +SOURCES = calculatorform.cpp \ + main.cpp + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/qttools/designer/calculatorform +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS *.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/qttools/designer/calculatorform +INSTALLS += target sources + +symbian: include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) diff --git a/examples/designer/calculatorform/calculatorform.ui b/examples/designer/calculatorform/calculatorform.ui new file mode 100644 index 000000000..3a956399a --- /dev/null +++ b/examples/designer/calculatorform/calculatorform.ui @@ -0,0 +1,284 @@ + + + + + CalculatorForm + + + CalculatorForm + + + + 0 + 0 + 400 + 300 + + + + + 5 + 5 + 0 + 0 + + + + Calculator Form + + + + + + + 9 + + + 6 + + + + + horizontalSpacer + + + + 239 + 9 + 152 + 52 + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + label_3_2 + + + + 169 + 9 + 20 + 52 + + + + = + + + Qt::AlignCenter + + + + + + + + + + 1 + + + 6 + + + + + label_2_2_2 + + + + 1 + 1 + 36 + 17 + + + + Output + + + + + + + outputWidget + + + + 1 + 24 + 36 + 27 + + + + QFrame::Box + + + QFrame::Sunken + + + 0 + + + Qt::AlignAbsolute|Qt::AlignBottom|Qt::AlignCenter|Qt::AlignHCenter|Qt::AlignHorizontal_Mask|Qt::AlignJustify|Qt::AlignLeading|Qt::AlignLeft|Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing|Qt::AlignVCenter|Qt::AlignVertical_Mask + + + + + + + + + verticalSpacer + + + + 89 + 67 + 20 + 224 + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + 1 + + + 6 + + + + + label_2 + + + + 1 + 1 + 46 + 19 + + + + Input 2 + + + + + + + inputSpinBox2 + + + + 1 + 26 + 46 + 25 + + + + + + + + + + label_3 + + + + 63 + 9 + 20 + 52 + + + + + + + + Qt::AlignCenter + + + + + + + + + + 1 + + + 6 + + + + + label + + + + 1 + 1 + 46 + 19 + + + + Input 1 + + + + + + + inputSpinBox1 + + + + 1 + 26 + 46 + 25 + + + + + + + + + + + + diff --git a/examples/designer/calculatorform/main.cpp b/examples/designer/calculatorform/main.cpp new file mode 100644 index 000000000..2dd1fc11d --- /dev/null +++ b/examples/designer/calculatorform/main.cpp @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "calculatorform.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + CalculatorForm calculator; + calculator.show(); + return app.exec(); +} + diff --git a/examples/designer/containerextension/containerextension.pro b/examples/designer/containerextension/containerextension.pro new file mode 100644 index 000000000..6ded91737 --- /dev/null +++ b/examples/designer/containerextension/containerextension.pro @@ -0,0 +1,28 @@ +#! [0] +TEMPLATE = lib +#! [0] +TARGET = $$qtLibraryTarget($$TARGET) +#! [1] +CONFIG += designer plugin +#! [1] +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/designer + +#! [2] +HEADERS += multipagewidget.h \ + multipagewidgetplugin.h \ + multipagewidgetcontainerextension.h \ + multipagewidgetextensionfactory.h + +SOURCES += multipagewidget.cpp \ + multipagewidgetplugin.cpp \ + multipagewidgetcontainerextension.cpp \ + multipagewidgetextensionfactory.cpp +#! [2] + +# install +target.path = $$[QT_INSTALL_PLUGINS]/designer +sources.files = $$SOURCES $$HEADERS *.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/qttools/designer/containerextension +INSTALLS += target sources + +symbian: include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) diff --git a/examples/designer/containerextension/multipagewidget.cpp b/examples/designer/containerextension/multipagewidget.cpp new file mode 100644 index 000000000..5b44f36d2 --- /dev/null +++ b/examples/designer/containerextension/multipagewidget.cpp @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "multipagewidget.h" + +MultiPageWidget::MultiPageWidget(QWidget *parent) + : QWidget(parent) +{ + comboBox = new QComboBox(); + comboBox->setObjectName("__qt__passive_comboBox"); + stackWidget = new QStackedWidget(); + + connect(comboBox, SIGNAL(activated(int)), + this, SLOT(setCurrentIndex(int))); + + layout = new QVBoxLayout(); + layout->addWidget(comboBox); + layout->addWidget(stackWidget); + setLayout(layout); +} + +QSize MultiPageWidget::sizeHint() const +{ + return QSize(200, 150); +} + +void MultiPageWidget::addPage(QWidget *page) +{ + insertPage(count(), page); +} + +void MultiPageWidget::removePage(int index) +{ + QWidget *widget = stackWidget->widget(index); + stackWidget->removeWidget(widget); + + comboBox->removeItem(index); +} + +int MultiPageWidget::count() const +{ + return stackWidget->count(); +} + +int MultiPageWidget::currentIndex() const +{ + return stackWidget->currentIndex(); +} + +void MultiPageWidget::insertPage(int index, QWidget *page) +{ + page->setParent(stackWidget); + + stackWidget->insertWidget(index, page); + + QString title = page->windowTitle(); + if (title.isEmpty()) { + title = tr("Page %1").arg(comboBox->count() + 1); + page->setWindowTitle(title); + } + comboBox->insertItem(index, title); +} + +void MultiPageWidget::setCurrentIndex(int index) +{ + if (index != currentIndex()) { + stackWidget->setCurrentIndex(index); + comboBox->setCurrentIndex(index); + emit currentIndexChanged(index); + } +} + +QWidget* MultiPageWidget::widget(int index) +{ + return stackWidget->widget(index); +} + +QString MultiPageWidget::pageTitle() const +{ + if (const QWidget *currentWidget = stackWidget->currentWidget()) + return currentWidget->windowTitle(); + return QString(); +} + +void MultiPageWidget::setPageTitle(QString const &newTitle) +{ + comboBox->setItemText(currentIndex(), newTitle); + if (QWidget *currentWidget = stackWidget->currentWidget()) + currentWidget->setWindowTitle(newTitle); + emit pageTitleChanged(newTitle); +} diff --git a/examples/designer/containerextension/multipagewidget.h b/examples/designer/containerextension/multipagewidget.h new file mode 100644 index 000000000..b2f3b7d5d --- /dev/null +++ b/examples/designer/containerextension/multipagewidget.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MULTIPAGEWIDGET_H +#define MULTIPAGEWIDGET_H + +#include + +QT_BEGIN_NAMESPACE +class QComboBox; +class QStackedWidget; +class QVBoxLayout; +QT_END_NAMESPACE + +//! [0] +class MultiPageWidget : public QWidget +{ + Q_OBJECT + Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex) + Q_PROPERTY(QString pageTitle READ pageTitle WRITE setPageTitle STORED false) + +public: + MultiPageWidget(QWidget *parent = 0); + + QSize sizeHint() const; + + int count() const; + int currentIndex() const; + QWidget *widget(int index); + QString pageTitle() const; + +public slots: + void addPage(QWidget *page); + void insertPage(int index, QWidget *page); + void removePage(int index); + void setPageTitle(QString const &newTitle); + void setCurrentIndex(int index); + +signals: + void currentIndexChanged(int index); + void pageTitleChanged(const QString &title); + +private: + QStackedWidget *stackWidget; + QComboBox *comboBox; + QVBoxLayout *layout; +}; +//! [0] + +#endif diff --git a/examples/designer/containerextension/multipagewidgetcontainerextension.cpp b/examples/designer/containerextension/multipagewidgetcontainerextension.cpp new file mode 100644 index 000000000..fe815341a --- /dev/null +++ b/examples/designer/containerextension/multipagewidgetcontainerextension.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "multipagewidgetcontainerextension.h" +#include "multipagewidget.h" + +//! [0] +MultiPageWidgetContainerExtension::MultiPageWidgetContainerExtension(MultiPageWidget *widget, + QObject *parent) + :QObject(parent) +{ + myWidget = widget; +} +//! [0] + +//! [1] +void MultiPageWidgetContainerExtension::addWidget(QWidget *widget) +{ + myWidget->addPage(widget); +} +//! [1] + +//! [2] +int MultiPageWidgetContainerExtension::count() const +{ + return myWidget->count(); +} +//! [2] + +//! [3] +int MultiPageWidgetContainerExtension::currentIndex() const +{ + return myWidget->currentIndex(); +} +//! [3] + +//! [4] +void MultiPageWidgetContainerExtension::insertWidget(int index, QWidget *widget) +{ + myWidget->insertPage(index, widget); +} +//! [4] + +//! [5] +void MultiPageWidgetContainerExtension::remove(int index) +{ + myWidget->removePage(index); +} +//! [5] + +//! [6] +void MultiPageWidgetContainerExtension::setCurrentIndex(int index) +{ + myWidget->setCurrentIndex(index); +} +//! [6] + +//! [7] +QWidget* MultiPageWidgetContainerExtension::widget(int index) const +{ + return myWidget->widget(index); +} +//! [7] diff --git a/examples/designer/containerextension/multipagewidgetcontainerextension.h b/examples/designer/containerextension/multipagewidgetcontainerextension.h new file mode 100644 index 000000000..dfb10c625 --- /dev/null +++ b/examples/designer/containerextension/multipagewidgetcontainerextension.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MULTIPAGEWIDGETCONTAINEREXTENSION_H +#define MULTIPAGEWIDGETCONTAINEREXTENSION_H + +#include + +QT_BEGIN_NAMESPACE +class QExtensionManager; +QT_END_NAMESPACE +class MultiPageWidget; + +//! [0] +class MultiPageWidgetContainerExtension: public QObject, + public QDesignerContainerExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerContainerExtension) + +public: + MultiPageWidgetContainerExtension(MultiPageWidget *widget, QObject *parent); + + void addWidget(QWidget *widget); + int count() const; + int currentIndex() const; + void insertWidget(int index, QWidget *widget); + void remove(int index); + void setCurrentIndex(int index); + QWidget *widget(int index) const; + +private: + MultiPageWidget *myWidget; +}; +//! [0] + +#endif diff --git a/examples/designer/containerextension/multipagewidgetextensionfactory.cpp b/examples/designer/containerextension/multipagewidgetextensionfactory.cpp new file mode 100644 index 000000000..36f3c8f46 --- /dev/null +++ b/examples/designer/containerextension/multipagewidgetextensionfactory.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "multipagewidgetextensionfactory.h" +#include "multipagewidgetcontainerextension.h" +#include "multipagewidget.h" + +//! [0] +MultiPageWidgetExtensionFactory::MultiPageWidgetExtensionFactory(QExtensionManager *parent) + : QExtensionFactory(parent) +{} +//! [0] + +//! [1] +QObject *MultiPageWidgetExtensionFactory::createExtension(QObject *object, + const QString &iid, + QObject *parent) const +{ + MultiPageWidget *widget = qobject_cast(object); + + if (widget && (iid == Q_TYPEID(QDesignerContainerExtension))) { + return new MultiPageWidgetContainerExtension(widget, parent); + } else { + return 0; + } +} +//! [1] diff --git a/examples/designer/containerextension/multipagewidgetextensionfactory.h b/examples/designer/containerextension/multipagewidgetextensionfactory.h new file mode 100644 index 000000000..2ed2946f6 --- /dev/null +++ b/examples/designer/containerextension/multipagewidgetextensionfactory.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MULTIPAGEWIDGETEXTENSIONFACTORY_H +#define MULTIPAGEWIDGETEXTENSIONFACTORY_H + +#include + +QT_BEGIN_NAMESPACE +class QExtensionManager; +QT_END_NAMESPACE + +//! [0] +class MultiPageWidgetExtensionFactory: public QExtensionFactory +{ + Q_OBJECT + +public: + MultiPageWidgetExtensionFactory(QExtensionManager *parent = 0); + +protected: + QObject *createExtension(QObject *object, const QString &iid, QObject *parent) const; +}; +//! [0] + +#endif diff --git a/examples/designer/containerextension/multipagewidgetplugin.cpp b/examples/designer/containerextension/multipagewidgetplugin.cpp new file mode 100644 index 000000000..60aab4fea --- /dev/null +++ b/examples/designer/containerextension/multipagewidgetplugin.cpp @@ -0,0 +1,196 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "multipagewidget.h" +#include "multipagewidgetplugin.h" +#include "multipagewidgetextensionfactory.h" + +//! [0] +MultiPageWidgetPlugin::MultiPageWidgetPlugin(QObject *parent) + :QObject(parent) +{ + initialized = false; +} + +QString MultiPageWidgetPlugin::name() const +{ + return QLatin1String("MultiPageWidget"); +} + +QString MultiPageWidgetPlugin::group() const +{ + return QLatin1String("Display Widgets [Examples]"); +} + +QString MultiPageWidgetPlugin::toolTip() const +{ + return QString(); +} + +QString MultiPageWidgetPlugin::whatsThis() const +{ + return QString(); +} + +QString MultiPageWidgetPlugin::includeFile() const +{ + return QLatin1String("multipagewidget.h"); +} + +QIcon MultiPageWidgetPlugin::icon() const +{ + return QIcon(); +} + +//! [0] //! [1] +bool MultiPageWidgetPlugin::isContainer() const +{ + return true; +} + +//! [1] //! [2] +QWidget *MultiPageWidgetPlugin::createWidget(QWidget *parent) +{ + MultiPageWidget *widget = new MultiPageWidget(parent); + connect(widget, SIGNAL(currentIndexChanged(int)), + this, SLOT(currentIndexChanged(int))); + connect(widget, SIGNAL(pageTitleChanged(QString)), + this, SLOT(pageTitleChanged(QString))); + return widget; +} + +//! [2] //! [3] +bool MultiPageWidgetPlugin::isInitialized() const +{ + return initialized; +} +//! [3] + +//! [4] +void MultiPageWidgetPlugin::initialize(QDesignerFormEditorInterface *formEditor) +{ + if (initialized) + return; +//! [4] + +//! [5] + QExtensionManager *manager = formEditor->extensionManager(); +//! [5] //! [6] + QExtensionFactory *factory = new MultiPageWidgetExtensionFactory(manager); + + Q_ASSERT(manager != 0); + manager->registerExtensions(factory, Q_TYPEID(QDesignerContainerExtension)); + + initialized = true; +} +//! [6] + +//! [7] +QString MultiPageWidgetPlugin::domXml() const +{ + return QLatin1String("\ +\ + \ + \ + \ + \ + \ + MultiPageWidget\ + QWidget\ + addPage\ + \ + \ +"); +} +//! [7] + +//! [8] +void MultiPageWidgetPlugin::currentIndexChanged(int index) +{ + Q_UNUSED(index); + MultiPageWidget *widget = qobject_cast(sender()); +//! [8] //! [9] + if (widget) { + QDesignerFormWindowInterface *form = QDesignerFormWindowInterface::findFormWindow(widget); + if (form) + form->emitSelectionChanged(); + } +} +//! [9] + +//! [10] +void MultiPageWidgetPlugin::pageTitleChanged(const QString &title) +{ + Q_UNUSED(title); + MultiPageWidget *widget = qobject_cast(sender()); +//! [10] //! [11] + if (widget) { + QWidget *page = widget->widget(widget->currentIndex()); + QDesignerFormWindowInterface *form; + form = QDesignerFormWindowInterface::findFormWindow(widget); +//! [11] + if (form) { +//! [12] + QDesignerFormEditorInterface *editor = form->core(); + QExtensionManager *manager = editor->extensionManager(); +//! [12] //! [13] + QDesignerPropertySheetExtension *sheet; + sheet = qt_extension(manager, page); + const int propertyIndex = sheet->indexOf(QLatin1String("windowTitle")); + sheet->setChanged(propertyIndex, true); + } + } +} + +//! [13] + +//! [14] +Q_EXPORT_PLUGIN2(containerextension, MultiPageWidgetPlugin) +//! [14] diff --git a/examples/designer/containerextension/multipagewidgetplugin.h b/examples/designer/containerextension/multipagewidgetplugin.h new file mode 100644 index 000000000..3d9ac52bf --- /dev/null +++ b/examples/designer/containerextension/multipagewidgetplugin.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] +#ifndef MULTIPAGEWIDGETPLUGIN_H +#define MULTIPAGEWIDGETPLUGIN_H + +#include + +QT_BEGIN_NAMESPACE +class QIcon; +class QWidget; +QT_END_NAMESPACE + +class MultiPageWidgetPlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) +public: + MultiPageWidgetPlugin(QObject *parent = 0); + + QString name() const; + QString group() const; + QString toolTip() const; + QString whatsThis() const; + QString includeFile() const; + QIcon icon() const; + bool isContainer() const; + QWidget *createWidget(QWidget *parent); + bool isInitialized() const; + void initialize(QDesignerFormEditorInterface *formEditor); + QString domXml() const; + +private slots: + void currentIndexChanged(int index); + void pageTitleChanged(const QString &title); + +private: + bool initialized; +}; + +#endif +//! [0] diff --git a/examples/designer/customwidgetplugin/analogclock.cpp b/examples/designer/customwidgetplugin/analogclock.cpp new file mode 100644 index 000000000..4a91e0dc0 --- /dev/null +++ b/examples/designer/customwidgetplugin/analogclock.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "analogclock.h" + +AnalogClock::AnalogClock(QWidget *parent) + : QWidget(parent) +{ + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(update())); + timer->start(1000); + + setWindowTitle(tr("Analog Clock")); + resize(200, 200); +} + +void AnalogClock::paintEvent(QPaintEvent *) +{ + static const QPoint hourHand[3] = { + QPoint(7, 8), + QPoint(-7, 8), + QPoint(0, -40) + }; + static const QPoint minuteHand[3] = { + QPoint(7, 8), + QPoint(-7, 8), + QPoint(0, -70) + }; + + QColor hourColor(127, 0, 127); + QColor minuteColor(0, 127, 127, 191); + + int side = qMin(width(), height()); + QTime time = QTime::currentTime(); + + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + painter.translate(width() / 2, height() / 2); + painter.scale(side / 200.0, side / 200.0); + + painter.setPen(Qt::NoPen); + painter.setBrush(hourColor); + + painter.save(); + painter.rotate(30.0 * ((time.hour() + time.minute() / 60.0))); + painter.drawConvexPolygon(hourHand, 3); + painter.restore(); + + painter.setPen(hourColor); + + for (int i = 0; i < 12; ++i) { + painter.drawLine(88, 0, 96, 0); + painter.rotate(30.0); + } + + painter.setPen(Qt::NoPen); + painter.setBrush(minuteColor); + + painter.save(); + painter.rotate(6.0 * (time.minute() + time.second() / 60.0)); + painter.drawConvexPolygon(minuteHand, 3); + painter.restore(); + + painter.setPen(minuteColor); + + for (int j = 0; j < 60; ++j) { + if ((j % 5) != 0) + painter.drawLine(92, 0, 96, 0); + painter.rotate(6.0); + } +} diff --git a/examples/designer/customwidgetplugin/analogclock.h b/examples/designer/customwidgetplugin/analogclock.h new file mode 100644 index 000000000..db42d5af3 --- /dev/null +++ b/examples/designer/customwidgetplugin/analogclock.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ANALOGCLOCK_H +#define ANALOGCLOCK_H + +#include +#include + +class QDESIGNER_WIDGET_EXPORT AnalogClock : public QWidget +{ + Q_OBJECT + +public: + AnalogClock(QWidget *parent = 0); + +protected: + void paintEvent(QPaintEvent *event); +}; + +#endif diff --git a/examples/designer/customwidgetplugin/customwidgetplugin.cpp b/examples/designer/customwidgetplugin/customwidgetplugin.cpp new file mode 100644 index 000000000..d6ab592d2 --- /dev/null +++ b/examples/designer/customwidgetplugin/customwidgetplugin.cpp @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "analogclock.h" +#include "customwidgetplugin.h" + +#include + +//! [0] +AnalogClockPlugin::AnalogClockPlugin(QObject *parent) + : QObject(parent) +{ + initialized = false; +} +//! [0] + +//! [1] +void AnalogClockPlugin::initialize(QDesignerFormEditorInterface * /* core */) +{ + if (initialized) + return; + + initialized = true; +} +//! [1] + +//! [2] +bool AnalogClockPlugin::isInitialized() const +{ + return initialized; +} +//! [2] + +//! [3] +QWidget *AnalogClockPlugin::createWidget(QWidget *parent) +{ + return new AnalogClock(parent); +} +//! [3] + +//! [4] +QString AnalogClockPlugin::name() const +{ + return "AnalogClock"; +} +//! [4] + +//! [5] +QString AnalogClockPlugin::group() const +{ + return "Display Widgets [Examples]"; +} +//! [5] + +//! [6] +QIcon AnalogClockPlugin::icon() const +{ + return QIcon(); +} +//! [6] + +//! [7] +QString AnalogClockPlugin::toolTip() const +{ + return ""; +} +//! [7] + +//! [8] +QString AnalogClockPlugin::whatsThis() const +{ + return ""; +} +//! [8] + +//! [9] +bool AnalogClockPlugin::isContainer() const +{ + return false; +} +//! [9] + +//! [10] +QString AnalogClockPlugin::domXml() const +{ + return "\n" + " \n" +//! [11] + " \n" + " \n" + " 0\n" + " 0\n" + " 100\n" + " 100\n" + " \n" + " \n" +//! [11] + " \n" + " The current time\n" + " \n" + " \n" + " The analog clock widget displays the current time.\n" + " \n" + " \n" + "\n"; +} +//! [10] + +//! [12] +QString AnalogClockPlugin::includeFile() const +{ + return "analogclock.h"; +} +//! [12] + +//! [13] +Q_EXPORT_PLUGIN2(customwidgetplugin, AnalogClockPlugin) +//! [13] diff --git a/examples/designer/customwidgetplugin/customwidgetplugin.h b/examples/designer/customwidgetplugin/customwidgetplugin.h new file mode 100644 index 000000000..72f916b25 --- /dev/null +++ b/examples/designer/customwidgetplugin/customwidgetplugin.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CUSTOMWIDGETPLUGIN_H +#define CUSTOMWIDGETPLUGIN_H + +#include + +//! [0] +class AnalogClockPlugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + AnalogClockPlugin(QObject *parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget *createWidget(QWidget *parent); + void initialize(QDesignerFormEditorInterface *core); + +private: + bool initialized; +}; +//! [0] + +#endif diff --git a/examples/designer/customwidgetplugin/customwidgetplugin.pro b/examples/designer/customwidgetplugin/customwidgetplugin.pro new file mode 100644 index 000000000..0d37874b7 --- /dev/null +++ b/examples/designer/customwidgetplugin/customwidgetplugin.pro @@ -0,0 +1,23 @@ +#! [0] #! [1] +CONFIG += designer plugin +#! [0] +TARGET = $$qtLibraryTarget($$TARGET) +#! [2] +TEMPLATE = lib +#! [1] #! [2] +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/designer + +#! [3] +HEADERS = analogclock.h \ + customwidgetplugin.h +SOURCES = analogclock.cpp \ + customwidgetplugin.cpp +#! [3] + +# install +target.path = $$[QT_INSTALL_PLUGINS]/designer +sources.files = $$SOURCES $$HEADERS *.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/qttools/designer/customwidgetplugin +INSTALLS += target sources + +symbian: include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) diff --git a/examples/designer/designer.pro b/examples/designer/designer.pro new file mode 100644 index 000000000..0c1d637c8 --- /dev/null +++ b/examples/designer/designer.pro @@ -0,0 +1,21 @@ +TEMPLATE = subdirs +SUBDIRS = calculatorform + +!static:SUBDIRS += calculatorbuilder \ + containerextension \ + customwidgetplugin \ + taskmenuextension \ + worldtimeclockbuilder \ + worldtimeclockplugin + +# the sun cc compiler has a problem with the include lines for the form.prf +solaris-cc*:SUBDIRS -= calculatorbuilder \ + worldtimeclockbuilder + + +# install +sources.files = README *.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/qttools/designer +INSTALLS += sources + +symbian: include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) diff --git a/examples/designer/taskmenuextension/taskmenuextension.pro b/examples/designer/taskmenuextension/taskmenuextension.pro new file mode 100644 index 000000000..ab0b36d2b --- /dev/null +++ b/examples/designer/taskmenuextension/taskmenuextension.pro @@ -0,0 +1,27 @@ +#! [0] +TEMPLATE = lib +#! [0] +TARGET = $$qtLibraryTarget($$TARGET) +#! [1] +CONFIG += designer plugin +#! [1] +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/designer + +#! [2] +HEADERS += tictactoe.h \ + tictactoedialog.h \ + tictactoeplugin.h \ + tictactoetaskmenu.h +SOURCES += tictactoe.cpp \ + tictactoedialog.cpp \ + tictactoeplugin.cpp \ + tictactoetaskmenu.cpp +#! [2] + +# install +target.path = $$[QT_INSTALL_PLUGINS]/designer +sources.files = $$SOURCES $$HEADERS *.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/qttools/designer/taskmenuextension +INSTALLS += target sources + +symbian: include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) diff --git a/examples/designer/taskmenuextension/tictactoe.cpp b/examples/designer/taskmenuextension/tictactoe.cpp new file mode 100644 index 000000000..6a258933a --- /dev/null +++ b/examples/designer/taskmenuextension/tictactoe.cpp @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "tictactoe.h" + +TicTacToe::TicTacToe(QWidget *parent) + : QWidget(parent) +{ +} + +QSize TicTacToe::minimumSizeHint() const +{ + return QSize(200, 200); +} + +QSize TicTacToe::sizeHint() const +{ + return QSize(200, 200); +} + +void TicTacToe::setState(const QString &newState) +{ + turnNumber = 0; + myState = "---------"; + int position = 0; + while (position < 9 && position < newState.length()) { + QChar mark = newState.at(position); + if (mark == Cross || mark == Nought) { + ++turnNumber; + myState.replace(position, 1, mark); + } + position++; + } + update(); +} + +QString TicTacToe::state() const +{ + return myState; +} + +void TicTacToe::clearBoard() +{ + myState = "---------"; + turnNumber = 0; + update(); +} + +void TicTacToe::mousePressEvent(QMouseEvent *event) +{ + if (turnNumber == 9) { + clearBoard(); + update(); + } else { + for (int position = 0; position < 9; ++position) { + QRect cell = cellRect(position / 3, position % 3); + if (cell.contains(event->pos())) { + if (myState.at(position) == Empty) { + if (turnNumber % 2 == 0) + myState.replace(position, 1, Cross); + else + myState.replace(position, 1, Nought); + ++turnNumber; + update(); + } + } + } + } +} + +void TicTacToe::paintEvent(QPaintEvent * /* event */) +{ + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + + painter.setPen(QPen(Qt::darkGreen, 1)); + painter.drawLine(cellWidth(), 0, cellWidth(), height()); + painter.drawLine(2 * cellWidth(), 0, 2 * cellWidth(), height()); + painter.drawLine(0, cellHeight(), width(), cellHeight()); + painter.drawLine(0, 2 * cellHeight(), width(), 2 * cellHeight()); + + painter.setPen(QPen(Qt::darkBlue, 2)); + + for (int position = 0; position < 9; ++position) { + QRect cell = cellRect(position / 3, position % 3); + + if (myState.at(position) == Cross) { + painter.drawLine(cell.topLeft(), cell.bottomRight()); + painter.drawLine(cell.topRight(), cell.bottomLeft()); + } else if (myState.at(position) == Nought) { + painter.drawEllipse(cell); + } + } + + painter.setPen(QPen(Qt::yellow, 3)); + + for (int position = 0; position < 9; position = position + 3) { + if (myState.at(position) != Empty + && myState.at(position + 1) == myState.at(position) + && myState.at(position + 2) == myState.at(position)) { + int y = cellRect((position / 3), 0).center().y(); + painter.drawLine(0, y, width(), y); + turnNumber = 9; + } + } + + for (int position = 0; position < 3; ++position) { + if (myState.at(position) != Empty + && myState.at(position + 3) == myState.at(position) + && myState.at(position + 6) == myState.at(position)) { + int x = cellRect(0, position).center().x(); + painter.drawLine(x, 0, x, height()); + turnNumber = 9; + } + } + if (myState.at(0) != Empty && myState.at(4) == myState.at(0) + && myState.at(8) == myState.at(0)) { + painter.drawLine(0, 0, width(), height()); + turnNumber = 9; + } + if (myState.at(2) != Empty && myState.at(4) == myState.at(2) + && myState.at(6) == myState.at(2)) { + painter.drawLine(0, height(), width(), 0); + turnNumber = 9; + } +} + +QRect TicTacToe::cellRect(int row, int column) const +{ + const int HMargin = width() / 30; + const int VMargin = height() / 30; + return QRect(column * cellWidth() + HMargin, + row * cellHeight() + VMargin, + cellWidth() - 2 * HMargin, + cellHeight() - 2 * VMargin); +} diff --git a/examples/designer/taskmenuextension/tictactoe.h b/examples/designer/taskmenuextension/tictactoe.h new file mode 100644 index 000000000..53ccf0472 --- /dev/null +++ b/examples/designer/taskmenuextension/tictactoe.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TICTACTOE_H +#define TICTACTOE_H + +#include + +QT_BEGIN_NAMESPACE +class QRect; +class QSize; +QT_END_NAMESPACE + +//! [0] +class TicTacToe : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QString state READ state WRITE setState) + +public: + TicTacToe(QWidget *parent = 0); + + QSize minimumSizeHint() const; + QSize sizeHint() const; + void setState(const QString &newState); + QString state() const; + void clearBoard(); + +protected: + void mousePressEvent(QMouseEvent *event); + void paintEvent(QPaintEvent *event); + +private: + enum { Empty = '-', Cross = 'X', Nought = 'O' }; + + QRect cellRect(int row, int col) const; + int cellWidth() const { return width() / 3; } + int cellHeight() const { return height() / 3; } + + QString myState; + int turnNumber; +}; +//! [0] + +#endif diff --git a/examples/designer/taskmenuextension/tictactoedialog.cpp b/examples/designer/taskmenuextension/tictactoedialog.cpp new file mode 100644 index 000000000..5af3c6f30 --- /dev/null +++ b/examples/designer/taskmenuextension/tictactoedialog.cpp @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "tictactoe.h" +#include "tictactoedialog.h" + +//! [0] +TicTacToeDialog::TicTacToeDialog(TicTacToe *tic, QWidget *parent) + : QDialog(parent) +{ + ticTacToe = tic; + editor = new TicTacToe; + editor->setState(ticTacToe->state()); + + buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok + | QDialogButtonBox::Cancel + | QDialogButtonBox::Reset); + + connect(buttonBox->button(QDialogButtonBox::Reset), SIGNAL(clicked()), + this, SLOT(resetState())); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(saveState())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addWidget(editor); + mainLayout->addWidget(buttonBox); + + setLayout(mainLayout); + setWindowTitle(tr("Edit State")); +} +//! [0] + +//! [1] +QSize TicTacToeDialog::sizeHint() const +{ + return QSize(250, 250); +} +//! [1] + +//! [2] +void TicTacToeDialog::resetState() +{ + editor->clearBoard(); +} +//! [2] + +//! [3] +void TicTacToeDialog::saveState() +{ +//! [3] //! [4] + if (QDesignerFormWindowInterface *formWindow + = QDesignerFormWindowInterface::findFormWindow(ticTacToe)) { + formWindow->cursor()->setProperty("state", editor->state()); + } +//! [4] //! [5] + accept(); +} +//! [5] diff --git a/examples/designer/taskmenuextension/tictactoedialog.h b/examples/designer/taskmenuextension/tictactoedialog.h new file mode 100644 index 000000000..163ab8966 --- /dev/null +++ b/examples/designer/taskmenuextension/tictactoedialog.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TICTACTOEDIALOG_H +#define TICTACTOEDIALOG_H + +#include + +QT_BEGIN_NAMESPACE +class QDialogButtonBox; +QT_END_NAMESPACE +class TicTacToe; + +//! [0] +class TicTacToeDialog : public QDialog +{ + Q_OBJECT + +public: + explicit TicTacToeDialog(TicTacToe *plugin = 0, QWidget *parent = 0); + + QSize sizeHint() const; + +private slots: + void resetState(); + void saveState(); + +private: + TicTacToe *editor; + TicTacToe *ticTacToe; + QDialogButtonBox *buttonBox; +}; +//! [0] + +#endif diff --git a/examples/designer/taskmenuextension/tictactoeplugin.cpp b/examples/designer/taskmenuextension/tictactoeplugin.cpp new file mode 100644 index 000000000..45c078c98 --- /dev/null +++ b/examples/designer/taskmenuextension/tictactoeplugin.cpp @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +#include "tictactoe.h" +#include "tictactoeplugin.h" +#include "tictactoetaskmenu.h" + +//! [0] +TicTacToePlugin::TicTacToePlugin(QObject *parent) + : QObject(parent) +{ + initialized = false; +} + +QString TicTacToePlugin::name() const +{ + return "TicTacToe"; +} + +QString TicTacToePlugin::group() const +{ + return "Display Widgets [Examples]"; +} + +QString TicTacToePlugin::toolTip() const +{ + return ""; +} + +QString TicTacToePlugin::whatsThis() const +{ + return ""; +} + +QString TicTacToePlugin::includeFile() const +{ + return "tictactoe.h"; +} + +QIcon TicTacToePlugin::icon() const +{ + return QIcon(); +} + +bool TicTacToePlugin::isContainer() const +{ + return false; +} + +QWidget *TicTacToePlugin::createWidget(QWidget *parent) +{ + TicTacToe *ticTacToe = new TicTacToe(parent); + ticTacToe->setState("-X-XO----"); + return ticTacToe; +} + +bool TicTacToePlugin::isInitialized() const +{ + return initialized; +} + +//! [0] //! [1] +void TicTacToePlugin::initialize(QDesignerFormEditorInterface *formEditor) +{ +//! [1] //! [2] + if (initialized) + return; + + QExtensionManager *manager = formEditor->extensionManager(); + Q_ASSERT(manager != 0); +//! [2] + +//! [3] + manager->registerExtensions(new TicTacToeTaskMenuFactory(manager), + Q_TYPEID(QDesignerTaskMenuExtension)); + + initialized = true; +} + +QString TicTacToePlugin::domXml() const +{ + return QLatin1String("\ +\ + \ + \ + \ + TicTacToe\ + \ + \ + \ + \ + \ +"); +} + +//! [3] + +//! [4] +Q_EXPORT_PLUGIN2(taskmenuextension, TicTacToePlugin) +//! [4] diff --git a/examples/designer/taskmenuextension/tictactoeplugin.h b/examples/designer/taskmenuextension/tictactoeplugin.h new file mode 100644 index 000000000..6bd6065ab --- /dev/null +++ b/examples/designer/taskmenuextension/tictactoeplugin.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] +#ifndef TICTACTOEPLUGIN_H +#define TICTACTOEPLUGIN_H + +#include + +QT_BEGIN_NAMESPACE +class QIcon; +class QWidget; +QT_END_NAMESPACE + +class TicTacToePlugin : public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + TicTacToePlugin(QObject *parent = 0); + + QString name() const; + QString group() const; + QString toolTip() const; + QString whatsThis() const; + QString includeFile() const; + QIcon icon() const; + bool isContainer() const; + QWidget *createWidget(QWidget *parent); + bool isInitialized() const; + void initialize(QDesignerFormEditorInterface *formEditor); + QString domXml() const; + +private: + bool initialized; +}; + +#endif +//! [0] diff --git a/examples/designer/taskmenuextension/tictactoetaskmenu.cpp b/examples/designer/taskmenuextension/tictactoetaskmenu.cpp new file mode 100644 index 000000000..79fe88e88 --- /dev/null +++ b/examples/designer/taskmenuextension/tictactoetaskmenu.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "tictactoe.h" +#include "tictactoedialog.h" +#include "tictactoetaskmenu.h" + +//! [0] +TicTacToeTaskMenu::TicTacToeTaskMenu(TicTacToe *tic, QObject *parent) + : QObject(parent) +{ + ticTacToe = tic; + + editStateAction = new QAction(tr("Edit State..."), this); + connect(editStateAction, SIGNAL(triggered()), this, SLOT(editState())); +} +//! [0] + +//! [1] +void TicTacToeTaskMenu::editState() +{ + TicTacToeDialog dialog(ticTacToe); + dialog.exec(); +} +//! [1] + +//! [2] +QAction *TicTacToeTaskMenu::preferredEditAction() const +{ + return editStateAction; +} +//! [2] + +//! [3] +QList TicTacToeTaskMenu::taskActions() const +{ + QList list; + list.append(editStateAction); + return list; +} +//! [3] + +//! [4] +TicTacToeTaskMenuFactory::TicTacToeTaskMenuFactory(QExtensionManager *parent) + : QExtensionFactory(parent) +{ +} +//! [4] + +//! [5] +QObject *TicTacToeTaskMenuFactory::createExtension(QObject *object, + const QString &iid, + QObject *parent) const +{ + if (iid != Q_TYPEID(QDesignerTaskMenuExtension)) + return 0; + + if (TicTacToe *tic = qobject_cast(object)) + return new TicTacToeTaskMenu(tic, parent); + + return 0; +} +//! [5] diff --git a/examples/designer/taskmenuextension/tictactoetaskmenu.h b/examples/designer/taskmenuextension/tictactoetaskmenu.h new file mode 100644 index 000000000..8e203d0d9 --- /dev/null +++ b/examples/designer/taskmenuextension/tictactoetaskmenu.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TICTACTOETASKMENU_H +#define TICTACTOETASKMENU_H + +#include +#include + +QT_BEGIN_NAMESPACE +class QAction; +class QExtensionManager; +QT_END_NAMESPACE +class TicTacToe; + +//! [0] +class TicTacToeTaskMenu : public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerTaskMenuExtension) + +public: + TicTacToeTaskMenu(TicTacToe *tic, QObject *parent); + + QAction *preferredEditAction() const; + QList taskActions() const; + +private slots: + void editState(); + +private: + QAction *editStateAction; + TicTacToe *ticTacToe; +}; +//! [0] + +//! [1] +class TicTacToeTaskMenuFactory : public QExtensionFactory +{ + Q_OBJECT + +public: + TicTacToeTaskMenuFactory(QExtensionManager *parent = 0); + +protected: + QObject *createExtension(QObject *object, const QString &iid, QObject *parent) const; +}; +//! [1] + +#endif diff --git a/examples/designer/worldtimeclockbuilder/form.ui b/examples/designer/worldtimeclockbuilder/form.ui new file mode 100644 index 000000000..e5be1d911 --- /dev/null +++ b/examples/designer/worldtimeclockbuilder/form.ui @@ -0,0 +1,162 @@ + + + + + WorldTimeForm + + + + 0 + 0 + 400 + 300 + + + + World Time Clock + + + + 9 + + + 6 + + + + + + + + 1 + + + 6 + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 1 + + + 6 + + + + + Current time: + + + + + + + true + + + + + + + + + 1 + + + 6 + + + + + Set time zone: + + + + + + + 12 + + + -12 + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + WorldTimeClock + +
worldtimeclock.h
+ 0 + +
+
+ + + + spinBox + valueChanged(int) + worldTimeClock + setTimeZone(int) + + + 339 + 166 + + + 157 + 230 + + + + + worldTimeClock + updated(QTime) + timeEdit + setTime(QTime) + + + 141 + 59 + + + 291 + 133 + + + + +
diff --git a/examples/designer/worldtimeclockbuilder/main.cpp b/examples/designer/worldtimeclockbuilder/main.cpp new file mode 100644 index 000000000..680394190 --- /dev/null +++ b/examples/designer/worldtimeclockbuilder/main.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//! [0] +#include +//! [0] +#include + +//! [1] +int main(int argc, char *argv[]) +{ + Q_INIT_RESOURCE(worldtimeclockbuilder); + + QApplication app(argc, argv); + + QUiLoader loader; +//! [1] + +//! [2] + QFile file(":/forms/form.ui"); + file.open(QFile::ReadOnly); + + QWidget *widget = loader.load(&file); + + file.close(); + widget->show(); +//! [2] + +//! [3] + return app.exec(); +} +//! [3] diff --git a/examples/designer/worldtimeclockbuilder/worldtimeclockbuilder.pro b/examples/designer/worldtimeclockbuilder/worldtimeclockbuilder.pro new file mode 100644 index 000000000..94fa49766 --- /dev/null +++ b/examples/designer/worldtimeclockbuilder/worldtimeclockbuilder.pro @@ -0,0 +1,13 @@ +#! [0] +CONFIG += uitools +SOURCES = main.cpp +RESOURCES = worldtimeclockbuilder.qrc +#! [0] + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/qttools/designer/worldtimeclockbuilder +sources.files = $$SOURCES $$HEADERS $$RESOURCES *.ui *.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/qttools/designer/worldtimeclockbuilder +INSTALLS += target sources + +symbian: include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) diff --git a/examples/designer/worldtimeclockbuilder/worldtimeclockbuilder.qrc b/examples/designer/worldtimeclockbuilder/worldtimeclockbuilder.qrc new file mode 100644 index 000000000..89d5ac3c2 --- /dev/null +++ b/examples/designer/worldtimeclockbuilder/worldtimeclockbuilder.qrc @@ -0,0 +1,5 @@ + + + form.ui + + diff --git a/examples/designer/worldtimeclockplugin/worldtimeclock.cpp b/examples/designer/worldtimeclockplugin/worldtimeclock.cpp new file mode 100644 index 000000000..088c6e97e --- /dev/null +++ b/examples/designer/worldtimeclockplugin/worldtimeclock.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "worldtimeclock.h" + +WorldTimeClock::WorldTimeClock(QWidget *parent) + : QWidget(parent) +{ + timeZoneOffset = 0; + + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(update())); + timer->start(1000); + + setWindowTitle(tr("World Time Clock")); + resize(200, 200); +} + +void WorldTimeClock::paintEvent(QPaintEvent *) +{ + static const QPoint hourHand[3] = { + QPoint(7, 8), + QPoint(-7, 8), + QPoint(0, -40) + }; + static const QPoint minuteHand[3] = { + QPoint(7, 8), + QPoint(-7, 8), + QPoint(0, -70) + }; + + QColor hourColor(127, 0, 127); + QColor minuteColor(0, 127, 127, 191); + + int side = qMin(width(), height()); + QTime time = QTime::currentTime(); + time = time.addSecs(timeZoneOffset); + + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + painter.translate(width() / 2, height() / 2); + painter.scale(side / 200.0, side / 200.0); + + painter.setPen(Qt::NoPen); + painter.setBrush(hourColor); + + painter.save(); + painter.rotate(30.0 * ((time.hour() + time.minute() / 60.0))); + painter.drawConvexPolygon(hourHand, 3); + painter.restore(); + + painter.setPen(hourColor); + + for (int i = 0; i < 12; ++i) { + painter.drawLine(88, 0, 96, 0); + painter.rotate(30.0); + } + + painter.setPen(Qt::NoPen); + painter.setBrush(minuteColor); + + painter.save(); + painter.rotate(6.0 * (time.minute() + time.second() / 60.0)); + painter.drawConvexPolygon(minuteHand, 3); + painter.restore(); + + painter.setPen(minuteColor); + + for (int j = 0; j < 60; ++j) { + if ((j % 5) != 0) + painter.drawLine(92, 0, 96, 0); + painter.rotate(6.0); + } + + emit updated(time); +} + +void WorldTimeClock::setTimeZone(int hourOffset) +{ + timeZoneOffset = qMin(qMax(-12, hourOffset), 12) * 3600; + update(); +} diff --git a/examples/designer/worldtimeclockplugin/worldtimeclock.h b/examples/designer/worldtimeclockplugin/worldtimeclock.h new file mode 100644 index 000000000..dc5933c33 --- /dev/null +++ b/examples/designer/worldtimeclockplugin/worldtimeclock.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WORLDTIMECLOCK_H +#define WORLDTIMECLOCK_H + +#include +#include +#include + +//! [0] //! [1] +class QDESIGNER_WIDGET_EXPORT WorldTimeClock : public QWidget +{ + Q_OBJECT +//! [0] + +public: + WorldTimeClock(QWidget *parent = 0); + +public slots: + void setTimeZone(int hourOffset); + +signals: + void updated(QTime currentTime); + +protected: + void paintEvent(QPaintEvent *event); + +private: + int timeZoneOffset; +//! [2] +}; +//! [1] //! [2] + +#endif diff --git a/examples/designer/worldtimeclockplugin/worldtimeclockplugin.cpp b/examples/designer/worldtimeclockplugin/worldtimeclockplugin.cpp new file mode 100644 index 000000000..88b8d45b0 --- /dev/null +++ b/examples/designer/worldtimeclockplugin/worldtimeclockplugin.cpp @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "worldtimeclock.h" +#include "worldtimeclockplugin.h" + +#include + +WorldTimeClockPlugin::WorldTimeClockPlugin(QObject *parent) + : QObject(parent) +{ + initialized = false; +} + +void WorldTimeClockPlugin::initialize(QDesignerFormEditorInterface * /* core */) +{ + if (initialized) + return; + + initialized = true; +} + +bool WorldTimeClockPlugin::isInitialized() const +{ + return initialized; +} + +QWidget *WorldTimeClockPlugin::createWidget(QWidget *parent) +{ + return new WorldTimeClock(parent); +} + +QString WorldTimeClockPlugin::name() const +{ + return "WorldTimeClock"; +} + +QString WorldTimeClockPlugin::group() const +{ + return "Display Widgets [Examples]"; +} + +QIcon WorldTimeClockPlugin::icon() const +{ + return QIcon(); +} + +QString WorldTimeClockPlugin::toolTip() const +{ + return ""; +} + +QString WorldTimeClockPlugin::whatsThis() const +{ + return ""; +} + +bool WorldTimeClockPlugin::isContainer() const +{ + return false; +} + +QString WorldTimeClockPlugin::domXml() const +{ + return "\n" + " \n" + " \n" + " \n" + " 0\n" + " 0\n" + " 100\n" + " 100\n" + " \n" + " \n" + " \n" + ""; +} + +QString WorldTimeClockPlugin::includeFile() const +{ + return "worldtimeclock.h"; +} + +//! [0] +Q_EXPORT_PLUGIN2(worldtimeclockplugin, WorldTimeClockPlugin) +//! [0] diff --git a/examples/designer/worldtimeclockplugin/worldtimeclockplugin.h b/examples/designer/worldtimeclockplugin/worldtimeclockplugin.h new file mode 100644 index 000000000..91c4b5202 --- /dev/null +++ b/examples/designer/worldtimeclockplugin/worldtimeclockplugin.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WORLDTIMECLOCKPLUGIN_H +#define WORLDTIMECLOCKPLUGIN_H + +#include + +//! [0] +class WorldTimeClockPlugin : public QObject, + public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + WorldTimeClockPlugin(QObject *parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget *createWidget(QWidget *parent); + void initialize(QDesignerFormEditorInterface *core); + +private: + bool initialized; +}; +//! [0] + +#endif diff --git a/examples/designer/worldtimeclockplugin/worldtimeclockplugin.pro b/examples/designer/worldtimeclockplugin/worldtimeclockplugin.pro new file mode 100644 index 000000000..01340e873 --- /dev/null +++ b/examples/designer/worldtimeclockplugin/worldtimeclockplugin.pro @@ -0,0 +1,23 @@ +#! [0] +CONFIG += designer plugin +#! [0] +TARGET = $$qtLibraryTarget($$TARGET) +#! [1] +TEMPLATE = lib +#! [1] +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/designer + +#! [2] +HEADERS = worldtimeclock.h \ + worldtimeclockplugin.h +SOURCES = worldtimeclock.cpp \ + worldtimeclockplugin.cpp +#! [2] + +# install +target.path = $$[QT_INSTALL_PLUGINS]/designer +sources.files = $$SOURCES $$HEADERS *.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/qttools/designer/worldtimeclockplugin +INSTALLS += target sources + +symbian: include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) diff --git a/examples/examples.pro b/examples/examples.pro new file mode 100644 index 000000000..e2f2c617f --- /dev/null +++ b/examples/examples.pro @@ -0,0 +1,2 @@ +TEMPLATE = subdirs +SUBDIRS += help designer diff --git a/examples/help/README b/examples/help/README new file mode 100644 index 000000000..85f5a4373 --- /dev/null +++ b/examples/help/README @@ -0,0 +1,38 @@ +Support for interactive help is provided by the Qt Assistant application. +Developers can take advantages of the facilities it offers to display +specially-prepared documentation to users of their applications. + + +The example launcher provided with Qt can be used to explore each of the +examples in this directory. + +Documentation for these examples can be found via the Tutorial and Examples +link in the main Qt documentation. + + +Finding the Qt Examples and Demos launcher +========================================== + +On Windows: + +The launcher can be accessed via the Windows Start menu. Select the menu +entry entitled "Qt Examples and Demos" entry in the submenu containing +the Qt tools. + +On Mac OS X: + +For the binary distribution, the qtdemo executable is installed in the +/Developer/Applications/Qt directory. For the source distribution, it is +installed alongside the other Qt tools on the path specified when Qt is +configured. + +On Unix/Linux: + +The qtdemo executable is installed alongside the other Qt tools on the path +specified when Qt is configured. + +On all platforms: + +The source code for the launcher can be found in the demos/qtdemo directory +in the Qt package. This example is built at the same time as the Qt libraries, +tools, examples, and demonstrations. diff --git a/examples/help/contextsensitivehelp/contextsensitivehelp.pro b/examples/help/contextsensitivehelp/contextsensitivehelp.pro new file mode 100644 index 000000000..ef85c840d --- /dev/null +++ b/examples/help/contextsensitivehelp/contextsensitivehelp.pro @@ -0,0 +1,20 @@ +TEMPLATE = app + +CONFIG += help + +SOURCES += main.cpp \ + wateringconfigdialog.cpp \ + helpbrowser.cpp + +HEADERS += wateringconfigdialog.h \ + helpbrowser.h + +FORMS += wateringconfigdialog.ui + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/qttools/help/contextsensitivehelp +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS *.pro *.png *.doc doc +sources.path = $$[QT_INSTALL_EXAMPLES]/qttools/help/contextsensitivehelp +INSTALLS += target sources + +symbian: include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) diff --git a/examples/help/contextsensitivehelp/doc/amount.html b/examples/help/contextsensitivehelp/doc/amount.html new file mode 100644 index 000000000..7a02a6fd5 --- /dev/null +++ b/examples/help/contextsensitivehelp/doc/amount.html @@ -0,0 +1,11 @@ + + + + Water amount + + + Depending on the plant, temperature and rain fall the amount needs to be larger + or smaller. On a really hot day without rain, the suggested amount + can be increased by about 10%. + + diff --git a/examples/help/contextsensitivehelp/doc/filter.html b/examples/help/contextsensitivehelp/doc/filter.html new file mode 100644 index 000000000..64861126d --- /dev/null +++ b/examples/help/contextsensitivehelp/doc/filter.html @@ -0,0 +1,12 @@ + + + +Filter + + +Depending on the source of water, it needs to be filtered or not. Filtering +is strongly recommened for the river and lake. + + + + diff --git a/examples/help/contextsensitivehelp/doc/plants.html b/examples/help/contextsensitivehelp/doc/plants.html new file mode 100644 index 000000000..2d2bb6788 --- /dev/null +++ b/examples/help/contextsensitivehelp/doc/plants.html @@ -0,0 +1,44 @@ + + + + Plants + + + Different kind of plants need different amounts of water. Here's a short + overview over the most common grown plants and their avarage need of water: +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KindAmount
Squash2000
Bean1500
Carrot1200
Strawberry1300
Raspberry1000
Blueberry1100
+

+ Warning: Watering them too much or too little will + cause irreversible damage! + + diff --git a/examples/help/contextsensitivehelp/doc/rain.html b/examples/help/contextsensitivehelp/doc/rain.html new file mode 100644 index 000000000..1ffe45240 --- /dev/null +++ b/examples/help/contextsensitivehelp/doc/rain.html @@ -0,0 +1,11 @@ + + + + Rain + + + Depending on the rain fall, the automated watering system should not be + switched on at all. Also, the temperature should be + considered. + + diff --git a/examples/help/contextsensitivehelp/doc/source.html b/examples/help/contextsensitivehelp/doc/source.html new file mode 100644 index 000000000..68b2f8c71 --- /dev/null +++ b/examples/help/contextsensitivehelp/doc/source.html @@ -0,0 +1,33 @@ + + + + Water Source + + + The current pipe system connects to four different sources. Be aware + that only a limited amount of water can be taken from some sources. +
+ + + + + + + + + + + + + + + + + + + + + +
SourceAmount
Fountain4000
River6000
Lake10000
Public Water Systemunlimited
+ + diff --git a/examples/help/contextsensitivehelp/doc/temperature.html b/examples/help/contextsensitivehelp/doc/temperature.html new file mode 100644 index 000000000..4145ed725 --- /dev/null +++ b/examples/help/contextsensitivehelp/doc/temperature.html @@ -0,0 +1,13 @@ + + + + Temperature + + + Depending on the temperature, the plants need more or less water. The higher + the temperature the higher the need for water. If the temperature does not + reach a certain level, maybe no automatic watering should be done at all.
+ Before setting this parameter for good, you should also take the amount of + rain into account. + + diff --git a/examples/help/contextsensitivehelp/doc/time.html b/examples/help/contextsensitivehelp/doc/time.html new file mode 100644 index 000000000..0cc81f4d0 --- /dev/null +++ b/examples/help/contextsensitivehelp/doc/time.html @@ -0,0 +1,11 @@ + + + +Starting time + + +Starting the watering too early may be ineffective since most water +will evaporate. + + + diff --git a/examples/help/contextsensitivehelp/doc/wateringmachine.qch b/examples/help/contextsensitivehelp/doc/wateringmachine.qch new file mode 100644 index 000000000..35d29be22 Binary files /dev/null and b/examples/help/contextsensitivehelp/doc/wateringmachine.qch differ diff --git a/examples/help/contextsensitivehelp/doc/wateringmachine.qhc b/examples/help/contextsensitivehelp/doc/wateringmachine.qhc new file mode 100644 index 000000000..b5653c3ff Binary files /dev/null and b/examples/help/contextsensitivehelp/doc/wateringmachine.qhc differ diff --git a/examples/help/contextsensitivehelp/doc/wateringmachine.qhcp b/examples/help/contextsensitivehelp/doc/wateringmachine.qhcp new file mode 100644 index 000000000..eebf6520e --- /dev/null +++ b/examples/help/contextsensitivehelp/doc/wateringmachine.qhcp @@ -0,0 +1,14 @@ + + + + + + wateringmachine.qhp + wateringmachine.qch + + + + wateringmachine.qch + + + \ No newline at end of file diff --git a/examples/help/contextsensitivehelp/doc/wateringmachine.qhp b/examples/help/contextsensitivehelp/doc/wateringmachine.qhp new file mode 100644 index 000000000..6dd08e7ae --- /dev/null +++ b/examples/help/contextsensitivehelp/doc/wateringmachine.qhp @@ -0,0 +1,25 @@ + + + wateringmachine + wateringcompany.com.1-0-0.premium + + + + + + + + + + + + plants.html + temperature.html + rain.html + time.html + amount.html + source.html + filter.html + + + diff --git a/examples/help/contextsensitivehelp/helpbrowser.cpp b/examples/help/contextsensitivehelp/helpbrowser.cpp new file mode 100644 index 000000000..d37a72f3b --- /dev/null +++ b/examples/help/contextsensitivehelp/helpbrowser.cpp @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +#include "helpbrowser.h" + +HelpBrowser::HelpBrowser(QWidget *parent) + : QTextBrowser(parent) +{ + QString collectionFile = QLibraryInfo::location(QLibraryInfo::ExamplesPath) + + QLatin1String("/help/contextsensitivehelp/doc/wateringmachine.qhc"); + + m_helpEngine = new QHelpEngineCore(collectionFile, this); + if (!m_helpEngine->setupData()) { + delete m_helpEngine; + m_helpEngine = 0; + } +} + +void HelpBrowser::showHelpForKeyword(const QString &id) +{ + if (m_helpEngine) { + QMap links = m_helpEngine->linksForIdentifier(id); + if (links.count()) + setSource(links.constBegin().value()); + } +} + +QVariant HelpBrowser::loadResource(int type, const QUrl &name) +{ + QByteArray ba; + if (type < 4 && m_helpEngine) { + QUrl url(name); + if (name.isRelative()) + url = source().resolved(url); + ba = m_helpEngine->fileData(url); + } + return ba; +} + diff --git a/examples/help/contextsensitivehelp/helpbrowser.h b/examples/help/contextsensitivehelp/helpbrowser.h new file mode 100644 index 000000000..684ed6827 --- /dev/null +++ b/examples/help/contextsensitivehelp/helpbrowser.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef HELPBROWSER_H +#define HELPBROWSER_H + +#include + +QT_BEGIN_NAMESPACE +class QHelpEngineCore; +QT_END_NAMESPACE; + +class HelpBrowser : public QTextBrowser +{ + Q_OBJECT + +public: + HelpBrowser(QWidget *parent); + void showHelpForKeyword(const QString &id); + +private: + QVariant loadResource(int type, const QUrl &name); + + QHelpEngineCore *m_helpEngine; +}; + +#endif diff --git a/examples/help/contextsensitivehelp/main.cpp b/examples/help/contextsensitivehelp/main.cpp new file mode 100644 index 000000000..ca15d9fb6 --- /dev/null +++ b/examples/help/contextsensitivehelp/main.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "wateringconfigdialog.h" + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + WateringConfigDialog dia; + return dia.exec(); +} diff --git a/examples/help/contextsensitivehelp/wateringconfigdialog.cpp b/examples/help/contextsensitivehelp/wateringconfigdialog.cpp new file mode 100644 index 000000000..0529bfcfc --- /dev/null +++ b/examples/help/contextsensitivehelp/wateringconfigdialog.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "wateringconfigdialog.h" + +WateringConfigDialog::WateringConfigDialog() +{ + m_ui.setupUi(this); + m_widgetInfo.insert(m_ui.plantComboBox, tr("plants")); + m_widgetInfo.insert(m_ui.temperatureCheckBox, tr("temperature")); + m_widgetInfo.insert(m_ui.temperatureSpinBox, tr("temperature")); + m_widgetInfo.insert(m_ui.rainCheckBox, tr("rain")); + m_widgetInfo.insert(m_ui.rainSpinBox, tr("rain")); + m_widgetInfo.insert(m_ui.startTimeEdit, tr("starting time")); + m_widgetInfo.insert(m_ui.amountSpinBox, tr("water amount")); + m_widgetInfo.insert(m_ui.sourceComboBox, tr("water source")); + m_widgetInfo.insert(m_ui.filterCheckBox, tr("water filtering")); + + connect(qApp, SIGNAL(focusChanged(QWidget*,QWidget*)), + this, SLOT(focusChanged(QWidget*,QWidget*))); +} + +void WateringConfigDialog::focusChanged(QWidget *, QWidget *now) +{ + if (m_widgetInfo.contains(now)) { + m_ui.helpLabel->setText(tr("Information about %1:").arg(m_widgetInfo.value(now))); + QStringList lst = m_widgetInfo.value(now).split(QLatin1Char(' ')); + m_ui.helpBrowser->showHelpForKeyword(lst.last()); + } +} + diff --git a/examples/help/contextsensitivehelp/wateringconfigdialog.h b/examples/help/contextsensitivehelp/wateringconfigdialog.h new file mode 100644 index 000000000..d1fd98643 --- /dev/null +++ b/examples/help/contextsensitivehelp/wateringconfigdialog.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WATERINGCONFIGDIALOG_H +#define WATERINGCONFIGDIALOG_H + +#include +#include "ui_wateringconfigdialog.h" + +class WateringConfigDialog : public QDialog +{ + Q_OBJECT +public: + WateringConfigDialog(); + +private slots: + void focusChanged(QWidget *old, QWidget *now); + +private: + Ui::WateringConfigDialog m_ui; + QMap m_widgetInfo; +}; + +#endif diff --git a/examples/help/contextsensitivehelp/wateringconfigdialog.ui b/examples/help/contextsensitivehelp/wateringconfigdialog.ui new file mode 100644 index 000000000..d7a473a3c --- /dev/null +++ b/examples/help/contextsensitivehelp/wateringconfigdialog.ui @@ -0,0 +1,446 @@ + + WateringConfigDialog + + + + 0 + 0 + 334 + 550 + + + + Watering Configuration + + + + + + + + Plant: + + + + + + + + 0 + 0 + + + + + Squash + + + + + Bean + + + + + Carrot + + + + + Strawberry + + + + + Raspberry + + + + + Blueberry + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 67 + 16 + + + + + + + + Water when: + + + + + + + Temperature is higher than: + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 16 + 20 + + + + + + + + false + + + + + + C + + + 10 + + + 60 + + + 20 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Rain less than: + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 16 + 20 + + + + + + + + false + + + + + + mm + + + 1 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + Starting Time: + + + + + + + + + + Amount: + + + + + + + l + + + 100 + + + 10000 + + + 100 + + + 1000 + + + + + + + Source: + + + + + + + + Fountain + + + + + River + + + + + Lake + + + + + Public Water System + + + + + + + + Filter: + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + <a href="test">Show Details</a> + + + + + + + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok + + + + + + + + HelpBrowser + QTextBrowser +
helpbrowser.h
+
+
+ + + + buttonBox + accepted() + WateringConfigDialog + accept() + + + 227 + 372 + + + 157 + 274 + + + + + buttonBox + rejected() + WateringConfigDialog + reject() + + + 286 + 378 + + + 286 + 274 + + + + + temperatureCheckBox + toggled(bool) + temperatureSpinBox + setEnabled(bool) + + + 132 + 101 + + + 132 + 125 + + + + + rainCheckBox + toggled(bool) + rainSpinBox + setEnabled(bool) + + + 110 + 154 + + + 113 + 169 + + + + +
diff --git a/examples/help/help.pro b/examples/help/help.pro new file mode 100644 index 000000000..f03ec01f4 --- /dev/null +++ b/examples/help/help.pro @@ -0,0 +1,13 @@ +TEMPLATE = subdirs +CONFIG += ordered + +SUBDIRS += contextsensitivehelp \ + remotecontrol \ + simpletextviewer + +# install +sources.files = README *.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/qttools/help +INSTALLS += sources + +symbian: include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) diff --git a/examples/help/remotecontrol/enter.png b/examples/help/remotecontrol/enter.png new file mode 100644 index 000000000..f397f4b9c Binary files /dev/null and b/examples/help/remotecontrol/enter.png differ diff --git a/examples/help/remotecontrol/main.cpp b/examples/help/remotecontrol/main.cpp new file mode 100644 index 000000000..ad561ce4f --- /dev/null +++ b/examples/help/remotecontrol/main.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "remotecontrol.h" + +int main(int argc, char *argv[]) +{ + Q_INIT_RESOURCE(remotecontrol); + + QApplication a(argc, argv); + RemoteControl w; + w.show(); + a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit())); + return a.exec(); +} diff --git a/examples/help/remotecontrol/remotecontrol.cpp b/examples/help/remotecontrol/remotecontrol.cpp new file mode 100644 index 000000000..45d3fde82 --- /dev/null +++ b/examples/help/remotecontrol/remotecontrol.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +#include + +#include "remotecontrol.h" + +RemoteControl::RemoteControl(QWidget *parent, Qt::WFlags flags) + : QMainWindow(parent, flags) +{ + ui.setupUi(this); + connect(ui.indexLineEdit, SIGNAL(returnPressed()), + this, SLOT(on_indexButton_clicked())); + connect(ui.identifierLineEdit, SIGNAL(returnPressed()), + this, SLOT(on_identifierButton_clicked())); + connect(ui.urlLineEdit, SIGNAL(returnPressed()), + this, SLOT(on_urlButton_clicked())); + + QString rc; + QTextStream(&rc) << QLatin1String("qthelp://com.trolltech.qt.") + << (QT_VERSION >> 16) << ((QT_VERSION >> 8) & 0xFF) + << (QT_VERSION & 0xFF) + << QLatin1String("/qdoc/index.html"); + + ui.startUrlLineEdit->setText(rc); + + process = new QProcess(this); + connect(process, SIGNAL(finished(int,QProcess::ExitStatus)), + this, SLOT(helpViewerClosed())); +} + +RemoteControl::~RemoteControl() +{ + if (process->state() == QProcess::Running) { + process->terminate(); + process->waitForFinished(3000); + } +} + +void RemoteControl::on_actionQuit_triggered() +{ + close(); +} + +void RemoteControl::on_launchButton_clicked() +{ + if (process->state() == QProcess::Running) + return; + + QString app = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QDir::separator(); +#if !defined(Q_OS_MAC) + app += QLatin1String("assistant"); +#else + app += QLatin1String("Assistant.app/Contents/MacOS/Assistant"); +#endif + + ui.contentsCheckBox->setChecked(true); + ui.indexCheckBox->setChecked(true); + ui.bookmarksCheckBox->setChecked(true); + + QStringList args; + args << QLatin1String("-enableRemoteControl"); + process->start(app, args); + if (!process->waitForStarted()) { + QMessageBox::critical(this, tr("Remote Control"), + tr("Could not start Qt Assistant from %1.").arg(app)); + return; + } + + if (!ui.startUrlLineEdit->text().isEmpty()) + sendCommand(QLatin1String("SetSource ") + + ui.startUrlLineEdit->text()); + + ui.launchButton->setEnabled(false); + ui.startUrlLineEdit->setEnabled(false); + ui.actionGroupBox->setEnabled(true); +} + +void RemoteControl::sendCommand(const QString &cmd) +{ + if (process->state() != QProcess::Running) + return; + process->write(cmd.toLocal8Bit() + '\n'); +} + +void RemoteControl::on_indexButton_clicked() +{ + sendCommand(QLatin1String("ActivateKeyword ") + + ui.indexLineEdit->text()); +} + +void RemoteControl::on_identifierButton_clicked() +{ + sendCommand(QLatin1String("ActivateIdentifier ") + + ui.identifierLineEdit->text()); +} + +void RemoteControl::on_urlButton_clicked() +{ + sendCommand(QLatin1String("SetSource ") + + ui.urlLineEdit->text()); +} + +void RemoteControl::on_syncContentsButton_clicked() +{ + sendCommand(QLatin1String("SyncContents")); +} + +void RemoteControl::on_contentsCheckBox_toggled(bool checked) +{ + sendCommand(checked ? + QLatin1String("Show Contents") : QLatin1String("Hide Contents")); +} + +void RemoteControl::on_indexCheckBox_toggled(bool checked) +{ + sendCommand(checked ? + QLatin1String("Show Index") : QLatin1String("Hide Index")); +} + +void RemoteControl::on_bookmarksCheckBox_toggled(bool checked) +{ + sendCommand(checked ? + QLatin1String("Show Bookmarks") : QLatin1String("Hide Bookmarks")); +} + +void RemoteControl::helpViewerClosed() +{ + ui.launchButton->setEnabled(true); + ui.startUrlLineEdit->setEnabled(true); + ui.actionGroupBox->setEnabled(false); +} diff --git a/examples/help/remotecontrol/remotecontrol.h b/examples/help/remotecontrol/remotecontrol.h new file mode 100644 index 000000000..e440add3f --- /dev/null +++ b/examples/help/remotecontrol/remotecontrol.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef REMOTECONTROL_H +#define REMOTECONTROL_H + +#include +#include "ui_remotecontrol.h" + +QT_BEGIN_NAMESPACE +class QProcess; +QT_END_NAMESPACE; + +class RemoteControl : public QMainWindow +{ + Q_OBJECT + +public: + RemoteControl(QWidget *parent = 0, Qt::WFlags flags = 0); + ~RemoteControl(); + +private: + Ui::RemoteControlClass ui; + QProcess *process; + +private slots: + void on_launchButton_clicked(); + void on_actionQuit_triggered(); + void on_indexButton_clicked(); + void on_identifierButton_clicked(); + void on_urlButton_clicked(); + void on_syncContentsButton_clicked(); + void on_contentsCheckBox_toggled(bool checked); + void on_indexCheckBox_toggled(bool checked); + void on_bookmarksCheckBox_toggled(bool checked); + void helpViewerClosed(); + + void sendCommand(const QString &cmd); +}; + +#endif // REMOTECONTROL_H diff --git a/examples/help/remotecontrol/remotecontrol.pro b/examples/help/remotecontrol/remotecontrol.pro new file mode 100644 index 000000000..f080b3c0b --- /dev/null +++ b/examples/help/remotecontrol/remotecontrol.pro @@ -0,0 +1,15 @@ +TEMPLATE = app + +HEADERS += remotecontrol.h +SOURCES += main.cpp \ + remotecontrol.cpp +FORMS += remotecontrol.ui +RESOURCES += remotecontrol.qrc + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/qttools/help/remotecontrol +sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS *.pro *.png *.doc doc +sources.path = $$[QT_INSTALL_EXAMPLES]/qttools/help/remotecontrol +INSTALLS += target sources + +symbian: include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) diff --git a/examples/help/remotecontrol/remotecontrol.qrc b/examples/help/remotecontrol/remotecontrol.qrc new file mode 100644 index 000000000..9b4299d21 --- /dev/null +++ b/examples/help/remotecontrol/remotecontrol.qrc @@ -0,0 +1,5 @@ + + + enter.png + + diff --git a/examples/help/remotecontrol/remotecontrol.ui b/examples/help/remotecontrol/remotecontrol.ui new file mode 100644 index 000000000..1cfc7f540 --- /dev/null +++ b/examples/help/remotecontrol/remotecontrol.ui @@ -0,0 +1,228 @@ + + RemoteControlClass + + + + 0 + 0 + 344 + 364 + + + + RemoteControl + + + + + + + Start URL: + + + + + + + + + + Launch Qt HelpViewer + + + + + + + Qt::Horizontal + + + + 101 + 20 + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 113 + 16 + + + + + + + + false + + + Actions + + + + + + Search in Index: + + + + + + + 0 + + + + + + + + + + + :/remotecontrol/enter.png + + + + + + + + + Identifier: + + + + + + + 0 + + + + + + + + + + + :/remotecontrol/enter.png + + + + + + + + + Show URL: + + + + + + + 0 + + + + + + + + + + + :/remotecontrol/enter.png + + + + + + + + + Sync Contents + + + + + + + Qt::Horizontal + + + + 81 + 20 + + + + + + + + Show Contents + + + + + + + Show Index + + + + + + + Show Bookmarks + + + + + + + + + + + + 0 + 0 + 344 + 21 + + + + + File + + + + + + + + + Quit + + + + + + + + + diff --git a/examples/help/simpletextviewer/assistant.cpp b/examples/help/simpletextviewer/assistant.cpp new file mode 100644 index 000000000..2223b4bbf --- /dev/null +++ b/examples/help/simpletextviewer/assistant.cpp @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +#include + +#include "assistant.h" + +Assistant::Assistant() + : proc(0) +{ +} + +//! [0] +Assistant::~Assistant() +{ + if (proc && proc->state() == QProcess::Running) { + proc->terminate(); + proc->waitForFinished(3000); + } + delete proc; +} +//! [0] + +//! [1] +void Assistant::showDocumentation(const QString &page) +{ + if (!startAssistant()) + return; + + QByteArray ba("SetSource "); + ba.append("qthelp://com.trolltech.examples.simpletextviewer/doc/"); + + proc->write(ba + page.toLocal8Bit() + '\n'); +} +//! [1] + +//! [2] +bool Assistant::startAssistant() +{ + if (!proc) + proc = new QProcess(); + + if (proc->state() != QProcess::Running) { + QString app = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QDir::separator(); +#if !defined(Q_OS_MAC) + app += QLatin1String("assistant"); +#else + app += QLatin1String("Assistant.app/Contents/MacOS/Assistant"); +#endif + + QStringList args; + args << QLatin1String("-collectionFile") + << QLibraryInfo::location(QLibraryInfo::ExamplesPath) + + QLatin1String("/help/simpletextviewer/documentation/simpletextviewer.qhc") + << QLatin1String("-enableRemoteControl"); + + proc->start(app, args); + + if (!proc->waitForStarted()) { + QMessageBox::critical(0, QObject::tr("Simple Text Viewer"), + QObject::tr("Unable to launch Qt Assistant (%1)").arg(app)); + return false; + } + } + return true; +} +//! [2] diff --git a/examples/help/simpletextviewer/assistant.h b/examples/help/simpletextviewer/assistant.h new file mode 100644 index 000000000..3f508dd82 --- /dev/null +++ b/examples/help/simpletextviewer/assistant.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ASSISTANT_H +#define ASSISTANT_H + +#include + +QT_BEGIN_NAMESPACE +class QProcess; +QT_END_NAMESPACE + +class Assistant +{ +public: + Assistant(); + ~Assistant(); + void showDocumentation(const QString &file); + +private: + bool startAssistant(); + QProcess *proc; +}; + +#endif diff --git a/examples/help/simpletextviewer/documentation/about.txt b/examples/help/simpletextviewer/documentation/about.txt new file mode 100644 index 000000000..eeab35f4a --- /dev/null +++ b/examples/help/simpletextviewer/documentation/about.txt @@ -0,0 +1,9 @@ +The Simple Text Viewer enables the user to select and view existing +files. + +HTML files is displayed using rich text, while other files are +presented as plain text. The application provides a file dialog +allowing the user to search for files using wildcard matching. The +search is performed within in the specified directory, and the user is +given an option to browse the existing file system to find the +relevant directory. diff --git a/examples/help/simpletextviewer/documentation/browse.html b/examples/help/simpletextviewer/documentation/browse.html new file mode 100644 index 000000000..987abf31f --- /dev/null +++ b/examples/help/simpletextviewer/documentation/browse.html @@ -0,0 +1,34 @@ + + + + Browse + + + +

Browse

+ +

+ The file dialog let you browse the current file system to + specify the directory in which the file you want to open + resides. + Note that only the specified directory will be searched, any + subdirectories will simply be ignored. +

+ +
+
+ + + + +
+ +
+
+

+ See also: File Dialog, Wildcard Matching, + Find File +

+ + + diff --git a/examples/help/simpletextviewer/documentation/filedialog.html b/examples/help/simpletextviewer/documentation/filedialog.html new file mode 100644 index 000000000..afa65ed57 --- /dev/null +++ b/examples/help/simpletextviewer/documentation/filedialog.html @@ -0,0 +1,48 @@ + + + + File Dialog + + + +

File Dialog

+ +

+ In the file dialog you can name a particular file name, or + search for files using wildcard matching, i.e. specify a + file name containing wildcards. In addition you must specify + the directory in which the file you search for resides. +

+ +
+
+ + + + +
+ +
+
+

+ By default the dialog will search for all files (*) in the + current directory (the directory the application is run from). +

+ +

+ When editing the file name and directory parameters, an + overview of the matching files are displayed in the + dialog. The overview is updated whenever the parameters + change. +

+ +
+
+

+ See also: Browse, Wildcard Matching, + Find File +

+ + + + diff --git a/examples/help/simpletextviewer/documentation/findfile.html b/examples/help/simpletextviewer/documentation/findfile.html new file mode 100644 index 000000000..32e014718 --- /dev/null +++ b/examples/help/simpletextviewer/documentation/findfile.html @@ -0,0 +1,32 @@ + + + + Find File + + + +

Find File

+ +

+ To open and view a file in the Simple Text Viewer, select the + 'Open...' option in the 'File' menu. The application will then + provide you with a file dialog that you can use to search for + any existing file. +

+ +
+
+ + + + +
+ +
+
+

+ See also: Open File, File Dialog +

+ + + diff --git a/examples/help/simpletextviewer/documentation/images/browse.png b/examples/help/simpletextviewer/documentation/images/browse.png new file mode 100644 index 000000000..86db6b19e Binary files /dev/null and b/examples/help/simpletextviewer/documentation/images/browse.png differ diff --git a/examples/help/simpletextviewer/documentation/images/fadedfilemenu.png b/examples/help/simpletextviewer/documentation/images/fadedfilemenu.png new file mode 100644 index 000000000..fde0e43f6 Binary files /dev/null and b/examples/help/simpletextviewer/documentation/images/fadedfilemenu.png differ diff --git a/examples/help/simpletextviewer/documentation/images/filedialog.png b/examples/help/simpletextviewer/documentation/images/filedialog.png new file mode 100644 index 000000000..883a33a26 Binary files /dev/null and b/examples/help/simpletextviewer/documentation/images/filedialog.png differ diff --git a/examples/help/simpletextviewer/documentation/images/handbook.png b/examples/help/simpletextviewer/documentation/images/handbook.png new file mode 100644 index 000000000..3bd2b928b Binary files /dev/null and b/examples/help/simpletextviewer/documentation/images/handbook.png differ diff --git a/examples/help/simpletextviewer/documentation/images/icon.png b/examples/help/simpletextviewer/documentation/images/icon.png new file mode 100644 index 000000000..6daec0ade Binary files /dev/null and b/examples/help/simpletextviewer/documentation/images/icon.png differ diff --git a/examples/help/simpletextviewer/documentation/images/mainwindow.png b/examples/help/simpletextviewer/documentation/images/mainwindow.png new file mode 100644 index 000000000..c28d5e9ff Binary files /dev/null and b/examples/help/simpletextviewer/documentation/images/mainwindow.png differ diff --git a/examples/help/simpletextviewer/documentation/images/open.png b/examples/help/simpletextviewer/documentation/images/open.png new file mode 100644 index 000000000..1e5bba3c8 Binary files /dev/null and b/examples/help/simpletextviewer/documentation/images/open.png differ diff --git a/examples/help/simpletextviewer/documentation/images/wildcard.png b/examples/help/simpletextviewer/documentation/images/wildcard.png new file mode 100644 index 000000000..6e83a56cc Binary files /dev/null and b/examples/help/simpletextviewer/documentation/images/wildcard.png differ diff --git a/examples/help/simpletextviewer/documentation/index.html b/examples/help/simpletextviewer/documentation/index.html new file mode 100644 index 000000000..5a7b1d5fa --- /dev/null +++ b/examples/help/simpletextviewer/documentation/index.html @@ -0,0 +1,41 @@ + + + + Manual + + + +

Simple Text Viewer

+ +

+ The Simple Text Viewer enables the user to select and view + existing files. +

+ +

+ +

+ +

+ HTML files is displayed using rich text, while + other files are presented as plain text. The application + provides a file dialog allowing the user to search for files + using wildcard matching. The search is performed within in the + specified directory, and the user is given an option to browse + the existing file system to find the relevant directory. +

+ + + + + + + diff --git a/examples/help/simpletextviewer/documentation/intro.html b/examples/help/simpletextviewer/documentation/intro.html new file mode 100644 index 000000000..2e2aa40de --- /dev/null +++ b/examples/help/simpletextviewer/documentation/intro.html @@ -0,0 +1,28 @@ + + + + Manual + + + +

Simple Text Viewer

+ +

+ The Simple Text Viewer enables the user to select and view + existing files. +

+ +

+ +

+ +

+ The application provides its own custom documentation that is + available through the Help menu in the main window's menubar + and through the Help button in the application's find file + dialog. +

+ + + + diff --git a/examples/help/simpletextviewer/documentation/openfile.html b/examples/help/simpletextviewer/documentation/openfile.html new file mode 100644 index 000000000..e172de95e --- /dev/null +++ b/examples/help/simpletextviewer/documentation/openfile.html @@ -0,0 +1,36 @@ + + + + Open File + + + +

Open File

+ +

+ Once the file you want to view appears in the dialog's + display, you can open it in two different ways. +

+ +

+ By pressing the 'Open' button the currently selected file will + be opened. By default, the first file in the list of matching + files is selected. Another way of opening a file is to simply + double click the displayed file name. +

+ +
+
+ + + + +
+ +
+
+

+ See also: Find File +

+ + diff --git a/examples/help/simpletextviewer/documentation/simpletextviewer.qch b/examples/help/simpletextviewer/documentation/simpletextviewer.qch new file mode 100644 index 000000000..c40132803 Binary files /dev/null and b/examples/help/simpletextviewer/documentation/simpletextviewer.qch differ diff --git a/examples/help/simpletextviewer/documentation/simpletextviewer.qhc b/examples/help/simpletextviewer/documentation/simpletextviewer.qhc new file mode 100644 index 000000000..db380cabf Binary files /dev/null and b/examples/help/simpletextviewer/documentation/simpletextviewer.qhc differ diff --git a/examples/help/simpletextviewer/documentation/simpletextviewer.qhcp b/examples/help/simpletextviewer/documentation/simpletextviewer.qhcp new file mode 100644 index 000000000..e7c23210b --- /dev/null +++ b/examples/help/simpletextviewer/documentation/simpletextviewer.qhcp @@ -0,0 +1,30 @@ + + + + Simple Text Viewer + images/handbook.png + Trolltech/SimpleTextViewer + qthelp://com.trolltech.examples.simpletextviewer/doc/index.html + + About Simple Text Viewer + + + about.txt + images/icon.png + + false + false + false + + + + + simpletextviewer.qhp + simpletextviewer.qch + + + + simpletextviewer.qch + + + diff --git a/examples/help/simpletextviewer/documentation/simpletextviewer.qhp b/examples/help/simpletextviewer/documentation/simpletextviewer.qhp new file mode 100644 index 000000000..4cb83a5f3 --- /dev/null +++ b/examples/help/simpletextviewer/documentation/simpletextviewer.qhp @@ -0,0 +1,49 @@ + + + com.trolltech.examples.simpletextviewer + doc + + +
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + browse.html + filedialog.html + findfile.html + index.html + intro.html + openfile.html + wildcardmatching.html + images/browse.png + images/fadedfilemenu.png + images/filedialog.png + images/handbook.png + images/mainwindow.png + images/open.png + images/wildcard.png + +
+
diff --git a/examples/help/simpletextviewer/documentation/wildcardmatching.html b/examples/help/simpletextviewer/documentation/wildcardmatching.html new file mode 100644 index 000000000..eb1839a06 --- /dev/null +++ b/examples/help/simpletextviewer/documentation/wildcardmatching.html @@ -0,0 +1,57 @@ + + + + Wildcard Matching + + + +

Wildcard Matching

+ +

+ Most command shells such as bash or cmd.exe support "file + globbing", the ability to identify a group of files by using + wildcards. + +
+
+ + + + +
+ +
+
+

+ Wildcard matching provides four features: +

+ +
    +
  • Any character represents itself apart from those + mentioned below. Thus 'c' matches the character 'c'. +
  • +
  • The '?' character matches any single character.
  • +
  • The '*' matches zero or more of any characters.
  • +
  • Sets of characters can be represented in square brackets. + Within the character class, like outside, backslash + has no special meaning. +
  • +
+ +

+ For example we could identify HTML files with + *.html. This will match zero or more characters + followed by a dot followed by 'h', 't', 'm' and 'l'. +

+ +
+
+

+ See also: Browse, File Dialog, + Find File +

+ + + + + diff --git a/examples/help/simpletextviewer/findfiledialog.cpp b/examples/help/simpletextviewer/findfiledialog.cpp new file mode 100644 index 000000000..086be965d --- /dev/null +++ b/examples/help/simpletextviewer/findfiledialog.cpp @@ -0,0 +1,221 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "findfiledialog.h" +#include "assistant.h" +#include "textedit.h" + +//! [0] +FindFileDialog::FindFileDialog(TextEdit *editor, Assistant *assistant) + : QDialog(editor) +{ + currentAssistant = assistant; + currentEditor = editor; +//! [0] + + createButtons(); + createComboBoxes(); + createFilesTree(); + createLabels(); + createLayout(); + + directoryComboBox->addItem(QDir::toNativeSeparators(QDir::currentPath())); + fileNameComboBox->addItem("*"); + findFiles(); + + setWindowTitle(tr("Find File")); +//! [1] +} +//! [1] + +void FindFileDialog::browse() +{ + QString currentDirectory = directoryComboBox->currentText(); + QString newDirectory = QFileDialog::getExistingDirectory(this, + tr("Select Directory"), currentDirectory); + if (!newDirectory.isEmpty()) { + directoryComboBox->addItem(QDir::toNativeSeparators(newDirectory)); + directoryComboBox->setCurrentIndex(directoryComboBox->count() - 1); + update(); + } +} + +//! [2] +void FindFileDialog::help() +{ + currentAssistant->showDocumentation("filedialog.html"); +} +//! [2] + +void FindFileDialog::openFile(QTreeWidgetItem *item) +{ + if (!item) { + item = foundFilesTree->currentItem(); + if (!item) + return; + } + + QString fileName = item->text(0); + QString path = directoryComboBox->currentText() + QDir::separator(); + + currentEditor->setContents(path + fileName); + close(); +} + +void FindFileDialog::update() +{ + findFiles(); + buttonBox->button(QDialogButtonBox::Open)->setEnabled( + foundFilesTree->topLevelItemCount() > 0); +} + +void FindFileDialog::findFiles() +{ + QRegExp filePattern(fileNameComboBox->currentText() + "*"); + filePattern.setPatternSyntax(QRegExp::Wildcard); + + QDir directory(directoryComboBox->currentText()); + + QStringList allFiles = directory.entryList(QDir::Files | QDir::NoSymLinks); + QStringList matchingFiles; + + foreach (QString file, allFiles) { + if (filePattern.exactMatch(file)) + matchingFiles << file; + } + showFiles(matchingFiles); +} + +void FindFileDialog::showFiles(const QStringList &files) +{ + foundFilesTree->clear(); + + for (int i = 0; i < files.count(); ++i) { + QTreeWidgetItem *item = new QTreeWidgetItem(foundFilesTree); + item->setText(0, files[i]); + } + + if (files.count() > 0) + foundFilesTree->setCurrentItem(foundFilesTree->topLevelItem(0)); +} + +void FindFileDialog::createButtons() +{ + browseButton = new QToolButton; + browseButton->setText(tr("...")); + connect(browseButton, SIGNAL(clicked()), this, SLOT(browse())); + + buttonBox = new QDialogButtonBox(QDialogButtonBox::Open + | QDialogButtonBox::Cancel + | QDialogButtonBox::Help); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(openFile())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(buttonBox, SIGNAL(helpRequested()), this, SLOT(help())); +} + +void FindFileDialog::createComboBoxes() +{ + directoryComboBox = new QComboBox; + fileNameComboBox = new QComboBox; + + fileNameComboBox->setEditable(true); + fileNameComboBox->setSizePolicy(QSizePolicy::Expanding, + QSizePolicy::Preferred); + + directoryComboBox->setMinimumContentsLength(30); + directoryComboBox->setSizeAdjustPolicy( + QComboBox::AdjustToMinimumContentsLength); + directoryComboBox->setSizePolicy(QSizePolicy::Expanding, + QSizePolicy::Preferred); + + connect(fileNameComboBox, SIGNAL(editTextChanged(QString)), + this, SLOT(update())); + connect(directoryComboBox, SIGNAL(currentIndexChanged(QString)), + this, SLOT(update())); +} + +void FindFileDialog::createFilesTree() +{ + foundFilesTree = new QTreeWidget; + foundFilesTree->setColumnCount(1); + foundFilesTree->setHeaderLabels(QStringList(tr("Matching Files"))); + foundFilesTree->setRootIsDecorated(false); + foundFilesTree->setSelectionMode(QAbstractItemView::SingleSelection); + + connect(foundFilesTree, SIGNAL(itemActivated(QTreeWidgetItem*,int)), + this, SLOT(openFile(QTreeWidgetItem*))); +} + +void FindFileDialog::createLabels() +{ + directoryLabel = new QLabel(tr("Search in:")); + fileNameLabel = new QLabel(tr("File name (including wildcards):")); +} + +void FindFileDialog::createLayout() +{ + QHBoxLayout *fileLayout = new QHBoxLayout; + fileLayout->addWidget(fileNameLabel); + fileLayout->addWidget(fileNameComboBox); + + QHBoxLayout *directoryLayout = new QHBoxLayout; + directoryLayout->addWidget(directoryLabel); + directoryLayout->addWidget(directoryComboBox); + directoryLayout->addWidget(browseButton); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addLayout(fileLayout); + mainLayout->addLayout(directoryLayout); + mainLayout->addWidget(foundFilesTree); + mainLayout->addStretch(); + mainLayout->addWidget(buttonBox); + setLayout(mainLayout); +} diff --git a/examples/help/simpletextviewer/findfiledialog.h b/examples/help/simpletextviewer/findfiledialog.h new file mode 100644 index 000000000..71abd4aac --- /dev/null +++ b/examples/help/simpletextviewer/findfiledialog.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FINDFILEDIALOG_H +#define FINDFILEDIALOG_H + +#include + +QT_BEGIN_NAMESPACE +class QComboBox; +class QDialogButtonBox; +class QLabel; +class QToolButton; +class QTreeWidget; +class QTreeWidgetItem; +QT_END_NAMESPACE + +class Assistant; +class TextEdit; + +//! [0] +class FindFileDialog : public QDialog +{ + Q_OBJECT + +public: + FindFileDialog(TextEdit *editor, Assistant *assistant); + +private slots: + void browse(); + void help(); + void openFile(QTreeWidgetItem *item = 0); + void update(); + +private: + void findFiles(); + void showFiles(const QStringList &files); + + void createButtons(); + void createComboBoxes(); + void createFilesTree(); + void createLabels(); + void createLayout(); + + Assistant *currentAssistant; + TextEdit *currentEditor; + QTreeWidget *foundFilesTree; + + QComboBox *directoryComboBox; + QComboBox *fileNameComboBox; + + QLabel *directoryLabel; + QLabel *fileNameLabel; + + QDialogButtonBox *buttonBox; + + QToolButton *browseButton; +}; +//! [0] + +#endif diff --git a/examples/help/simpletextviewer/main.cpp b/examples/help/simpletextviewer/main.cpp new file mode 100644 index 000000000..4c8aab9c8 --- /dev/null +++ b/examples/help/simpletextviewer/main.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "mainwindow.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + MainWindow window; + window.show(); + return app.exec(); +} diff --git a/examples/help/simpletextviewer/mainwindow.cpp b/examples/help/simpletextviewer/mainwindow.cpp new file mode 100644 index 000000000..61fbdf3cb --- /dev/null +++ b/examples/help/simpletextviewer/mainwindow.cpp @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "mainwindow.h" +#include "findfiledialog.h" +#include "assistant.h" +#include "textedit.h" + +// ![0] +MainWindow::MainWindow() +{ + assistant = new Assistant; +// ![0] + textViewer = new TextEdit; + textViewer->setContents(QLibraryInfo::location(QLibraryInfo::ExamplesPath) + + QLatin1String("/help/simpletextviewer/documentation/intro.html")); + setCentralWidget(textViewer); + + createActions(); + createMenus(); + + setWindowTitle(tr("Simple Text Viewer")); + resize(750, 400); +// ![1] +} +//! [1] + +//! [2] +void MainWindow::closeEvent(QCloseEvent *) +{ + delete assistant; +} +//! [2] + +void MainWindow::about() +{ + QMessageBox::about(this, tr("About Simple Text Viewer"), + tr("This example demonstrates how to use\n" + "Qt Assistant as help system for your\n" + "own application.")); +} + +//! [3] +void MainWindow::showDocumentation() +{ + assistant->showDocumentation("index.html"); +} +//! [3] + +void MainWindow::open() +{ + FindFileDialog dialog(textViewer, assistant); + dialog.exec(); +} + +//! [4] +void MainWindow::createActions() +{ + assistantAct = new QAction(tr("Help Contents"), this); + assistantAct->setShortcut(QKeySequence::HelpContents); + connect(assistantAct, SIGNAL(triggered()), this, SLOT(showDocumentation())); +//! [4] + + openAct = new QAction(tr("&Open..."), this); + openAct->setShortcut(QKeySequence::Open); + connect(openAct, SIGNAL(triggered()), this, SLOT(open())); + + clearAct = new QAction(tr("&Clear"), this); + clearAct->setShortcut(tr("Ctrl+C")); + connect(clearAct, SIGNAL(triggered()), textViewer, SLOT(clear())); + + exitAct = new QAction(tr("E&xit"), this); + exitAct->setShortcuts(QKeySequence::Quit); + connect(exitAct, SIGNAL(triggered()), this, SLOT(close())); + + aboutAct = new QAction(tr("&About"), this); + connect(aboutAct, SIGNAL(triggered()), this, SLOT(about())); + + aboutQtAct = new QAction(tr("About &Qt"), this); + connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt())); +//! [5] +} +//! [5] + +void MainWindow::createMenus() +{ + fileMenu = new QMenu(tr("&File"), this); + fileMenu->addAction(openAct); + fileMenu->addAction(clearAct); + fileMenu->addSeparator(); + fileMenu->addAction(exitAct); + + helpMenu = new QMenu(tr("&Help"), this); + helpMenu->addAction(assistantAct); + helpMenu->addSeparator(); + helpMenu->addAction(aboutAct); + helpMenu->addAction(aboutQtAct); + + + menuBar()->addMenu(fileMenu); + menuBar()->addMenu(helpMenu); +} diff --git a/examples/help/simpletextviewer/mainwindow.h b/examples/help/simpletextviewer/mainwindow.h new file mode 100644 index 000000000..4fab382f2 --- /dev/null +++ b/examples/help/simpletextviewer/mainwindow.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + +class Assistant; +class TextEdit; + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(); + void showDocumentation(const QString &file); + +private slots: + void about(); + void showDocumentation(); + void open(); + +protected: + void closeEvent(QCloseEvent *event); + +private: + void createActions(); + void createMenus(); + + Assistant *assistant; + TextEdit *textViewer; + + QMenu *fileMenu; + QMenu *helpMenu; + + QAction *assistantAct; + QAction *clearAct; + QAction *openAct; + QAction *exitAct; + QAction *aboutAct; + QAction *aboutQtAct; +}; + +#endif diff --git a/examples/help/simpletextviewer/simpletextviewer.pro b/examples/help/simpletextviewer/simpletextviewer.pro new file mode 100644 index 000000000..46bda4cef --- /dev/null +++ b/examples/help/simpletextviewer/simpletextviewer.pro @@ -0,0 +1,18 @@ +HEADERS = mainwindow.h \ + findfiledialog.h \ + assistant.h \ + textedit.h +SOURCES = main.cpp \ + mainwindow.cpp \ + findfiledialog.cpp \ + assistant.cpp \ + textedit.cpp + +# install +target.path = $$[QT_INSTALL_EXAMPLES]/qttools/help/simpletextviewer +sources.files = $$SOURCES $$HEADERS $$RESOURCES documentation *.pro +sources.path = $$[QT_INSTALL_EXAMPLES]/qttools/help/simpletextviewer +INSTALLS += target sources + +symbian: include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri) + diff --git a/examples/help/simpletextviewer/textedit.cpp b/examples/help/simpletextviewer/textedit.cpp new file mode 100644 index 000000000..52d85b380 --- /dev/null +++ b/examples/help/simpletextviewer/textedit.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "textedit.h" + +TextEdit::TextEdit(QWidget *parent) + : QTextEdit(parent) +{ + setReadOnly(true); +} + +void TextEdit::setContents(const QString &fileName) +{ + QFileInfo fi(fileName); + srcUrl = QUrl::fromLocalFile(fi.absoluteFilePath()); + QFile file(fileName); + if (file.open(QIODevice::ReadOnly)) { + QString data(file.readAll()); + if (fileName.endsWith(".html")) + setHtml(data); + else + setPlainText(data); + } +} + +QVariant TextEdit::loadResource(int type, const QUrl &name) +{ + if (type == QTextDocument::ImageResource) { + QFile file(srcUrl.resolved(name).toLocalFile()); + if (file.open(QIODevice::ReadOnly)) + return file.readAll(); + } + return QTextEdit::loadResource(type, name); +} diff --git a/examples/help/simpletextviewer/textedit.h b/examples/help/simpletextviewer/textedit.h new file mode 100644 index 000000000..b9ecabd1d --- /dev/null +++ b/examples/help/simpletextviewer/textedit.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor +** the names of its contributors may be used to endorse or promote +** products derived from this software without specific prior written +** permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TEXTEDIT_H +#define TEXTEDIT_H + +#include +#include + +class TextEdit : public QTextEdit +{ + Q_OBJECT + +public: + TextEdit(QWidget *parent = 0); + void setContents(const QString &fileName); + +private: + QVariant loadResource(int type, const QUrl &name); + QUrl srcUrl; +}; + +#endif diff --git a/qttools.pro b/qttools.pro new file mode 100644 index 000000000..871d8cc99 --- /dev/null +++ b/qttools.pro @@ -0,0 +1,12 @@ +TEMPLATE = subdirs + +module_qttools_src.subdir = src +module_qttools_src.target = module-qttools-src + +module_qttools_tests.subdir = tests +module_qttools_tests.target = module-qttools-tests +module_qttools_tests.depends = module_qttools_src +module_qttools_tests.CONFIG = no_default_target no_default_install + +SUBDIRS += module_qttools_src \ + module_qttools_tests \ diff --git a/src/assistant/assistant.pro b/src/assistant/assistant.pro new file mode 100644 index 000000000..97196b253 --- /dev/null +++ b/src/assistant/assistant.pro @@ -0,0 +1,6 @@ +TEMPLATE = subdirs +CONFIG += ordered + +SUBDIRS += lib/fulltextsearch \ + lib \ + tools diff --git a/src/assistant/lib/fulltextsearch/fulltextsearch.pri b/src/assistant/lib/fulltextsearch/fulltextsearch.pri new file mode 100644 index 000000000..134678feb --- /dev/null +++ b/src/assistant/lib/fulltextsearch/fulltextsearch.pri @@ -0,0 +1,161 @@ +DEFINES += _BUILD_FOR_QT_ LUCENE_DISABLE_MEMTRACKING +win32:DEFINES += _CRT_SECURE_NO_DEPRECATE _MT + +CLUCENEDIR = ../../../../src/3rdparty/clucene/src/CLucene + +INCLUDEPATH += . .. \ + $$CLUCENEDIR \ + $$CLUCENEDIR/../ \ + $$CLUCENEDIR/analysis \ + $$CLUCENEDIR/analysis/standard \ + $$CLUCENEDIR/config \ + $$CLUCENEDIR/debug \ + $$CLUCENEDIR/document \ + $$CLUCENEDIR/index \ + $$CLUCENEDIR/queryParser \ + $$CLUCENEDIR/search \ + $$CLUCENEDIR/store \ + $$CLUCENEDIR/util + + +SOURCES += $$CLUCENEDIR/StdHeader.cpp \ + $$CLUCENEDIR/analysis/AnalysisHeader.cpp \ + $$CLUCENEDIR/analysis/Analyzers.cpp \ + $$CLUCENEDIR/config/gunichartables.cpp \ + $$CLUCENEDIR/config/repl_lltot.cpp \ + $$CLUCENEDIR/config/repl_tcscasecmp.cpp \ + $$CLUCENEDIR/config/repl_tcslwr.cpp \ + $$CLUCENEDIR/config/repl_tcstod.cpp \ + $$CLUCENEDIR/config/repl_tcstoll.cpp \ + $$CLUCENEDIR/config/repl_tprintf.cpp \ + $$CLUCENEDIR/config/threads.cpp \ + $$CLUCENEDIR/config/utf8.cpp \ + $$CLUCENEDIR/debug/condition.cpp \ + $$CLUCENEDIR/debug/error.cpp \ + $$CLUCENEDIR/debug/memtracking.cpp \ + $$CLUCENEDIR/document/DateField.cpp \ + $$CLUCENEDIR/document/Document.cpp \ + $$CLUCENEDIR/document/Field.cpp \ + $$CLUCENEDIR/index/CompoundFile.cpp \ + $$CLUCENEDIR/index/DocumentWriter.cpp \ + $$CLUCENEDIR/index/FieldInfos.cpp \ + $$CLUCENEDIR/index/FieldsReader.cpp \ + $$CLUCENEDIR/index/FieldsWriter.cpp \ + $$CLUCENEDIR/index/IndexModifier.cpp \ + $$CLUCENEDIR/index/IndexReader.cpp \ + $$CLUCENEDIR/index/IndexWriter.cpp \ + $$CLUCENEDIR/index/MultiReader.cpp \ + $$CLUCENEDIR/index/SegmentInfos.cpp \ + $$CLUCENEDIR/index/SegmentMergeInfo.cpp \ + $$CLUCENEDIR/index/SegmentMergeQueue.cpp \ + $$CLUCENEDIR/index/SegmentMerger.cpp \ + $$CLUCENEDIR/index/SegmentReader.cpp \ + $$CLUCENEDIR/index/SegmentTermDocs.cpp \ + $$CLUCENEDIR/index/SegmentTermEnum.cpp \ + $$CLUCENEDIR/index/SegmentTermPositions.cpp \ + $$CLUCENEDIR/index/SegmentTermVector.cpp \ + $$CLUCENEDIR/index/Term.cpp \ + $$CLUCENEDIR/index/TermInfo.cpp \ + $$CLUCENEDIR/index/TermInfosReader.cpp \ + $$CLUCENEDIR/index/TermInfosWriter.cpp \ + $$CLUCENEDIR/index/TermVectorReader.cpp \ + $$CLUCENEDIR/index/TermVectorWriter.cpp \ + $$CLUCENEDIR/queryParser/Lexer.cpp \ + $$CLUCENEDIR/queryParser/MultiFieldQueryParser.cpp \ + $$CLUCENEDIR/queryParser/QueryParser.cpp \ + $$CLUCENEDIR/queryParser/QueryParserBase.cpp \ + $$CLUCENEDIR/queryParser/QueryToken.cpp \ + $$CLUCENEDIR/queryParser/TokenList.cpp \ + $$CLUCENEDIR/search/BooleanQuery.cpp \ + $$CLUCENEDIR/search/BooleanScorer.cpp \ + $$CLUCENEDIR/search/CachingWrapperFilter.cpp \ + $$CLUCENEDIR/search/ChainedFilter.cpp \ + $$CLUCENEDIR/search/ConjunctionScorer.cpp \ + $$CLUCENEDIR/search/DateFilter.cpp \ + $$CLUCENEDIR/search/ExactPhraseScorer.cpp \ + $$CLUCENEDIR/search/Explanation.cpp \ + $$CLUCENEDIR/search/FieldCache.cpp \ + $$CLUCENEDIR/search/FieldCacheImpl.cpp \ + $$CLUCENEDIR/search/FieldDocSortedHitQueue.cpp \ + $$CLUCENEDIR/search/FieldSortedHitQueue.cpp \ + $$CLUCENEDIR/search/FilteredTermEnum.cpp \ + $$CLUCENEDIR/search/FuzzyQuery.cpp \ + $$CLUCENEDIR/search/HitQueue.cpp \ + $$CLUCENEDIR/search/Hits.cpp \ + $$CLUCENEDIR/search/IndexSearcher.cpp \ + $$CLUCENEDIR/search/MultiSearcher.cpp \ + $$CLUCENEDIR/search/MultiTermQuery.cpp \ + $$CLUCENEDIR/search/PhrasePositions.cpp \ + $$CLUCENEDIR/search/PhraseQuery.cpp \ + $$CLUCENEDIR/search/PhraseScorer.cpp \ + $$CLUCENEDIR/search/PrefixQuery.cpp \ + $$CLUCENEDIR/search/QueryFilter.cpp \ + $$CLUCENEDIR/search/RangeFilter.cpp \ + $$CLUCENEDIR/search/RangeQuery.cpp \ + $$CLUCENEDIR/search/SearchHeader.cpp \ + $$CLUCENEDIR/search/Similarity.cpp \ + $$CLUCENEDIR/search/SloppyPhraseScorer.cpp \ + $$CLUCENEDIR/search/Sort.cpp \ + $$CLUCENEDIR/search/TermQuery.cpp \ + $$CLUCENEDIR/search/TermScorer.cpp \ + $$CLUCENEDIR/search/WildcardQuery.cpp \ + $$CLUCENEDIR/search/WildcardTermEnum.cpp \ + $$CLUCENEDIR/store/FSDirectory.cpp \ + $$CLUCENEDIR/store/IndexInput.cpp \ + $$CLUCENEDIR/store/IndexOutput.cpp \ + $$CLUCENEDIR/store/Lock.cpp \ + $$CLUCENEDIR/store/MMapInput.cpp \ + $$CLUCENEDIR/store/RAMDirectory.cpp \ + $$CLUCENEDIR/store/TransactionalRAMDirectory.cpp \ + $$CLUCENEDIR/util/BitSet.cpp \ + $$CLUCENEDIR/util/Equators.cpp \ + $$CLUCENEDIR/util/FastCharStream.cpp \ + $$CLUCENEDIR/util/fileinputstream.cpp \ + $$CLUCENEDIR/util/Misc.cpp \ + $$CLUCENEDIR/util/Reader.cpp \ + $$CLUCENEDIR/util/StringBuffer.cpp \ + $$CLUCENEDIR/util/StringIntern.cpp \ + $$CLUCENEDIR/util/ThreadLocal.cpp \ + $$CLUCENEDIR/analysis/standard/StandardAnalyzer.cpp \ + $$CLUCENEDIR/analysis/standard/StandardFilter.cpp \ + $$CLUCENEDIR/analysis/standard/StandardTokenizer.cpp + + +#Header files +HEADERS += qclucene_global_p.h \ + qclucene-config_p.h \ + qanalyzer_p.h \ + qtokenizer_p.h \ + qtoken_p.h \ + qtokenstream_p.h \ + qdocument_p.h \ + qfield_p.h \ + qindexreader_p.h \ + qindexwriter_p.h \ + qterm_p.h \ + qqueryparser_p.h \ + qfilter_p.h \ + qhits_p.h \ + qsearchable_p.h \ + qsort_p.h \ + qquery_p.h \ + qreader_p.h + + +#Source files +SOURCES += qanalyzer.cpp \ + qtokenizer.cpp \ + qtoken.cpp \ + qtokenstream.cpp \ + qdocument.cpp \ + qfield.cpp \ + qindexreader.cpp \ + qindexwriter.cpp \ + qterm.cpp \ + qqueryparser.cpp \ + qfilter.cpp \ + qhits.cpp \ + qsearchable.cpp \ + qsort.cpp \ + qquery.cpp \ + qreader.cpp diff --git a/src/assistant/lib/fulltextsearch/fulltextsearch.pro b/src/assistant/lib/fulltextsearch/fulltextsearch.pro new file mode 100644 index 000000000..d0e7a8796 --- /dev/null +++ b/src/assistant/lib/fulltextsearch/fulltextsearch.pro @@ -0,0 +1,50 @@ + +QMAKE_TARGET_PRODUCT = QtCLucene +QMAKE_TARGET_DESCRIPTION = QtCLucene full text search library wrapper. +#if qt is built with frameworks in debug, we must build QtCLucene in debug and release +#that's a similar logic as in qbase.pri +mac:!static:contains(QT_CONFIG, qt_framework) { + CONFIG(debug, debug|release) { + !build_pass:CONFIG += build_all + } +} +QT_CONFIG -= qt_framework +QT -= gui +TEMPLATE = lib +TARGET = QtCLucene +DEFINES += QHELP_LIB +include(../../../../src/qbase.pri) +include(fulltextsearch.pri) + +CONFIG += qt warn_off +contains(QT_CONFIG, reduce_exports) { + CONFIG += hide_symbols + # workaround for compiler errors on Ubuntu + linux*-g++*:DEFINES += _GLIBCXX_EXTERN_TEMPLATE=0 +} + +unix|win32-g++*:QMAKE_PKGCONFIG_REQUIRES = QtCore + +# impossible to disable exceptions in clucene atm +CONFIG(exceptions_off) { + CONFIG -= exceptions_off + CONFIG += exceptions + !win32|win32-g++* { + QMAKE_CFLAGS -= -fno-exceptions + QMAKE_CXXFLAGS -= -fno-exceptions + QMAKE_LFLAGS -= -fno-exceptions + QMAKE_CFLAGS += -fexceptions + QMAKE_CXXFLAGS += -fexceptions + QMAKE_LFLAGS += -fexceptions + } +} + +win32-msvc.net | win32-msvc2* { + QMAKE_CFLAGS_RELEASE -= -O2 + QMAKE_CXXFLAGS_RELEASE -= -O2 +} + +# the following define could be set globally in case we need it elsewhere +solaris* { + DEFINES += Q_SOLARIS_VERSION=$$system(uname -r | sed -e 's/5\\.//') +} diff --git a/src/assistant/lib/fulltextsearch/license.txt b/src/assistant/lib/fulltextsearch/license.txt new file mode 100644 index 000000000..9ef3d701d --- /dev/null +++ b/src/assistant/lib/fulltextsearch/license.txt @@ -0,0 +1,503 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + diff --git a/src/assistant/lib/fulltextsearch/qanalyzer.cpp b/src/assistant/lib/fulltextsearch/qanalyzer.cpp new file mode 100644 index 000000000..71dd2c972 --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qanalyzer.cpp @@ -0,0 +1,219 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#include "qanalyzer_p.h" +#include "qclucene_global_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +QCLuceneAnalyzerPrivate::QCLuceneAnalyzerPrivate() + : QSharedData() +{ + analyzer = 0; + deleteCLuceneAnalyzer = true; +} + +QCLuceneAnalyzerPrivate::QCLuceneAnalyzerPrivate(const QCLuceneAnalyzerPrivate &other) + : QSharedData() +{ + analyzer = _CL_POINTER(other.analyzer); + deleteCLuceneAnalyzer = other.deleteCLuceneAnalyzer; +} + +QCLuceneAnalyzerPrivate::~QCLuceneAnalyzerPrivate() +{ + if (deleteCLuceneAnalyzer) + _CLDECDELETE(analyzer); +} + + +QCLuceneAnalyzer::QCLuceneAnalyzer() + : d(new QCLuceneAnalyzerPrivate()) +{ + //nothing todo, private +} + +QCLuceneAnalyzer::~QCLuceneAnalyzer() +{ + // nothing todo +} + +qint32 QCLuceneAnalyzer::positionIncrementGap(const QString &fieldName) const +{ + Q_UNUSED(fieldName); + return 0; +} + +QCLuceneTokenStream QCLuceneAnalyzer::tokenStream(const QString &fieldName, + const QCLuceneReader &reader) const +{ + TCHAR *fName = QStringToTChar(fieldName); + QCLuceneTokenStream tokenStream; + tokenStream.d->tokenStream = d->analyzer->tokenStream(fName, reader.d->reader); + delete [] fName; + + return tokenStream; +} + + +QCLuceneStandardAnalyzer::QCLuceneStandardAnalyzer() + : QCLuceneAnalyzer() +{ + d->analyzer = new lucene::analysis::standard::StandardAnalyzer(); +} + +QCLuceneStandardAnalyzer::~QCLuceneStandardAnalyzer() +{ + // nothing todo +} + +QCLuceneStandardAnalyzer::QCLuceneStandardAnalyzer(const QStringList &stopWords) +{ + const TCHAR **tArray = new const TCHAR*[stopWords.count() +1]; + + for(int i = 0; i < stopWords.count(); ++i) { + TCHAR *stopWord = QStringToTChar(stopWords.at(i)); + tArray[i] = STRDUP_TtoT(stopWord); + delete [] stopWord; + } + tArray[stopWords.count()] = 0; + + d->analyzer = new lucene::analysis::standard::StandardAnalyzer(tArray); + + for (int i = 0; i < stopWords.count(); ++i) + delete [] tArray[i]; + + delete [] tArray; +} + + +QCLuceneWhitespaceAnalyzer::QCLuceneWhitespaceAnalyzer() + : QCLuceneAnalyzer() +{ + d->analyzer = new lucene::analysis::WhitespaceAnalyzer(); +} + +QCLuceneWhitespaceAnalyzer::~QCLuceneWhitespaceAnalyzer() +{ + // nothing todo +} + + +QCLuceneSimpleAnalyzer::QCLuceneSimpleAnalyzer() + : QCLuceneAnalyzer() +{ + d->analyzer = new lucene::analysis::SimpleAnalyzer(); +} + +QCLuceneSimpleAnalyzer::~QCLuceneSimpleAnalyzer() +{ + // nothing todo +} + + +QCLuceneStopAnalyzer::QCLuceneStopAnalyzer() + : QCLuceneAnalyzer() +{ + d->analyzer = new lucene::analysis::StopAnalyzer(); +} + +QCLuceneStopAnalyzer::~QCLuceneStopAnalyzer() +{ + // nothing todo +} + +QCLuceneStopAnalyzer::QCLuceneStopAnalyzer(const QStringList &stopWords) + : QCLuceneAnalyzer() +{ + const TCHAR **tArray = new const TCHAR*[stopWords.count() +1]; + + for(int i = 0; i < stopWords.count(); ++i) { + TCHAR *stopWord = QStringToTChar(stopWords.at(i)); + tArray[i] = STRDUP_TtoT(stopWord); + delete [] stopWord; + } + tArray[stopWords.count()] = 0; + + d->analyzer = new lucene::analysis::StopAnalyzer(tArray); + + for (int i = 0; i < stopWords.count(); ++i) + delete [] tArray[i]; + + delete [] tArray; +} + +QStringList QCLuceneStopAnalyzer::englishStopWords() const +{ + QStringList stopWordList; + + const TCHAR** stopWords = lucene::analysis::StopAnalyzer::ENGLISH_STOP_WORDS; + for (qint32 i = 0; stopWords[i] != 0; ++i) + stopWordList.append(TCharToQString(stopWords[i])); + + return stopWordList; +} + + +QCLuceneKeywordAnalyzer::QCLuceneKeywordAnalyzer() + : QCLuceneAnalyzer() +{ + d->analyzer = new lucene::analysis::KeywordAnalyzer(); +} + +QCLuceneKeywordAnalyzer::~QCLuceneKeywordAnalyzer() +{ + // nothing todo +} + + +QCLucenePerFieldAnalyzerWrapper::QCLucenePerFieldAnalyzerWrapper( + QCLuceneAnalyzer *defaultAnalyzer) + : QCLuceneAnalyzer() +{ + d->analyzer = new + lucene::analysis::PerFieldAnalyzerWrapper(defaultAnalyzer->d->analyzer); + + analyzers.append(defaultAnalyzer); + defaultAnalyzer->d->deleteCLuceneAnalyzer = false; +} + +QCLucenePerFieldAnalyzerWrapper::~QCLucenePerFieldAnalyzerWrapper() +{ + qDeleteAll(analyzers); +} + +void QCLucenePerFieldAnalyzerWrapper::addAnalyzer(const QString &fieldName, + QCLuceneAnalyzer *analyzer) +{ + lucene::analysis::PerFieldAnalyzerWrapper *analyzerWrapper = + static_cast (d->analyzer); + + if (analyzerWrapper == 0) + return; + + analyzers.append(analyzer); + analyzer->d->deleteCLuceneAnalyzer = false; + + TCHAR *fName = QStringToTChar(fieldName); + analyzerWrapper->addAnalyzer(fName, analyzer->d->analyzer); + delete [] fName; +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/fulltextsearch/qanalyzer_p.h b/src/assistant/lib/fulltextsearch/qanalyzer_p.h new file mode 100644 index 000000000..162d6799b --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qanalyzer_p.h @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#ifndef QANALYZER_P_H +#define QANALYZER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qreader_p.h" +#include "qtokenstream_p.h" +#include "qclucene_global_p.h" + +#include +#include +#include +#include +#include + +CL_NS_DEF(analysis) + class Analyzer; +CL_NS_END +CL_NS_USE(analysis) + +QT_BEGIN_NAMESPACE + +class QCLuceneIndexWriter; +class QCLuceneQueryParser; +class QCLuceneStopAnalyzer; +class QCLuceneSimpleAnalyzer; +class QCLuceneKeywordAnalyzer; +class QCLuceneStandardAnalyzer; +class QCLuceneWhitespaceAnalyzer; +class QCLucenePerFieldAnalyzerWrapper; + +class QHELP_EXPORT QCLuceneAnalyzerPrivate : public QSharedData +{ +public: + QCLuceneAnalyzerPrivate(); + QCLuceneAnalyzerPrivate(const QCLuceneAnalyzerPrivate &other); + + ~QCLuceneAnalyzerPrivate(); + + Analyzer *analyzer; + bool deleteCLuceneAnalyzer; + +private: + QCLuceneAnalyzerPrivate &operator=(const QCLuceneAnalyzerPrivate &other); +}; + +class QHELP_EXPORT QCLuceneAnalyzer +{ +public: + virtual ~QCLuceneAnalyzer(); + + qint32 positionIncrementGap(const QString &fieldName) const; + QCLuceneTokenStream tokenStream(const QString &fieldName, + const QCLuceneReader &reader) const; + +protected: + friend class QCLuceneIndexWriter; + friend class QCLuceneQueryParser; + friend class QCLuceneStopAnalyzer; + friend class QCLuceneSimpleAnalyzer; + friend class QCLuceneKeywordAnalyzer; + friend class QCLuceneStandardAnalyzer; + friend class QCLuceneWhitespaceAnalyzer; + friend class QCLucenePerFieldAnalyzerWrapper; + QSharedDataPointer d; + +private: + QCLuceneAnalyzer(); +}; + +class QHELP_EXPORT QCLuceneStandardAnalyzer : public QCLuceneAnalyzer +{ +public: + QCLuceneStandardAnalyzer(); + QCLuceneStandardAnalyzer(const QStringList &stopWords); + + ~QCLuceneStandardAnalyzer(); +}; + +class QHELP_EXPORT QCLuceneWhitespaceAnalyzer : public QCLuceneAnalyzer +{ +public: + QCLuceneWhitespaceAnalyzer(); + ~QCLuceneWhitespaceAnalyzer(); +}; + +class QHELP_EXPORT QCLuceneSimpleAnalyzer : public QCLuceneAnalyzer +{ +public: + QCLuceneSimpleAnalyzer(); + ~QCLuceneSimpleAnalyzer(); +}; + +class QHELP_EXPORT QCLuceneStopAnalyzer : public QCLuceneAnalyzer +{ +public: + QCLuceneStopAnalyzer(); + QCLuceneStopAnalyzer(const QStringList &stopWords); + + ~QCLuceneStopAnalyzer(); + + QStringList englishStopWords() const; +}; + +class QHELP_EXPORT QCLuceneKeywordAnalyzer : public QCLuceneAnalyzer +{ +public: + QCLuceneKeywordAnalyzer(); + ~QCLuceneKeywordAnalyzer(); +}; + +class QHELP_EXPORT QCLucenePerFieldAnalyzerWrapper : public QCLuceneAnalyzer +{ +public: + QCLucenePerFieldAnalyzerWrapper(QCLuceneAnalyzer *defaultAnalyzer); + ~QCLucenePerFieldAnalyzerWrapper(); + + void addAnalyzer(const QString &fieldName, QCLuceneAnalyzer *analyzer); + +private: + QList analyzers; +}; + +QT_END_NAMESPACE + +#endif // QANALYZER_P_H diff --git a/src/assistant/lib/fulltextsearch/qclucene-config_p.h b/src/assistant/lib/fulltextsearch/qclucene-config_p.h new file mode 100644 index 000000000..476296cf5 --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qclucene-config_p.h @@ -0,0 +1,557 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#ifndef QCLUCENE_CONFIG_P_H +#define QCLUCENE_CONFIG_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include + +#ifndef _SRC_CLUCENE_CLUCENE_CONFIG_H +#define _SRC_CLUCENE_CLUCENE_CONFIG_H 1 + +/* +src/CLucene/clucene-config.h. +Generated +automatically +at +end +of +configure. +*/ +/* config.h.tmp. Generated by configure. */ +/* config.h.tmp.in. Generated from configure.ac by autoheader. */ + +/* Disable multithreading */ +/* #undef _CL_DISABLE_MULTITHREADING */ + +/* Define to 1 if you have the header file. */ +#ifndef _CL_HAVE_ALGORITHM +#define _CL_HAVE_ALGORITHM 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef _CL_HAVE_CTYPE_H +#define _CL_HAVE_CTYPE_H 1 +#endif + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#ifndef _CL_HAVE_DIRENT_H +#define _CL_HAVE_DIRENT_H 1 +#endif + +#if !defined (__MINGW32__) + /* Define to 1 if you have the header file. */ +# ifndef _CL_HAVE_DLFCN_H +# define _CL_HAVE_DLFCN_H 1 +# endif +#endif + +/* Define to 1 if you have the header file. */ +#ifndef _CL_HAVE_ERRNO_H +#define _CL_HAVE_ERRNO_H 1 +#endif + +#if !defined(__SUNPRO_CC) && !defined(__SUNPRO_C) + /* Define to 1 if you have the header file. */ +# ifndef _CL_HAVE_EXT_HASH_MAP +# define _CL_HAVE_EXT_HASH_MAP 1 +# endif + + /* Define to 1 if you have the header file. */ +# ifndef _CL_HAVE_EXT_HASH_SET +# define _CL_HAVE_EXT_HASH_SET 1 +# endif +#endif + +/* Define to 1 if you have the header file. */ +#ifndef _CL_HAVE_FCNTL_H +#define _CL_HAVE_FCNTL_H 1 +#endif + +#if !defined(__xlC__) && !defined(__xlc__) && !defined (__MINGW32__) && \ + !defined(__HP_aCC) && !defined(__SUNPRO_C) && !defined(__SUNPRO_CC) || \ + defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x550) || (defined(__HP_aCC) && defined(__ia64)) + /* Define to 1 if the system has the type `float_t'. */ +# ifndef _CL_HAVE_FLOAT_T +# define _CL_HAVE_FLOAT_T 1 +# endif +#endif + +/* Define to 1 if you have the header file. */ +#ifndef _CL_HAVE_FUNCTIONAL +#define _CL_HAVE_FUNCTIONAL 1 +#endif + +/* Does not support new float byte<->float conversions */ +#ifndef _CL_HAVE_FUNCTIONING_FLOAT_BYTE +#define _CL_HAVE_FUNCTIONING_FLOAT_BYTE +#endif + +/* Define to 1 if you have the `getpagesize' function. */ +#ifndef _CL_HAVE_GETPAGESIZE +#define _CL_HAVE_GETPAGESIZE 1 +#endif + +/* Define to 1 if you have the header file. */ +/* #undef _CL_HAVE_HASH_MAP */ + +/* Define to 1 if you have the header file. */ +/* #undef _CL_HAVE_HASH_SET */ + +/* Define to 1 if the system has the type `intptr_t'. */ +#ifndef _CL_HAVE_INTPTR_T +#define _CL_HAVE_INTPTR_T 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef _CL_HAVE_INTTYPES_H +#define _CL_HAVE_INTTYPES_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef _CL_HAVE_LIST +#define _CL_HAVE_LIST 1 +#endif + +/* Define to 1 if you have the `lltoa' function. */ +/* #undef _CL_HAVE_LLTOA */ + +#if defined(__MINGW32__) + /* Define to 1 if you have the `lltow' function. */ +# ifndef _CL_HAVE_LLTOW +# define _CL_HAVE_LLTOW 1 +# endif +#endif + +#if !defined(__SUNPRO_CC) && !defined(__SUNPRO_C) && !defined(__xlC__) && !defined(__xlc__) + /* Define to 1 if long double works and has more range or precision than double. */ +# ifndef _CL_HAVE_LONG_DOUBLE +# define _CL_HAVE_LONG_DOUBLE 1 +# endif +#endif + +/* Define to 1 if you have the header file. */ +#ifndef _CL_HAVE_MAP +#define _CL_HAVE_MAP 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef _CL_HAVE_MATH_H +#define _CL_HAVE_MATH_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef _CL_HAVE_MEMORY_H +#define _CL_HAVE_MEMORY_H 1 +#endif + +#if !defined(__MINGW32__) && !defined(__HP_aCC) && !defined(__xlC__) && !defined(__xlc__) + /* Define to 1 if you have a working `mmap' system call. */ +# ifndef _CL_HAVE_MMAP +# define _CL_HAVE_MMAP 1 +# endif +#endif + +/* define if the compiler implements namespaces */ +#ifndef _CL_HAVE_NAMESPACES +#define _CL_HAVE_NAMESPACES +#endif + +#if defined(__SUNPRO_CC) || defined(__SUNPRO_C) || defined(__HP_aCC) || defined(__xlC__) || defined(__xlc__) + /* Define if you have the nanosleep function */ +# ifndef _CL_HAVE_NANOSLEEP +# define _CL_HAVE_NANOSLEEP 1 +# endif +#endif + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef _CL_HAVE_NDIR_H */ + +/* Does not support new float byte<->float conversions */ +/* #undef _CL_HAVE_NO_FLOAT_BYTE */ + +/* Does not support try/catch blocks */ +/* #undef _CL_HAVE_NO_FUNCTION_TRY_BLOCKS */ + +/* Define to 1 if you have the `printf' function. */ +#ifndef _CL_HAVE_PRINTF +#define _CL_HAVE_PRINTF 1 +#endif + +#if !defined(__MINGW32__) + /* Define if you have POSIX threads libraries and header files. */ +# ifndef _CL_HAVE_PTHREAD +# define _CL_HAVE_PTHREAD 1 +# endif +#endif + +/* Define if recursive pthread mutexes are available */ +/* #undef _CL_HAVE_PTHREAD_MUTEX_RECURSIVE */ + +/* Define to 1 if you have the header file. */ +#ifndef _CL_HAVE_SET +#define _CL_HAVE_SET 1 +#endif + +/* Define to 1 if you have the `snprintf' function. */ +#ifndef _CL_HAVE_SNPRINTF +#define _CL_HAVE_SNPRINTF 1 +#endif + +/* Defined if the snprintf overflow test fails */ +/* #undef _CL_HAVE_SNPRINTF_BUG */ + +/* Define to 1 if you have the `snwprintf' function. */ +/* #undef _CL_HAVE_SNWPRINTF */ + +#if !defined(__HP_aCC) && !defined(__SUNPRO_CC) && !defined(__SUNPRO_C) + /* define if the compiler supports ISO C++ standard library */ +# ifndef _CL_HAVE_STD +# define _CL_HAVE_STD +# endif +#endif + +/* Define to 1 if you have the header file. */ +#ifndef _CL_HAVE_STDARG_H +#define _CL_HAVE_STDARG_H 1 +#endif + +/* x */ +#ifndef _CL_HAVE_STDEXCEPT +#define _CL_HAVE_STDEXCEPT +#endif + +#if !defined(__SUNPRO_CC) && !defined(__SUNPRO_C) && !defined(__HP_aCC) && \ + !defined(__xlC__) && !defined(__xlc__) + /* Define to 1 if you have the header file. */ +# ifndef _CL_HAVE_STDINT_H +# define _CL_HAVE_STDINT_H 1 +# endif +#endif + +#if !defined(__HP_aCC) + /* Define to 1 if you have the header file. */ +# ifndef _CL_HAVE_STDLIB_H +# define _CL_HAVE_STDLIB_H 1 +# endif + + /* define if the compiler supports Standard Template Library */ +# ifndef _CL_HAVE_STL +# define _CL_HAVE_STL +# endif +#endif + +/* Define to 1 if you have the header file. */ +#ifndef _CL_HAVE_STRINGS_H +#define _CL_HAVE_STRINGS_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef _CL_HAVE_STRING_H +#define _CL_HAVE_STRING_H 1 +#endif + +/* Define to 1 if you have the `strlwr' function. */ +/* #undef _CL_HAVE_STRLWR */ + +/* Define to 1 if you have the `strtoll' function. */ +/* #undef _CL_HAVE_STRTOLL */ + +/* Define to 1 if you have the `strupr' function. */ +/* #undef _CL_HAVE_STRUPR */ + +/* Defined if the swprintf test fails */ +#ifndef _CL_HAVE_SWPRINTF_BUG +#define _CL_HAVE_SWPRINTF_BUG +#endif + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef _CL_HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef _CL_HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#ifndef _CL_HAVE_SYS_STAT_H +#define _CL_HAVE_SYS_STAT_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef _CL_HAVE_SYS_TIMEB_H +#define _CL_HAVE_SYS_TIMEB_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef _CL_HAVE_SYS_TYPES_H +#define _CL_HAVE_SYS_TYPES_H 1 +#endif + +#if defined(__MINGW32__) + /* Define to 1 if you have the header file. */ + # ifndef _CL_HAVE_TCHAR_H + # define _CL_HAVE_TCHAR_H 1 + # endif +#endif + +#if defined(__MINGW32__) || defined(__SUNPRO_CC) || defined(__SUNPRO_C) + /* Define to 1 if you have the `tell' function. */ +# ifndef _CL_HAVE_TELL +# define _CL_HAVE_TELL 1 +# endif +#endif + +/* Define to 1 if you have the header file. */ +#ifndef _CL_HAVE_UNISTD_H +#define _CL_HAVE_UNISTD_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef _CL_HAVE_VECTOR +#define _CL_HAVE_VECTOR 1 +#endif + +/* Define to 1 if you have the `vsnwprintf' function. */ +/* #undef _CL_HAVE_VSNWPRINTF */ + +/* Define to 1 if you have the header file. */ +#ifndef _CL_HAVE_WCHAR_H +#define _CL_HAVE_WCHAR_H 1 +#endif + +/* Define to 1 if the system has the type `wchar_t'. */ +#ifndef _CL_HAVE_WCHAR_T +#define _CL_HAVE_WCHAR_T 1 +#endif + +#if !defined(__SUNPRO_CC) && !defined(__SUNPRO_C) && !defined(__MINGW32__) && \ + !defined(Q_OS_MAC) && !defined(__HP_aCC) + /* Define to 1 if you have the `wcscasecmp' function. */ +# ifndef _CL_HAVE_WCSCASECMP +# define _CL_HAVE_WCSCASECMP 1 +# endif +#endif + +/* Define to 1 if you have the `wcscat' function. */ +#ifndef _CL_HAVE_WCSCAT +#define _CL_HAVE_WCSCAT 1 +#endif + +/* Define to 1 if you have the `wcschr' function. */ +#ifndef _CL_HAVE_WCSCHR +#define _CL_HAVE_WCSCHR 1 +#endif + +/* Define to 1 if you have the `wcscmp' function. */ +#ifndef _CL_HAVE_WCSCMP +#define _CL_HAVE_WCSCMP 1 +#endif + +/* Define to 1 if you have the `wcscpy' function. */ +#ifndef _CL_HAVE_WCSCPY +#define _CL_HAVE_WCSCPY 1 +#endif + +/* Define to 1 if you have the `wcscspn' function. */ +#ifndef _CL_HAVE_WCSCSPN +#define _CL_HAVE_WCSCSPN 1 +#endif + +#if defined(__MINGW32__) + /* Define to 1 if you have the `wcsicmp' function. */ +# ifndef _CL_HAVE_WCSICMP +# define _CL_HAVE_WCSICMP 1 +# endif +#endif + +/* Define to 1 if you have the `wcslen' function. */ +#ifndef _CL_HAVE_WCSLEN +#define _CL_HAVE_WCSLEN 1 +#endif + +/* Define to 1 if you have the `wcsncmp' function. */ +#ifndef _CL_HAVE_WCSNCMP +#define _CL_HAVE_WCSNCMP 1 +#endif + +/* Define to 1 if you have the `wcsncpy' function. */ +#ifndef _CL_HAVE_WCSNCPY +#define _CL_HAVE_WCSNCPY 1 +#endif + +/* Define to 1 if you have the `wcsstr' function. */ +#ifndef _CL_HAVE_WCSSTR +#define _CL_HAVE_WCSSTR 1 +#endif + +/* Define to 1 if you have the `wcstod' function. */ +#ifndef _CL_HAVE_WCSTOD +#define _CL_HAVE_WCSTOD 1 +#endif + +#if !defined(__SUNPRO_CC) && !defined(__SUNPRO_C) && !defined(__HP_aCC) + /* Define to 1 if you have the `wcstoll' function. */ +# ifndef _CL_HAVE_WCSTOLL +# define _CL_HAVE_WCSTOLL 1 +# endif +#endif + +#if defined(__MINGW32__) + /* Define to 1 if you have the `wcsupr' function. */ +# ifndef _CL_HAVE_WCSUPR +# define _CL_HAVE_WCSUPR 1 +# endif +#endif + +#if defined(__SUNPRO_CC) || defined(__SUNPRO_C) || defined(__HP_aCC) + /* Define to 1 if you have a functioning header file. */ +# ifndef _CL_HAVE_WCTYPE_H +# define _CL_HAVE_WCTYPE_H +# endif +#endif + +/* Define to 1 if you have the `wprintf' function. */ +/* #undef _CL_HAVE_WPRINTF */ + +#if defined(__MINGW32__) + /* Define to 1 if you have the `_filelength' function. */ +# ifndef _CL_HAVE__FILELENGTH +# define _CL_HAVE__FILELENGTH 1 +# endif +#endif + +/* How to define a static const in a class */ +#ifndef LUCENE_STATIC_CONSTANT_SYNTAX +#define LUCENE_STATIC_CONSTANT_SYNTAX 1 +#endif + +/* Name of package */ +#ifndef _CL_PACKAGE +#define _CL_PACKAGE "clucene-core" +#endif + +/* Define to the address where bug reports for this package should be sent. */ +#ifndef _CL_PACKAGE_BUGREPORT +#define _CL_PACKAGE_BUGREPORT "" +#endif + +/* Define to the full name of this package. */ +#ifndef _CL_PACKAGE_NAME +#define _CL_PACKAGE_NAME "" +#endif + +/* Define to the full name and version of this package. */ +#ifndef _CL_PACKAGE_STRING +#define _CL_PACKAGE_STRING "" +#endif + +/* Define to the one symbol short name of this package. */ +#ifndef _CL_PACKAGE_TARNAME +#define _CL_PACKAGE_TARNAME "" +#endif + +/* Define to the version of this package. */ +#ifndef _CL_PACKAGE_VERSION +#define _CL_PACKAGE_VERSION "" +#endif + +/* Define to the necessary symbol if this constant uses a non-standard name on + your system. */ +/* #undef _CL_PTHREAD_CREATE_JOINABLE */ + +/* The size of a `unsigned char', as computed by sizeof. */ +/* #undef _CL_SIZEOF_UNSIGNED_CHAR */ + +/* The size of a `unsigned int', as computed by sizeof. */ +/* #undef _CL_SIZEOF_UNSIGNED_INT */ + +/* The size of a `unsigned long', as computed by sizeof. */ +/* #undef _CL_SIZEOF_UNSIGNED_LONG */ + +/* The size of a `unsigned long long', as computed by sizeof. */ +/* #undef _CL_SIZEOF_UNSIGNED_LONG_LONG */ + +/* The size of a `unsigned __int64', as computed by sizeof. */ +/* #undef _CL_SIZEOF_UNSIGNED___INT64 */ + +/* Define to 1 if the `S_IS*' macros in do not work properly. */ +/* #undef _CL_STAT_MACROS_BROKEN */ + +#if !defined(__HP_aCC) + /* Define to 1 if you have the ANSI C header files. */ +# ifndef _CL_STDC_HEADERS +# define _CL_STDC_HEADERS 1 +# endif + +/* Define to 1 if you can safely include both and . */ +# ifndef _CL_TIME_WITH_SYS_TIME +# define _CL_TIME_WITH_SYS_TIME 1 +# endif +#endif + +/* Version number of package */ +#ifndef _CL_VERSION +#define _CL_VERSION "0.9.17" +#endif + +/* Forces into Ascii mode */ +/* #undef _ASCII */ + +/* Conditional Debugging */ +/* #undef _CL__CND_DEBUG */ + +/* debugging option */ +/* #undef _DEBUG */ + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* If not already defined, then define as a datatype of *exactly* 32 bits. */ +/* #undef uint32_t */ + +/* If not already defined, then define as a datatype of *exactly* 64 bits. */ +/* #undef uint64_t */ + +/* If not already defined, then define as a datatype of *exactly* 8 bits. */ +/* #undef uint8_t */ + +/* once: +_SRC_CLUCENE_CLUCENE_CONFIG_H +*/ +#endif + + +#if defined Q_CC_MSVC && _MSC_VER < 1300 +# define LUCENE_NO_STDC_NAMESPACE +#endif + + +#endif // QCLUCENE_CONFIG_P_H + diff --git a/src/assistant/lib/fulltextsearch/qclucene_global_p.h b/src/assistant/lib/fulltextsearch/qclucene_global_p.h new file mode 100644 index 000000000..887b113e5 --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qclucene_global_p.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#ifndef QCLUCENE_GLOBAL_P_H +#define QCLUCENE_GLOBAL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#if !defined(_MSC_VER) +# include "qclucene-config_p.h" +#endif + +#include +#include + +#if !defined(_MSC_VER) && !defined(__MINGW32__) && defined(_CL_HAVE_WCHAR_H) && defined(_CL_HAVE_WCHAR_T) +# if !defined(TCHAR) +# define TCHAR wchar_t +# endif +#else +# include +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#if !defined(QT_SHARED) && !defined(QT_DLL) +# define QHELP_EXPORT +#elif defined(QHELP_LIB) +# define QHELP_EXPORT Q_DECL_EXPORT +#else +# define QHELP_EXPORT Q_DECL_IMPORT +#endif + +// +// W A R N I N G +// ------------- +// +// adjustments here, need to be done in +// QTDIR/src/3rdparty/clucene/src/CLucene/StdHeader.h as well +// +#if defined(_LUCENE_DONTIMPLEMENT_NS_MACROS) + +#elif !defined(DISABLE_NAMESPACE) +# ifdef QT_NAMESPACE +# define CL_NS_DEF(sub) namespace QT_NAMESPACE { namespace lucene{ namespace sub{ +# define CL_NS_DEF2(sub,sub2) namespace QT_NAMESPACE { namespace lucene{ namespace sub{ namespace sub2 { + +# define CL_NS_END }}} +# define CL_NS_END2 }}}} + +# define CL_NS_USE(sub) using namespace QT_NAMESPACE::lucene::sub; +# define CL_NS_USE2(sub,sub2) using namespace QT_NAMESPACE::lucene::sub::sub2; + +# define CL_NS(sub) QT_NAMESPACE::lucene::sub +# define CL_NS2(sub,sub2) QT_NAMESPACE::lucene::sub::sub2 +# else +# define CL_NS_DEF(sub) namespace lucene{ namespace sub{ +# define CL_NS_DEF2(sub,sub2) namespace lucene{ namespace sub{ namespace sub2 { + +# define CL_NS_END }} +# define CL_NS_END2 }}} + +# define CL_NS_USE(sub) using namespace lucene::sub; +# define CL_NS_USE2(sub,sub2) using namespace lucene::sub::sub2; + +# define CL_NS(sub) lucene::sub +# define CL_NS2(sub,sub2) lucene::sub::sub2 +# endif +#else +# define CL_NS_DEF(sub) +# define CL_NS_DEF2(sub, sub2) +# define CL_NS_END +# define CL_NS_END2 +# define CL_NS_USE(sub) +# define CL_NS_USE2(sub,sub2) +# define CL_NS(sub) +# define CL_NS2(sub,sub2) +#endif + +namespace { + TCHAR* QStringToTChar(const QString &str) + { + TCHAR *string = new TCHAR[(str.length() +1) * sizeof(TCHAR)]; + memset(string, 0, (str.length() +1) * sizeof(TCHAR)); + #if defined(UNICODE) || defined(_CL_HAVE_WCHAR_H) && defined(_CL_HAVE_WCHAR_T) + str.toWCharArray(string); + #else + const QByteArray ba = str.toAscii(); + strcpy(string, ba.constData()); + #endif + return string; + } + + QString TCharToQString(const TCHAR *string) + { + #if defined(UNICODE) || defined(_CL_HAVE_WCHAR_H) && defined(_CL_HAVE_WCHAR_T) + QString retValue = QString::fromWCharArray(string); + return retValue; + #else + return QString(QLatin1String(string)); + #endif + } +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QCLUCENE_GLOBAL_P_H diff --git a/src/assistant/lib/fulltextsearch/qdocument.cpp b/src/assistant/lib/fulltextsearch/qdocument.cpp new file mode 100644 index 000000000..3c4cc068d --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qdocument.cpp @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#include "qdocument_p.h" +#include "qreader_p.h" +#include "qclucene_global_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +QCLuceneDocumentPrivate::QCLuceneDocumentPrivate() + : QSharedData() +{ + document = 0; + deleteCLuceneDocument = true; +} + +QCLuceneDocumentPrivate::QCLuceneDocumentPrivate(const QCLuceneDocumentPrivate &other) + : QSharedData() +{ + document = _CL_POINTER(other.document); + deleteCLuceneDocument = other.deleteCLuceneDocument; +} + +QCLuceneDocumentPrivate::~QCLuceneDocumentPrivate() +{ + if (deleteCLuceneDocument) + _CLDECDELETE(document); +} + + +QCLuceneDocument::QCLuceneDocument() + : d(new QCLuceneDocumentPrivate()) +{ + // nothing todo + d->document = new lucene::document::Document(); +} + +QCLuceneDocument::~QCLuceneDocument() +{ + qDeleteAll(fieldList); + fieldList.clear(); +} + +void QCLuceneDocument::add(QCLuceneField *field) +{ + field->d->deleteCLuceneField = false; + d->document->add(*field->d->field); + fieldList.append(field); +} + +QCLuceneField* QCLuceneDocument::getField(const QString &name) const +{ + QCLuceneField* field = 0; + foreach (field, fieldList) { + if (field->name() == name && field->d->field != 0) + return field; + } + + field = 0; + TCHAR *fieldName = QStringToTChar(name); + lucene::document::Field *f = d->document->getField(fieldName); + if (f) { + field = new QCLuceneField(); + field->d->field = f; + fieldList.append(field); + field->d->deleteCLuceneField = false; + + lucene::util::Reader *r = f->readerValue(); + if (r) { + field->reader->d->reader = r; + field->reader->d->deleteCLuceneReader = false; + } + } + delete [] fieldName; + + return field; +} + +QString QCLuceneDocument::get(const QString &name) const +{ + QCLuceneField* field = getField(name); + if (field) + return field->stringValue(); + + return QString(); +} + +QString QCLuceneDocument::toString() const +{ + return TCharToQString(d->document->toString()); +} + +void QCLuceneDocument::setBoost(qreal boost) +{ + d->document->setBoost(qreal(boost)); +} + +qreal QCLuceneDocument::getBoost() const +{ + return qreal(d->document->getBoost()); +} + +void QCLuceneDocument::removeField(const QString &name) +{ + TCHAR *fieldName = QStringToTChar(name); + d->document->removeField(fieldName); + delete [] fieldName; + + QList tmp; + lucene::document::DocumentFieldEnumeration *dfe = d->document->fields(); + while (dfe->hasMoreElements()) { + const lucene::document::Field* f = dfe->nextElement(); + foreach (QCLuceneField* field, fieldList) { + if (f == field->d->field) { + tmp.append(field); + break; + } + } + } + _CLDELETE(dfe); + fieldList = tmp; +} + +void QCLuceneDocument::removeFields(const QString &name) +{ + for (qint32 i = fieldList.count() -1; i >= 0; --i) { + QCLuceneField* field = fieldList.at(i); + if (field->name() == name) + delete fieldList.takeAt(i); + } + + TCHAR *fieldName = QStringToTChar(name); + d->document->removeFields(fieldName); + delete [] fieldName; +} + +QStringList QCLuceneDocument::getValues(const QString &name) const +{ + TCHAR *fieldName = QStringToTChar(name); + TCHAR **values = d->document->getValues(fieldName); + + QStringList retValue; + if (values) { + for (qint32 i = 0; 0 != values[i]; ++i) { + retValue.append(TCharToQString((const TCHAR*)values[i])); + delete [] values[i]; values[i] = 0; + } + delete values; + } + + delete [] fieldName; + return retValue; +} + +void QCLuceneDocument::clear() +{ + d->document->clear(); + qDeleteAll(fieldList); + fieldList.clear(); +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/fulltextsearch/qdocument_p.h b/src/assistant/lib/fulltextsearch/qdocument_p.h new file mode 100644 index 000000000..31369af2a --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qdocument_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#ifndef QDOCUMENT_P_H +#define QDOCUMENT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qfield_p.h" +#include "qclucene_global_p.h" + +#include +#include +#include +#include +#include + +CL_NS_DEF(document) + class Document; +CL_NS_END +CL_NS_USE(document) + +QT_BEGIN_NAMESPACE + +class QCLuceneHits; +class QCLuceneIndexReader; +class QCLuceneIndexWriter; +class QCLuceneIndexSearcher; +class QCLuceneMultiSearcher; + +class QHELP_EXPORT QCLuceneDocumentPrivate : public QSharedData +{ +public: + QCLuceneDocumentPrivate(); + QCLuceneDocumentPrivate(const QCLuceneDocumentPrivate &other); + + ~QCLuceneDocumentPrivate(); + + Document *document; + bool deleteCLuceneDocument; + +private: + QCLuceneDocumentPrivate &operator=(const QCLuceneDocumentPrivate &other); +}; + +class QHELP_EXPORT QCLuceneDocument +{ +public: + QCLuceneDocument(); + ~QCLuceneDocument(); + + void add(QCLuceneField *field); + QCLuceneField* getField(const QString &name) const; + QString get(const QString &name) const; + QString toString() const; + void setBoost(qreal boost); + qreal getBoost() const; + void removeField(const QString &name); + void removeFields(const QString &name); + QStringList getValues(const QString &name) const; + void clear(); + +protected: + friend class QCLuceneHits; + friend class QCLuceneIndexReader; + friend class QCLuceneIndexWriter; + friend class QCLuceneIndexSearcher; + friend class QCLuceneMultiSearcher; + QSharedDataPointer d; + +private: + mutable QList fieldList; +}; + +QT_END_NAMESPACE + +#endif // QDOCUMENT_P_H diff --git a/src/assistant/lib/fulltextsearch/qfield.cpp b/src/assistant/lib/fulltextsearch/qfield.cpp new file mode 100644 index 000000000..448acf0e6 --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qfield.cpp @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#include "qfield_p.h" +#include "qreader_p.h" +#include "qclucene_global_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +QCLuceneFieldPrivate::QCLuceneFieldPrivate() + : QSharedData() +{ + field = 0; + deleteCLuceneField = true; +} + +QCLuceneFieldPrivate::QCLuceneFieldPrivate(const QCLuceneFieldPrivate &other) + : QSharedData() +{ + field = _CL_POINTER(other.field); + deleteCLuceneField = other.deleteCLuceneField; +} + +QCLuceneFieldPrivate::~QCLuceneFieldPrivate() +{ + if (deleteCLuceneField) + _CLDECDELETE(field); +} + + +QCLuceneField::QCLuceneField() + : d(new QCLuceneFieldPrivate()) + , reader(0) +{ + // nothing todo +} + +QCLuceneField::QCLuceneField(const QString &name, const QString &value, int configs) + : d(new QCLuceneFieldPrivate()) + , reader(0) +{ + TCHAR* fieldName = QStringToTChar(name); + TCHAR* fieldValue = QStringToTChar(value); + + d->field = new lucene::document::Field(fieldName, fieldValue, configs); + + delete [] fieldName; + delete [] fieldValue; +} + +QCLuceneField::QCLuceneField(const QString &name, QCLuceneReader *reader, + int configs) + : d(new QCLuceneFieldPrivate()) + , reader(reader) +{ + TCHAR* fieldName = QStringToTChar(name); + + reader->d->deleteCLuceneReader = false; // clucene takes ownership + d->field = new lucene::document::Field(fieldName, reader->d->reader, configs); + + delete [] fieldName; +} + +QCLuceneField::~QCLuceneField() +{ + delete reader; +} + +QString QCLuceneField::name() const +{ + return TCharToQString(d->field->name()); +} + +QString QCLuceneField::stringValue() const +{ + return TCharToQString((const TCHAR*)d->field->stringValue()); +} + +QCLuceneReader* QCLuceneField::readerValue() const +{ + return reader; +} + +bool QCLuceneField::isStored() const +{ + return d->field->isStored(); +} + +bool QCLuceneField::isIndexed() const +{ + return d->field->isIndexed(); +} + +bool QCLuceneField::isTokenized() const +{ + return d->field->isTokenized(); +} + +bool QCLuceneField::isCompressed() const +{ + return d->field->isCompressed(); +} + +void QCLuceneField::setConfig(int termVector) +{ + d->field->setConfig(termVector); +} + +bool QCLuceneField::isTermVectorStored() const +{ + return d->field->isTermVectorStored(); +} + +bool QCLuceneField::isStoreOffsetWithTermVector() const +{ + return d->field->isStoreOffsetWithTermVector(); +} + +bool QCLuceneField::isStorePositionWithTermVector() const +{ + return d->field->isStorePositionWithTermVector(); +} + +qreal QCLuceneField::getBoost() const +{ + return qreal(d->field->getBoost()); +} + +void QCLuceneField::setBoost(qreal value) +{ + d->field->setBoost(qreal(value)); +} + +bool QCLuceneField::isBinary() const +{ + return d->field->isBinary(); +} + +bool QCLuceneField::getOmitNorms() const +{ + return d->field->getOmitNorms(); +} + +void QCLuceneField::setOmitNorms(bool omitNorms) +{ + d->field->setOmitNorms(omitNorms); +} + +QString QCLuceneField::toString() const +{ + return TCharToQString(d->field->toString()); +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/fulltextsearch/qfield_p.h b/src/assistant/lib/fulltextsearch/qfield_p.h new file mode 100644 index 000000000..39f2ff308 --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qfield_p.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#ifndef QFIELD_P_H +#define QFIELD_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qclucene_global_p.h" + +#include +#include +#include + +CL_NS_DEF(document) + class Field; +CL_NS_END +CL_NS_USE(document) + +QT_BEGIN_NAMESPACE + +class QCLuceneReader; +class QCLuceneDocument; + +class QHELP_EXPORT QCLuceneFieldPrivate : public QSharedData +{ +public: + QCLuceneFieldPrivate(); + QCLuceneFieldPrivate(const QCLuceneFieldPrivate &other); + + ~QCLuceneFieldPrivate(); + + Field *field; + bool deleteCLuceneField; + +private: + QCLuceneFieldPrivate &operator=(const QCLuceneFieldPrivate &other); +}; + +class QHELP_EXPORT QCLuceneField +{ +public: + enum Store { + STORE_YES = 1, + STORE_NO = 2, + STORE_COMPRESS = 4 + }; + + enum Index { + INDEX_NO = 16, + INDEX_TOKENIZED = 32, + INDEX_UNTOKENIZED = 64, + INDEX_NONORMS = 128 + }; + + enum TermVector { + TERMVECTOR_NO = 256, + TERMVECTOR_YES = 512, + TERMVECTOR_WITH_POSITIONS = 1024, + TERMVECTOR_WITH_OFFSETS = 2048 + }; + + QCLuceneField(const QString &name, const QString &value, int configs); + QCLuceneField(const QString &name, QCLuceneReader *reader, int configs); + ~QCLuceneField(); + + QString name() const; + QString stringValue() const; + QCLuceneReader* readerValue() const; + bool isStored() const; + bool isIndexed() const; + bool isTokenized() const; + bool isCompressed() const; + void setConfig(int termVector); + bool isTermVectorStored() const; + bool isStoreOffsetWithTermVector() const; + bool isStorePositionWithTermVector() const; + qreal getBoost() const; + void setBoost(qreal value); + bool isBinary() const; + bool getOmitNorms() const; + void setOmitNorms(bool omitNorms); + QString toString() const; + +protected: + QCLuceneField(); + friend class QCLuceneDocument; + QSharedDataPointer d; + +private: + QCLuceneReader* reader; +}; + +QT_END_NAMESPACE + +#endif // QFIELD_P_H diff --git a/src/assistant/lib/fulltextsearch/qfilter.cpp b/src/assistant/lib/fulltextsearch/qfilter.cpp new file mode 100644 index 000000000..4807193ff --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qfilter.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#include "qfilter_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +QCLuceneFilterPrivate::QCLuceneFilterPrivate() + : QSharedData() +{ + filter = 0; + deleteCLuceneFilter = true; +} + +QCLuceneFilterPrivate::QCLuceneFilterPrivate(const QCLuceneFilterPrivate &other) + : QSharedData() +{ + filter = _CL_POINTER(other.filter); + deleteCLuceneFilter = other.deleteCLuceneFilter; +} + +QCLuceneFilterPrivate::~QCLuceneFilterPrivate () +{ + if (deleteCLuceneFilter) + _CLDECDELETE(filter); +} + + +QCLuceneFilter::QCLuceneFilter() + : d(new QCLuceneFilterPrivate()) +{ + // nothing todo +} + +QCLuceneFilter::~QCLuceneFilter() +{ + // nothing todo +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/fulltextsearch/qfilter_p.h b/src/assistant/lib/fulltextsearch/qfilter_p.h new file mode 100644 index 000000000..67f6615b1 --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qfilter_p.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#ifndef QFilter_P_H +#define QFilter_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qclucene_global_p.h" + +#include +#include + +CL_NS_DEF(search) + class Filter; +CL_NS_END +CL_NS_USE(search) + +QT_BEGIN_NAMESPACE + +class QCLuceneHits; +class QCLuceneSearcher; + +class QHELP_EXPORT QCLuceneFilterPrivate : public QSharedData +{ +public: + QCLuceneFilterPrivate(); + QCLuceneFilterPrivate(const QCLuceneFilterPrivate &other); + + ~QCLuceneFilterPrivate (); + + Filter *filter; + bool deleteCLuceneFilter; + +private: + QCLuceneFilterPrivate &operator=(const QCLuceneFilterPrivate &other); +}; + +class QHELP_EXPORT QCLuceneFilter +{ + QCLuceneFilter(); + virtual ~QCLuceneFilter(); + +protected: + friend class QCLuceneHits; + friend class QCLuceneSearcher; + QSharedDataPointer d; +}; + +QT_END_NAMESPACE + +#endif // QFilter_P_H diff --git a/src/assistant/lib/fulltextsearch/qhits.cpp b/src/assistant/lib/fulltextsearch/qhits.cpp new file mode 100644 index 000000000..5223a743d --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qhits.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#include "qhits_p.h" +#include "qsearchable_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +QCLuceneHitsPrivate::QCLuceneHitsPrivate() + : QSharedData() +{ + hits = 0; + deleteCLuceneHits = true; +} + +QCLuceneHitsPrivate::QCLuceneHitsPrivate(const QCLuceneHitsPrivate &other) + : QSharedData() +{ + hits = _CL_POINTER(other.hits); + deleteCLuceneHits = other.deleteCLuceneHits; +} + +QCLuceneHitsPrivate::~QCLuceneHitsPrivate() +{ + if (deleteCLuceneHits) + _CLDECDELETE(hits); +} + + +QCLuceneHits::QCLuceneHits(const QCLuceneSearcher &searcher, + const QCLuceneQuery &query, const QCLuceneFilter &filter) + : d(new QCLuceneHitsPrivate()) +{ + d->hits = new lucene::search::Hits(searcher.d->searchable, query.d->query, + filter.d->filter); +} + +QCLuceneHits::QCLuceneHits(const QCLuceneSearcher &searcher, const QCLuceneQuery &query, + const QCLuceneFilter &filter, const QCLuceneSort &sort) + : d(new QCLuceneHitsPrivate()) +{ + d->hits = new lucene::search::Hits(searcher.d->searchable, query.d->query, + filter.d->filter, sort.d->sort); +} + +QCLuceneHits::~QCLuceneHits() +{ + // nothing todo +} + +QCLuceneDocument QCLuceneHits::document(const qint32 index) +{ + // TODO: check this + QCLuceneDocument document; + document.d->deleteCLuceneDocument = false; + lucene::document::Document &doc = d->hits->doc(int32_t(index)); + document.d->document = &doc; + + return document; +} + +qint32 QCLuceneHits::length() const +{ + return qint32(d->hits->length()); +} + +qint32 QCLuceneHits::id(const qint32 index) +{ + return qint32(d->hits->id(int32_t(index))); +} + +qreal QCLuceneHits::score(const qint32 index) +{ + return qreal(d->hits->score(int32_t(index))); +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/fulltextsearch/qhits_p.h b/src/assistant/lib/fulltextsearch/qhits_p.h new file mode 100644 index 000000000..98cd7021a --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qhits_p.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#ifndef QHITS_P_H +#define QHITS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qsort_p.h" +#include "qquery_p.h" +#include "qfilter_p.h" +#include "qdocument_p.h" +#include "qclucene_global_p.h" + +#include +#include + +CL_NS_DEF(search) + class Hits; +CL_NS_END +CL_NS_USE(search) + +QT_BEGIN_NAMESPACE + +class QCLuceneSearcher; + +class QHELP_EXPORT QCLuceneHitsPrivate : public QSharedData +{ +public: + QCLuceneHitsPrivate(); + QCLuceneHitsPrivate(const QCLuceneHitsPrivate &other); + + ~QCLuceneHitsPrivate(); + + Hits *hits; + bool deleteCLuceneHits; + +private: + QCLuceneHitsPrivate &operator=(const QCLuceneHitsPrivate &other); +}; + +class QHELP_EXPORT QCLuceneHits +{ +public: + QCLuceneHits(const QCLuceneSearcher &searcher, const QCLuceneQuery &query, + const QCLuceneFilter &filter); + QCLuceneHits(const QCLuceneSearcher &searcher, const QCLuceneQuery &query, + const QCLuceneFilter &filter, const QCLuceneSort &sort); + virtual ~QCLuceneHits(); + + QCLuceneDocument document(const qint32 index); + qint32 length() const; + qint32 id (const qint32 index); + qreal score(const qint32 index); + +protected: + friend class QCLuceneSearcher; + QSharedDataPointer d; +}; + +QT_END_NAMESPACE + +#endif // QHITS_P_H diff --git a/src/assistant/lib/fulltextsearch/qindexreader.cpp b/src/assistant/lib/fulltextsearch/qindexreader.cpp new file mode 100644 index 000000000..285a96334 --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qindexreader.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#include "qindexreader_p.h" +#include "qclucene_global_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +QCLuceneIndexReaderPrivate::QCLuceneIndexReaderPrivate() + : QSharedData() +{ + reader = 0; + deleteCLuceneIndexReader = true; +} + +QCLuceneIndexReaderPrivate::QCLuceneIndexReaderPrivate(const QCLuceneIndexReaderPrivate &other) + : QSharedData() +{ + reader = _CL_POINTER(other.reader); + deleteCLuceneIndexReader = other.deleteCLuceneIndexReader; +} + +QCLuceneIndexReaderPrivate::~QCLuceneIndexReaderPrivate() +{ + if (deleteCLuceneIndexReader) + _CLDECDELETE(reader); +} + + +QCLuceneIndexReader::QCLuceneIndexReader() + : d(new QCLuceneIndexReaderPrivate()) +{ + // nothing todo, private +} + +QCLuceneIndexReader::~QCLuceneIndexReader() +{ + // nothing todo +} + +bool QCLuceneIndexReader::isLuceneFile(const QString &filename) +{ + using namespace lucene::index; + + return IndexReader::isLuceneFile(filename); +} + +bool QCLuceneIndexReader::indexExists(const QString &directory) +{ + using namespace lucene::index; + return IndexReader::indexExists(directory); +} + +QCLuceneIndexReader QCLuceneIndexReader::open(const QString &path) +{ + using namespace lucene::index; + + QCLuceneIndexReader indexReader; + indexReader.d->reader = IndexReader::open(path); + + return indexReader; +} + +void QCLuceneIndexReader::unlock(const QString &path) +{ + using namespace lucene::index; + IndexReader::unlock(path); +} + +bool QCLuceneIndexReader::isLocked(const QString &directory) +{ + using namespace lucene::index; + return IndexReader::isLocked(directory); +} + +quint64 QCLuceneIndexReader::lastModified(const QString &directory) +{ + using namespace lucene::index; + return quint64(IndexReader::lastModified(directory)); +} + +qint64 QCLuceneIndexReader::getCurrentVersion(const QString &directory) +{ + using namespace lucene::index; + return qint64(IndexReader::getCurrentVersion(directory)); +} + +void QCLuceneIndexReader::close() +{ + d->reader->close(); +} + +bool QCLuceneIndexReader::isCurrent() +{ + return d->reader->isCurrent(); +} + +void QCLuceneIndexReader::undeleteAll() +{ + d->reader->undeleteAll(); +} + +qint64 QCLuceneIndexReader::getVersion() +{ + return qint64(d->reader->getVersion()); +} + +void QCLuceneIndexReader::deleteDocument(qint32 docNum) +{ + d->reader->deleteDocument(int32_t(docNum)); +} + +bool QCLuceneIndexReader::hasNorms(const QString &field) +{ + TCHAR *fieldName = QStringToTChar(field); + bool retValue = d->reader->hasNorms(fieldName); + delete [] fieldName; + + return retValue; +} + +qint32 QCLuceneIndexReader::deleteDocuments(const QCLuceneTerm &term) +{ + return d->reader->deleteDocuments(term.d->term); +} + +bool QCLuceneIndexReader::document(qint32 index, QCLuceneDocument &document) +{ + if (!document.d->document) + document.d->document = new lucene::document::Document(); + + if (d->reader->document(int32_t(index), document.d->document)) + return true; + + return false; +} + +void QCLuceneIndexReader::setNorm(qint32 doc, const QString &field, qreal value) +{ + TCHAR *fieldName = QStringToTChar(field); + d->reader->setNorm(int32_t(doc), fieldName, qreal(value)); + delete [] fieldName; +} + +void QCLuceneIndexReader::setNorm(qint32 doc, const QString &field, quint8 value) +{ + TCHAR *fieldName = QStringToTChar(field); + d->reader->setNorm(int32_t(doc), fieldName, uint8_t(value)); + delete [] fieldName; +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/fulltextsearch/qindexreader_p.h b/src/assistant/lib/fulltextsearch/qindexreader_p.h new file mode 100644 index 000000000..7421daa17 --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qindexreader_p.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#ifndef QINDEXREADER_P_H +#define QINDEXREADER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qterm_p.h" +#include "qdocument_p.h" +#include "qclucene_global_p.h" + +#include +#include +#include +#include + +CL_NS_DEF(index) + class IndexReader; +CL_NS_END +CL_NS_USE(index) + +QT_BEGIN_NAMESPACE + +class QCLuceneIndexWriter; +class QCLuceneIndexSearcher; + +class QHELP_EXPORT QCLuceneIndexReaderPrivate : public QSharedData +{ +public: + QCLuceneIndexReaderPrivate(); + QCLuceneIndexReaderPrivate(const QCLuceneIndexReaderPrivate &other); + + ~QCLuceneIndexReaderPrivate(); + + IndexReader *reader; + bool deleteCLuceneIndexReader; + +private: + QCLuceneIndexReaderPrivate &operator=(const QCLuceneIndexReaderPrivate &other); +}; + +class QHELP_EXPORT QCLuceneIndexReader +{ +public: + enum FieldOption { + ALL = 1, + INDEXED = 2, + UNINDEXED = 4, + INDEXED_WITH_TERMVECTOR = 8, + INDEXED_NO_TERMVECTOR = 16, + TERMVECTOR = 32, + TERMVECTOR_WITH_POSITION = 64, + TERMVECTOR_WITH_OFFSET = 128, + TERMVECTOR_WITH_POSITION_OFFSET = 256 + }; + + virtual ~QCLuceneIndexReader(); + + static bool isLuceneFile(const QString &filename); + static bool indexExists(const QString &directory); + static QCLuceneIndexReader open(const QString &path); + + static void unlock(const QString &path); + static bool isLocked(const QString &directory); + + static quint64 lastModified(const QString &directory); + static qint64 getCurrentVersion(const QString &directory); + + void close(); + bool isCurrent(); + void undeleteAll(); + qint64 getVersion(); + void deleteDocument(qint32 docNum); + bool hasNorms(const QString &field); + qint32 deleteDocuments(const QCLuceneTerm &term); + bool document(qint32 index, QCLuceneDocument &document); + void setNorm(qint32 doc, const QString &field, qreal value); + void setNorm(qint32 doc, const QString &field, quint8 value); + +protected: + friend class QCLuceneIndexWriter; + friend class QCLuceneIndexSearcher; + QSharedDataPointer d; + +private: + QCLuceneIndexReader(); +}; + +QT_END_NAMESPACE + +#endif // QINDEXREADER_P_H diff --git a/src/assistant/lib/fulltextsearch/qindexwriter.cpp b/src/assistant/lib/fulltextsearch/qindexwriter.cpp new file mode 100644 index 000000000..1f579eb65 --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qindexwriter.cpp @@ -0,0 +1,191 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#include "qindexwriter_p.h" +#include "qindexreader_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +QCLuceneIndexWriterPrivate::QCLuceneIndexWriterPrivate() + : QSharedData() +{ + writer = 0; + deleteCLuceneIndexWriter = true; +} + +QCLuceneIndexWriterPrivate::QCLuceneIndexWriterPrivate(const QCLuceneIndexWriterPrivate &other) + : QSharedData() +{ + writer = _CL_POINTER(other.writer); + deleteCLuceneIndexWriter = other.deleteCLuceneIndexWriter; +} + +QCLuceneIndexWriterPrivate::~QCLuceneIndexWriterPrivate() +{ + if (deleteCLuceneIndexWriter) + _CLDECDELETE(writer); +} + + +QCLuceneIndexWriter::QCLuceneIndexWriter(const QString &path, + QCLuceneAnalyzer &analyzer, + bool create, bool closeDir) + : d(new QCLuceneIndexWriterPrivate()) + , analyzer(analyzer) +{ + d->writer = new lucene::index::IndexWriter(path, + analyzer.d->analyzer, create, closeDir); +} + +QCLuceneIndexWriter::~QCLuceneIndexWriter() +{ + // nothing todo +} + +void QCLuceneIndexWriter::close() +{ + d->writer->close(); +} + +void QCLuceneIndexWriter::optimize() +{ + d->writer->optimize(); +} + +qint32 QCLuceneIndexWriter::docCount() +{ + return qint32(d->writer->docCount()); +} + +QCLuceneAnalyzer QCLuceneIndexWriter::getAnalyzer() +{ + return analyzer; +} + +void QCLuceneIndexWriter::addIndexes(const QList &readers) +{ + using namespace lucene::index; + IndexReader** readerArray = new IndexReader*[readers.count()]; + + for (int i = 0; i < readers.count(); ++i) + readerArray[i] = (readers.at(i))->d->reader; + + d->writer->addIndexes(readerArray); + delete [] readerArray; +} + +void QCLuceneIndexWriter::addDocument(QCLuceneDocument &doc, + QCLuceneAnalyzer &analyzer) +{ + if (doc.d->document) + d->writer->addDocument(doc.d->document, analyzer.d->analyzer); +} + +qint32 QCLuceneIndexWriter::getMaxFieldLength() const +{ + return qint32(d->writer->getMaxFieldLength()); +} + +void QCLuceneIndexWriter::setMaxFieldLength(qint32 value) +{ + d->writer->setMaxFieldLength(int32_t(value)); +} + +qint32 QCLuceneIndexWriter::getMaxBufferedDocs() const +{ + return qint32(d->writer->getMaxBufferedDocs()); +} + +void QCLuceneIndexWriter::setMaxBufferedDocs(qint32 value) +{ + d->writer->setMaxBufferedDocs(int32_t(value)); +} + +qint64 QCLuceneIndexWriter::getWriteLockTimeout() const +{ + return qint64(d->writer->getWriteLockTimeout()); +} + +void QCLuceneIndexWriter::setWriteLockTimeout(qint64 writeLockTimeout) +{ + d->writer->setWriteLockTimeout(int64_t(writeLockTimeout)); +} + +qint64 QCLuceneIndexWriter::getCommitLockTimeout() const +{ + return qint64(d->writer->getCommitLockTimeout()); +} + +void QCLuceneIndexWriter::setCommitLockTimeout(qint64 commitLockTimeout) +{ + d->writer->setCommitLockTimeout(int64_t(commitLockTimeout)); +} + +qint32 QCLuceneIndexWriter::getMergeFactor() const +{ + return qint32(d->writer->getMergeFactor()); +} + +void QCLuceneIndexWriter::setMergeFactor(qint32 value) +{ + d->writer->setMergeFactor(int32_t(value)); +} + +qint32 QCLuceneIndexWriter::getTermIndexInterval() const +{ + return qint32(d->writer->getTermIndexInterval()); +} + +void QCLuceneIndexWriter::setTermIndexInterval(qint32 interval) +{ + d->writer->setTermIndexInterval(int32_t(interval)); +} + +qint32 QCLuceneIndexWriter::getMinMergeDocs() const +{ + return qint32(d->writer->getMinMergeDocs()); +} + +void QCLuceneIndexWriter::setMinMergeDocs(qint32 value) +{ + d->writer->setMinMergeDocs(int32_t(value)); +} + +qint32 QCLuceneIndexWriter::getMaxMergeDocs() const +{ + return qint32(d->writer->getMaxMergeDocs()); +} + +void QCLuceneIndexWriter::setMaxMergeDocs(qint32 value) +{ + d->writer->setMaxMergeDocs(int32_t(value)); +} + +bool QCLuceneIndexWriter::getUseCompoundFile() const +{ + return d->writer->getUseCompoundFile(); +} + +void QCLuceneIndexWriter::setUseCompoundFile(bool value) +{ + d->writer->setUseCompoundFile(value); +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/fulltextsearch/qindexwriter_p.h b/src/assistant/lib/fulltextsearch/qindexwriter_p.h new file mode 100644 index 000000000..1f9c86115 --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qindexwriter_p.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#ifndef QINDEXWRITER_P_H +#define QINDEXWRITER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qanalyzer_p.h" +#include "qdocument_p.h" +#include "qclucene_global_p.h" + +#include +#include +#include + +CL_NS_DEF(index) + class IndexWriter; +CL_NS_END +CL_NS_USE(index) + +QT_BEGIN_NAMESPACE + +class QCLuceneIndexReader; + +class QHELP_EXPORT QCLuceneIndexWriterPrivate : public QSharedData +{ +public: + QCLuceneIndexWriterPrivate(); + QCLuceneIndexWriterPrivate(const QCLuceneIndexWriterPrivate &other); + + ~QCLuceneIndexWriterPrivate(); + + IndexWriter *writer; + bool deleteCLuceneIndexWriter; + +private: + QCLuceneIndexWriterPrivate &operator=(const QCLuceneIndexWriterPrivate &other); +}; + +class QHELP_EXPORT QCLuceneIndexWriter +{ +public: + enum { + DEFAULT_MERGE_FACTOR = 10, + COMMIT_LOCK_TIMEOUT = 10000, + DEFAULT_MAX_BUFFERED_DOCS = 10, + DEFAULT_MAX_FIELD_LENGTH = 10000, + DEFAULT_TERM_INDEX_INTERVAL = 128, + DEFAULT_MAX_MERGE_DOCS = 0x7FFFFFFFL + }; + + QCLuceneIndexWriter(const QString &path, QCLuceneAnalyzer &analyzer, + bool create, bool closeDir = true); + virtual ~QCLuceneIndexWriter(); + + void close(); + void optimize(); + qint32 docCount(); + QCLuceneAnalyzer getAnalyzer(); + + void addIndexes(const QList &readers); + void addDocument(QCLuceneDocument &doc, QCLuceneAnalyzer &analyzer); + + qint32 getMaxFieldLength() const; + void setMaxFieldLength(qint32 value); + + qint32 getMaxBufferedDocs() const; + void setMaxBufferedDocs(qint32 value); + + qint64 getWriteLockTimeout() const; + void setWriteLockTimeout(qint64 writeLockTimeout); + + qint64 getCommitLockTimeout() const; + void setCommitLockTimeout(qint64 commitLockTimeout); + + qint32 getMergeFactor() const; + void setMergeFactor(qint32 value); + + qint32 getTermIndexInterval() const; + void setTermIndexInterval(qint32 interval); + + qint32 getMinMergeDocs() const; + void setMinMergeDocs(qint32 value); + + qint32 getMaxMergeDocs() const; + void setMaxMergeDocs(qint32 value); + + bool getUseCompoundFile() const; + void setUseCompoundFile(bool value); + +protected: + QSharedDataPointer d; + +private: + QCLuceneAnalyzer analyzer; +}; + +QT_END_NAMESPACE + +#endif // QINDEXWRITER_P_H diff --git a/src/assistant/lib/fulltextsearch/qquery.cpp b/src/assistant/lib/fulltextsearch/qquery.cpp new file mode 100644 index 000000000..170341cdd --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qquery.cpp @@ -0,0 +1,358 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#include "qquery_p.h" +#include "qclucene_global_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +QCLuceneQueryPrivate::QCLuceneQueryPrivate() + : QSharedData() +{ + query = 0; + deleteCLuceneQuery = true; +} + +QCLuceneQueryPrivate::QCLuceneQueryPrivate(const QCLuceneQueryPrivate &other) + : QSharedData() +{ + query = _CL_POINTER(other.query); + deleteCLuceneQuery = other.deleteCLuceneQuery; +} + +QCLuceneQueryPrivate::~QCLuceneQueryPrivate() +{ + if (deleteCLuceneQuery) + _CLDECDELETE(query); +} + + +QCLuceneQuery::QCLuceneQuery() + : d(new QCLuceneQueryPrivate()) +{ + // nothing todo, private +} + +QCLuceneQuery::~QCLuceneQuery() +{ + // nothing todo +} + +void QCLuceneQuery::setBoost(qreal boost) +{ + d->query->setBoost(qreal(boost)); +} + +qreal QCLuceneQuery::getBoost() const +{ + return qreal(d->query->getBoost()); +} + +QString QCLuceneQuery::getQueryName() const +{ + return TCharToQString(d->query->getQueryName()); +} + +bool QCLuceneQuery::instanceOf(const QString &other) const +{ + if (other == getQueryName()) + return true; + + return false; +} + +QString QCLuceneQuery::toString(const QString &field) const +{ + TCHAR *fieldName = QStringToTChar(field); + QString retValue = TCharToQString(d->query->toString(fieldName)); + delete [] fieldName; + + return retValue; +} + +quint32 QCLuceneQuery::hashCode() const +{ + return quint32(d->query->hashCode()); +} + +QString QCLuceneQuery::toString() const +{ + return TCharToQString(d->query->toString()); +} + +bool QCLuceneQuery::equals(const QCLuceneQuery &other) const +{ + return d->query->equals(other.d->query); +} + + +QCLucenePrefixQuery::QCLucenePrefixQuery(const QCLuceneTerm &prefix) + : QCLuceneQuery() + , prefix(prefix) +{ + d->query = new lucene::search::PrefixQuery(prefix.d->term); +} + +QCLucenePrefixQuery::~QCLucenePrefixQuery() +{ + // nothing todo +} + +QString QCLucenePrefixQuery::getClassName() +{ + return TCharToQString(lucene::search::PrefixQuery::getClassName()); +} + +QCLuceneTerm QCLucenePrefixQuery::getPrefix() const +{ + return prefix; +} + + +QCLuceneRangeQuery::QCLuceneRangeQuery(const QCLuceneTerm &lowerTerm, + const QCLuceneTerm &upperTerm, + bool inclusive) + : QCLuceneQuery() + , lowerTerm(lowerTerm) + , upperTerm(upperTerm) +{ + d->query = new lucene::search::RangeQuery(lowerTerm.d->term, + upperTerm.d->term, inclusive); +} + +QCLuceneRangeQuery::~QCLuceneRangeQuery() +{ + // nothing todo +} + +QString QCLuceneRangeQuery::getClassName() +{ + return TCharToQString(lucene::search::RangeQuery::getClassName()); +} + +QCLuceneTerm QCLuceneRangeQuery::getLowerTerm() const +{ + return lowerTerm; +} + +QCLuceneTerm QCLuceneRangeQuery::getUpperTerm() const +{ + return upperTerm; +} + +bool QCLuceneRangeQuery::isInclusive() const +{ + lucene::search::RangeQuery *query = + static_cast (d->query); + + if (query == 0) + return false; + + return query->isInclusive(); +} + +QString QCLuceneRangeQuery::getField() const +{ + lucene::search::RangeQuery *query = + static_cast (d->query); + + if (query == 0) + return QString(); + + return TCharToQString(query->getField()); +} + + +QCLuceneTermQuery::QCLuceneTermQuery(const QCLuceneTerm &term) + : QCLuceneQuery() + , term(term) +{ + d->query = new lucene::search::TermQuery(term.d->term); +} + +QCLuceneTermQuery::~QCLuceneTermQuery() +{ + // nothing todo +} + +QString QCLuceneTermQuery::getClassName() +{ + return TCharToQString(lucene::search::TermQuery::getClassName()); +} + +QCLuceneTerm QCLuceneTermQuery::getTerm() const +{ + return term; +} + + +QCLuceneBooleanQuery::QCLuceneBooleanQuery() + : QCLuceneQuery() +{ + d->query = new lucene::search::BooleanQuery(); +} + +QCLuceneBooleanQuery::~QCLuceneBooleanQuery() +{ + qDeleteAll(queries); +} + +QString QCLuceneBooleanQuery::getClassName() +{ + return TCharToQString(lucene::search::BooleanQuery::getClassName()); +} + +quint32 QCLuceneBooleanQuery::getClauseCount() const +{ + lucene::search::BooleanQuery *query = + static_cast (d->query); + + if (query == 0) + return 1024; + + return quint32(query->getClauseCount()); +} + +quint32 QCLuceneBooleanQuery::getMaxClauseCount() const +{ + lucene::search::BooleanQuery *query = + static_cast (d->query); + + if (query == 0) + return 1024; + + return quint32(query->getMaxClauseCount()); +} + +void QCLuceneBooleanQuery::setMaxClauseCount(quint32 maxClauseCount) +{ + lucene::search::BooleanQuery *query = + static_cast (d->query); + + if (query == 0) + return; + + query->setMaxClauseCount(size_t(maxClauseCount)); +} + +void QCLuceneBooleanQuery::add(QCLuceneQuery *query, bool required, bool prohibited) +{ + add(query, false, required, prohibited); +} + +void QCLuceneBooleanQuery::add(QCLuceneQuery *query, bool delQuery, + bool required, bool prohibited) +{ + lucene::search::BooleanQuery *booleanQuery = + static_cast (d->query); + + if (booleanQuery == 0) + return; + + booleanQuery->add(query->d->query, delQuery, required, prohibited); + + if (delQuery) { + queries.append(query); + query->d->deleteCLuceneQuery = false; + } +} + + +QCLucenePhraseQuery::QCLucenePhraseQuery() + : QCLuceneQuery() +{ + d->query = new lucene::search::PhraseQuery(); +} + +QCLucenePhraseQuery::~QCLucenePhraseQuery() +{ + termList.clear(); +} + +QString QCLucenePhraseQuery::getClassName() +{ + return TCharToQString(lucene::search::RangeQuery::getClassName()); +} + +qint32 QCLucenePhraseQuery::getSlop() const +{ + lucene::search::PhraseQuery *phraseQuery = + static_cast (d->query); + + if (phraseQuery == 0) + return 0; + + return qint32(phraseQuery->getSlop()); +} + +void QCLucenePhraseQuery::setSlop(const qint32 slop) +{ + lucene::search::PhraseQuery *phraseQuery = + static_cast (d->query); + + if (phraseQuery == 0) + return; + + phraseQuery->setSlop(int32_t(slop)); +} + +void QCLucenePhraseQuery::addTerm(const QCLuceneTerm &term) +{ + lucene::search::PhraseQuery *phraseQuery = + static_cast (d->query); + + if (phraseQuery == 0) + return; + + termList.append(term); + phraseQuery->add(term.d->term); +} + +void QCLucenePhraseQuery::addTerm(const QCLuceneTerm &term, qint32 position) +{ + lucene::search::PhraseQuery *phraseQuery = + static_cast (d->query); + + if (phraseQuery == 0) + return; + + termList.insert(position, term); + phraseQuery->add(term.d->term, int32_t(position)); + +} + +QString QCLucenePhraseQuery::getFieldName() const +{ + lucene::search::PhraseQuery *phraseQuery = + static_cast (d->query); + + if (phraseQuery == 0) + return QString(); + + return TCharToQString(phraseQuery->getFieldName()); +} + +QList QCLucenePhraseQuery::getTerms() const +{ + return termList; +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/fulltextsearch/qquery_p.h b/src/assistant/lib/fulltextsearch/qquery_p.h new file mode 100644 index 000000000..3268b7c42 --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qquery_p.h @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#ifndef QQUERY_P_H +#define QQUERY_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qterm_p.h" +#include "qclucene_global_p.h" + +#include +#include +#include +#include + +CL_NS_DEF(search) + class Query; +CL_NS_END +CL_NS_USE(search) + +QT_BEGIN_NAMESPACE + +class QCLuceneHits; +class QCLuceneTermQuery; +class QCLuceneRangeQuery; +class QCLuceneQueryParser; +class QCLucenePrefixQuery; +class QCLuceneBooleanQuery; +class QCLucenePhraseQuery; + +class QHELP_EXPORT QCLuceneQueryPrivate : public QSharedData +{ +public: + QCLuceneQueryPrivate(); + QCLuceneQueryPrivate(const QCLuceneQueryPrivate &other); + + ~QCLuceneQueryPrivate(); + + Query *query; + bool deleteCLuceneQuery; + +private: + QCLuceneQueryPrivate &operator=(const QCLuceneQueryPrivate &other); +}; + +class QHELP_EXPORT QCLuceneQuery +{ +public: + virtual ~QCLuceneQuery(); + + void setBoost(qreal boost); + qreal getBoost() const; + QString getQueryName() const; + bool instanceOf(const QString &other) const; + QString toString(const QString &field) const; + quint32 hashCode() const; + QString toString() const; + bool equals(const QCLuceneQuery &other) const; + +protected: + friend class QCLuceneHits; + friend class QCLuceneTermQuery; + friend class QCLuceneRangeQuery; + friend class QCLucenePrefixQuery; + friend class QCLuceneQueryParser; + friend class QCLuceneBooleanQuery; + friend class QCLucenePhraseQuery; + QSharedDataPointer d; + +private: + QCLuceneQuery(); +}; + +class QHELP_EXPORT QCLucenePrefixQuery : public QCLuceneQuery +{ +public: + QCLucenePrefixQuery(const QCLuceneTerm &prefix); + ~QCLucenePrefixQuery(); + + static QString getClassName(); + + QCLuceneTerm getPrefix() const; + +private: + QCLuceneTerm prefix; +}; + +class QHELP_EXPORT QCLuceneRangeQuery : public QCLuceneQuery +{ +public: + QCLuceneRangeQuery(const QCLuceneTerm &lowerTerm, + const QCLuceneTerm &upperTerm, bool inclusive); + ~QCLuceneRangeQuery(); + + static QString getClassName(); + + QCLuceneTerm getLowerTerm() const; + QCLuceneTerm getUpperTerm() const; + + bool isInclusive() const; + QString getField() const; + +private: + QCLuceneTerm lowerTerm; + QCLuceneTerm upperTerm; +}; + +class QHELP_EXPORT QCLuceneTermQuery : public QCLuceneQuery +{ +public: + QCLuceneTermQuery(const QCLuceneTerm &term); + ~QCLuceneTermQuery(); + + static QString getClassName(); + + QCLuceneTerm getTerm() const; + +private: + QCLuceneTerm term; +}; + +class QHELP_EXPORT QCLuceneBooleanQuery : public QCLuceneQuery +{ +public: + QCLuceneBooleanQuery(); + ~QCLuceneBooleanQuery(); + + static QString getClassName(); + + quint32 getClauseCount() const; + quint32 getMaxClauseCount() const; + void setMaxClauseCount(quint32 maxClauseCount); + + void add(QCLuceneQuery *query, bool required, bool prohibited); + void add(QCLuceneQuery *query, bool delQuery, bool required, bool prohibited); + +private: + QList queries; +}; + +class QHELP_EXPORT QCLucenePhraseQuery : public QCLuceneQuery +{ +public: + QCLucenePhraseQuery(); + ~QCLucenePhraseQuery(); + + static QString getClassName(); + + qint32 getSlop() const; + void setSlop(const qint32 slop); + + void addTerm(const QCLuceneTerm &term); + void addTerm(const QCLuceneTerm &term, qint32 position); + + QString getFieldName() const; + QList getTerms() const; + +private: + QList termList; +}; + +QT_END_NAMESPACE + +#endif // QQUERY_P_H diff --git a/src/assistant/lib/fulltextsearch/qqueryparser.cpp b/src/assistant/lib/fulltextsearch/qqueryparser.cpp new file mode 100644 index 000000000..f306a041b --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qqueryparser.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#include "qqueryparser_p.h" +#include "qquery_p.h" +#include "qclucene_global_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +QCLuceneQueryParserPrivate::QCLuceneQueryParserPrivate() + : QSharedData() +{ + queryParser = 0; + deleteCLuceneQueryParser = true; +} + +QCLuceneQueryParserPrivate::QCLuceneQueryParserPrivate(const QCLuceneQueryParserPrivate &other) + : QSharedData() +{ + queryParser = _CL_POINTER(other.queryParser); + deleteCLuceneQueryParser = other.deleteCLuceneQueryParser; +} + +QCLuceneQueryParserPrivate::~QCLuceneQueryParserPrivate() +{ + if (deleteCLuceneQueryParser) + _CLDECDELETE(queryParser); +} + + +QCLuceneQueryParser::QCLuceneQueryParser(const QString &field, + QCLuceneAnalyzer &analyzer) + : d(new QCLuceneQueryParserPrivate()) + , field(field) + , analyzer(analyzer) +{ + TCHAR *fieldName = QStringToTChar(field); + + d->queryParser = new lucene::queryParser::QueryParser(fieldName, + analyzer.d->analyzer); + + delete [] fieldName; +} + +QCLuceneQueryParser::~QCLuceneQueryParser() +{ + // nothing todo +} + +QCLuceneQuery* QCLuceneQueryParser::parse(const QString &query) +{ + TCHAR *string = QStringToTChar(query); + + QCLuceneQuery *retValue = 0; + lucene::search::Query* q = d->queryParser->parse(string); + if (q) { + retValue = new QCLuceneQuery(); + retValue->d->query = q; + } + + delete [] string; + return retValue; +} + +QCLuceneQuery* QCLuceneQueryParser::parse(QCLuceneReader &reader) +{ + QCLuceneQuery *retValue = 0; + lucene::search::Query* q = d->queryParser->parse(reader.d->reader); + if (q) { + retValue = new QCLuceneQuery(); + retValue->d->query = q; + } + + return retValue; +} + +QCLuceneQuery* QCLuceneQueryParser::parse(const QString &query, const QString &field, + QCLuceneAnalyzer &analyzer) +{ + QCLuceneQueryParser parser(field, analyzer); + return parser.parse(query); +} + +QCLuceneAnalyzer QCLuceneQueryParser::getAnalyzer() +{ + return analyzer; +} + +QString QCLuceneQueryParser::getField() +{ + return field; +} + + +QCLuceneMultiFieldQueryParser::QCLuceneMultiFieldQueryParser( + const QStringList &fieldList, QCLuceneAnalyzer &analyzer) + : QCLuceneQueryParser(QLatin1String(""), analyzer) +{ + Q_UNUSED(fieldList) +} + +QCLuceneMultiFieldQueryParser::~QCLuceneMultiFieldQueryParser() +{ + // nothing todo +} + +QCLuceneQuery* QCLuceneMultiFieldQueryParser::parse(const QString &query, + const QStringList &fieldList, + QCLuceneAnalyzer &analyzer) +{ + QCLuceneBooleanQuery *retValue = new QCLuceneBooleanQuery(); + foreach (const QString &field, fieldList) { + QCLuceneQuery *q = QCLuceneQueryParser::parse(query, field, analyzer); + if (!q) { + delete retValue; + retValue = 0; break; + } else { + retValue->add(q, true, false, false); + } + } + + return retValue; +} + +QCLuceneQuery* QCLuceneMultiFieldQueryParser::parse(const QString &query, + const QStringList &fieldList, + QList flags, + QCLuceneAnalyzer &analyzer) +{ + QCLuceneBooleanQuery *retValue = new QCLuceneBooleanQuery(); + qint32 i = 0; + foreach (const QString &field, fieldList) { + QCLuceneQuery *q = QCLuceneQueryParser::parse(query, field, analyzer); + if (q) { + qint32 flag = flags.at(i); + switch (flag) { + case QCLuceneMultiFieldQueryParser::REQUIRED_FIELD: { + retValue->add(q, true, true, false); + } break; + + case QCLuceneMultiFieldQueryParser::PROHIBITED_FIELD: { + retValue->add(q, true, false, true); + } break; + + default: { + retValue->add(q, true, false, false); + } break; + } + + ++i; + } else { + delete retValue; + retValue = 0; break; + } + } + return retValue; +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/fulltextsearch/qqueryparser_p.h b/src/assistant/lib/fulltextsearch/qqueryparser_p.h new file mode 100644 index 000000000..e1b8c74eb --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qqueryparser_p.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#ifndef QQUERYPARSER_P_H +#define QQUERYPARSER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qreader_p.h" +#include "qanalyzer_p.h" +#include "qclucene_global_p.h" + +#include +#include +#include +#include + +CL_NS_DEF(queryParser) + class QueryParser; +CL_NS_END +CL_NS_USE(queryParser) + +QT_BEGIN_NAMESPACE + +class QCLuceneQuery; +class QCLuceneMultiFieldQueryParser; + +class QHELP_EXPORT QCLuceneQueryParserPrivate : public QSharedData +{ +public: + QCLuceneQueryParserPrivate(); + QCLuceneQueryParserPrivate(const QCLuceneQueryParserPrivate &other); + + ~QCLuceneQueryParserPrivate(); + + QueryParser *queryParser; + bool deleteCLuceneQueryParser; + +private: + QCLuceneQueryParserPrivate &operator=(const QCLuceneQueryParserPrivate &other); +}; + +class QHELP_EXPORT QCLuceneQueryParser +{ +public: + QCLuceneQueryParser(const QString &field, QCLuceneAnalyzer &analyzer); + virtual ~QCLuceneQueryParser(); + + QCLuceneQuery* parse(const QString &query); + QCLuceneQuery* parse(QCLuceneReader &reader); + static QCLuceneQuery* parse(const QString &query, const QString &field, + QCLuceneAnalyzer &analyzer); + QCLuceneAnalyzer getAnalyzer(); + QString getField(); + +protected: + friend class QCLuceneMultiFieldQueryParser; + QSharedDataPointer d; + +private: + QString field; + QCLuceneAnalyzer analyzer; +}; + +class QHELP_EXPORT QCLuceneMultiFieldQueryParser : public QCLuceneQueryParser +{ +public: + enum FieldFlags { + NORMAL_FIELD = 0, + REQUIRED_FIELD = 1, + PROHIBITED_FIELD = 2 + }; + + QCLuceneMultiFieldQueryParser(const QStringList &fieldList, + QCLuceneAnalyzer &analyzer); + ~QCLuceneMultiFieldQueryParser(); + + static QCLuceneQuery *parse(const QString &query, const QStringList &fieldList, + QCLuceneAnalyzer &analyzer); + static QCLuceneQuery *parse(const QString &query, const QStringList &fieldList, + QList flags, QCLuceneAnalyzer &analyzer); +}; + +QT_END_NAMESPACE + +#endif // QQUERYPARSER_P_H diff --git a/src/assistant/lib/fulltextsearch/qreader.cpp b/src/assistant/lib/fulltextsearch/qreader.cpp new file mode 100644 index 000000000..0a8b7accf --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qreader.cpp @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#include "qreader_p.h" +#include "qclucene_global_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +QCLuceneReaderPrivate::QCLuceneReaderPrivate() + : QSharedData() +{ + reader = 0; + deleteCLuceneReader = true; +} + +QCLuceneReaderPrivate::QCLuceneReaderPrivate(const QCLuceneReaderPrivate &other) + : QSharedData() +{ + reader = _CL_POINTER(other.reader); + deleteCLuceneReader = other.deleteCLuceneReader; +} + +QCLuceneReaderPrivate::~QCLuceneReaderPrivate() +{ + if (deleteCLuceneReader) + _CLDECDELETE(reader); +} + +QCLuceneReader::QCLuceneReader() + : d(new QCLuceneReaderPrivate()) +{ + // nothing todo +} + +QCLuceneReader::~QCLuceneReader() +{ + // nothing todo +} + + +QCLuceneStringReader::QCLuceneStringReader(const QString &value) + : QCLuceneReader() + , string(QStringToTChar(value)) +{ + d->reader = new lucene::util::StringReader(string); +} + +QCLuceneStringReader::QCLuceneStringReader(const QString &value, qint32 length) + : QCLuceneReader() + , string(QStringToTChar(value)) +{ + d->reader = new lucene::util::StringReader(string, int32_t(length)); +} + +QCLuceneStringReader::QCLuceneStringReader(const QString &value, qint32 length, + bool copyData) + : QCLuceneReader() + , string(QStringToTChar(value)) +{ + d->reader = new lucene::util::StringReader(string, int32_t(length), copyData); +} + +QCLuceneStringReader::~QCLuceneStringReader() +{ + delete [] string; +} + + +QCLuceneFileReader::QCLuceneFileReader(const QString &path, const QString &encoding, + qint32 cacheLength, qint32 cacheBuffer) + : QCLuceneReader() +{ + const QByteArray tmpPath = path.toLocal8Bit(); + const QByteArray tmpEncoding = encoding.toAscii(); + d->reader = new lucene::util::FileReader(tmpPath.constData(), + tmpEncoding.constData(), int32_t(cacheLength), int32_t(cacheBuffer)); +} + +QCLuceneFileReader::~QCLuceneFileReader() +{ + // nothing todo +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/fulltextsearch/qreader_p.h b/src/assistant/lib/fulltextsearch/qreader_p.h new file mode 100644 index 000000000..e24e9d836 --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qreader_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#ifndef QREADER_P_H +#define QREADER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qclucene_global_p.h" + +#include +#include +#include + +CL_NS_DEF(util) + class Reader; +CL_NS_END +CL_NS_USE(util) + +QT_BEGIN_NAMESPACE + +class QCLuceneField; +class QCLuceneAnalyzer; +class QCLuceneDocument; +class QCLuceneQueryParser; +class QCLuceneStandardTokenizer; + +class QHELP_EXPORT QCLuceneReaderPrivate : public QSharedData +{ +public: + QCLuceneReaderPrivate(); + QCLuceneReaderPrivate(const QCLuceneReaderPrivate &other); + + ~QCLuceneReaderPrivate(); + + Reader* reader; + bool deleteCLuceneReader; + +private: + QCLuceneReaderPrivate &operator=(const QCLuceneReaderPrivate &other); +}; + +class QHELP_EXPORT QCLuceneReader +{ +public: + QCLuceneReader(); + virtual ~QCLuceneReader(); + +protected: + friend class QCLuceneField; + friend class QCLuceneAnalyzer; + friend class QCLuceneDocument; + friend class QCLuceneQueryParser; + friend class QCLuceneStandardTokenizer; + QSharedDataPointer d; +}; + +class QCLuceneStringReader : public QCLuceneReader +{ +public: + QCLuceneStringReader(const QString &value); + QCLuceneStringReader(const QString &value, qint32 length); + QCLuceneStringReader(const QString &value, qint32 length, bool copyData); + + ~QCLuceneStringReader(); + +private: + TCHAR *string; +}; + +class QHELP_EXPORT QCLuceneFileReader : public QCLuceneReader +{ +public: + QCLuceneFileReader(const QString &path, const QString &encoding, + qint32 cacheLength = 13, qint32 cacheBuffer = 14); + ~QCLuceneFileReader(); +}; + +QT_END_NAMESPACE + +#endif // QREADER_P_H diff --git a/src/assistant/lib/fulltextsearch/qsearchable.cpp b/src/assistant/lib/fulltextsearch/qsearchable.cpp new file mode 100644 index 000000000..508fc05f6 --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qsearchable.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#include "qsearchable_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +QCLuceneSearchablePrivate::QCLuceneSearchablePrivate() + : QSharedData() +{ + searchable = 0; + deleteCLuceneSearchable = true; +} + +QCLuceneSearchablePrivate::QCLuceneSearchablePrivate(const QCLuceneSearchablePrivate &other) + : QSharedData() +{ + searchable = _CL_POINTER(other.searchable); + deleteCLuceneSearchable = other.deleteCLuceneSearchable; +} + +QCLuceneSearchablePrivate::~QCLuceneSearchablePrivate() +{ + if (deleteCLuceneSearchable) + _CLDECDELETE(searchable); +} + + +QCLuceneSearchable::QCLuceneSearchable() + : d(new QCLuceneSearchablePrivate()) +{ + // nothing todo +} + +QCLuceneSearchable::~QCLuceneSearchable() +{ + // nothing todo +} + + +QCLuceneSearcher::QCLuceneSearcher() + : QCLuceneSearchable() +{ + // nothing todo +} + +QCLuceneSearcher::~QCLuceneSearcher() +{ + // nothing todo; +} + +QCLuceneHits QCLuceneSearcher::search(const QCLuceneQuery &query) +{ + return search(query, QCLuceneFilter()); +} + +QCLuceneHits QCLuceneSearcher::search(const QCLuceneQuery &query, + const QCLuceneFilter &filter) +{ + return QCLuceneHits(*this, query, filter); +} + +QCLuceneHits QCLuceneSearcher::search(const QCLuceneQuery &query, + const QCLuceneSort &sort) +{ + return QCLuceneHits(*this, query, QCLuceneFilter(), sort); +} + +QCLuceneHits QCLuceneSearcher::search(const QCLuceneQuery &query, + const QCLuceneFilter &filter, + const QCLuceneSort &sort) +{ + return QCLuceneHits(*this, query, filter, sort); +} + + +QCLuceneIndexSearcher::QCLuceneIndexSearcher(const QString &path) + : QCLuceneSearcher() +{ + lucene::search::IndexSearcher *searcher = + new lucene::search::IndexSearcher(path); + + reader.d->reader = searcher->getReader(); + reader.d->deleteCLuceneIndexReader = false; + + d->searchable = searcher; +} + +QCLuceneIndexSearcher::QCLuceneIndexSearcher(const QCLuceneIndexReader &reader) + : QCLuceneSearcher() + , reader(reader) +{ + d->searchable = new lucene::search::IndexSearcher(reader.d->reader); +} + +QCLuceneIndexSearcher::~QCLuceneIndexSearcher() +{ + // nothing todo +} + +void QCLuceneIndexSearcher::close() +{ + d->searchable->close(); +} + +qint32 QCLuceneIndexSearcher::maxDoc() const +{ + return qint32(d->searchable->maxDoc()); +} + +QCLuceneIndexReader QCLuceneIndexSearcher::getReader() +{ + return reader; +} + +bool QCLuceneIndexSearcher::doc(qint32 i, QCLuceneDocument &document) +{ + return d->searchable->doc(int32_t(i), document.d->document); +} + + +QCLuceneMultiSearcher::QCLuceneMultiSearcher(const QList searchables) +: QCLuceneSearcher() +{ + lucene::search::Searchable** list= + _CL_NEWARRAY(lucene::search::Searchable*, searchables.count()); + + d->searchable = new lucene::search::MultiSearcher(list); + + _CLDELETE_ARRAY(list); +} + +QCLuceneMultiSearcher::~QCLuceneMultiSearcher() +{ + // nothing todo +} + +void QCLuceneMultiSearcher::close() +{ + d->searchable->close(); +} + +qint32 QCLuceneMultiSearcher::maxDoc() const +{ + return qint32(d->searchable->maxDoc()); +} + +qint32 QCLuceneMultiSearcher::subDoc(qint32 index) const +{ + lucene::search::MultiSearcher *searcher = + static_cast (d->searchable); + + if (searcher == 0) + return 0; + + return qint32(searcher->subDoc(int32_t(index))); +} + +qint32 QCLuceneMultiSearcher::subSearcher(qint32 index) const +{ + lucene::search::MultiSearcher *searcher = + static_cast (d->searchable); + + if (searcher == 0) + return 0; + + return qint32(searcher->subSearcher(int32_t(index))); +} + +qint32 QCLuceneMultiSearcher::searcherIndex(qint32 index) const +{ + lucene::search::MultiSearcher *searcher = + static_cast (d->searchable); + + if (searcher == 0) + return 0; + + return qint32(searcher->searcherIndex(int32_t(index))); +} + +bool QCLuceneMultiSearcher::doc(qint32 i, QCLuceneDocument &document) +{ + return d->searchable->doc(int32_t(i), document.d->document); +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/fulltextsearch/qsearchable_p.h b/src/assistant/lib/fulltextsearch/qsearchable_p.h new file mode 100644 index 000000000..149cfb049 --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qsearchable_p.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#ifndef QSEARCHABLE_P_H +#define QSEARCHABLE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhits_p.h" +#include "qsort_p.h" +#include "qquery_p.h" +#include "qfilter_p.h" +#include "qdocument_p.h" +#include "qindexreader_p.h" +#include "qclucene_global_p.h" + +#include +#include +#include +#include + +CL_NS_DEF(search) + class Searcher; +CL_NS_END +CL_NS_USE(search) + +QT_BEGIN_NAMESPACE + +class QCLuceneHits; +class QCLuceneSearcher; +class QCLuceneIndexSearcher; +class QCLuceneMultiSearcher; + +class QHELP_EXPORT QCLuceneSearchablePrivate : public QSharedData +{ +public: + QCLuceneSearchablePrivate(); + QCLuceneSearchablePrivate(const QCLuceneSearchablePrivate &other); + + ~QCLuceneSearchablePrivate(); + + Searcher *searchable; + bool deleteCLuceneSearchable; + +private: + QCLuceneSearchablePrivate &operator=(const QCLuceneSearchablePrivate &other); +}; + +class QHELP_EXPORT QCLuceneSearchable +{ +public: + virtual ~QCLuceneSearchable(); + +protected: + friend class QCLuceneSearcher; + friend class QCLuceneIndexSearcher; + friend class QCLuceneMultiSearcher; + QSharedDataPointer d; + +private: + QCLuceneSearchable(); +}; + +class QHELP_EXPORT QCLuceneSearcher : public QCLuceneSearchable +{ +public: + QCLuceneSearcher(); + virtual ~QCLuceneSearcher(); + + QCLuceneHits search(const QCLuceneQuery &query); + QCLuceneHits search(const QCLuceneQuery &query, const QCLuceneFilter &filter); + QCLuceneHits search(const QCLuceneQuery &query, const QCLuceneSort &sort); + QCLuceneHits search(const QCLuceneQuery &query, const QCLuceneFilter &filter, + const QCLuceneSort &sort); + +protected: + friend class QCLuceneHits; +}; + +class QHELP_EXPORT QCLuceneIndexSearcher : public QCLuceneSearcher +{ +public: + QCLuceneIndexSearcher(const QString &path); + QCLuceneIndexSearcher(const QCLuceneIndexReader &reader); + ~QCLuceneIndexSearcher(); + + void close(); + qint32 maxDoc() const; + QCLuceneIndexReader getReader(); + bool doc(qint32 i, QCLuceneDocument &document); + +private: + QCLuceneIndexReader reader; +}; + +class QHELP_EXPORT QCLuceneMultiSearcher : public QCLuceneSearcher +{ +public: + QCLuceneMultiSearcher(const QList searchables); + ~QCLuceneMultiSearcher(); + + void close(); + qint32 maxDoc() const; + qint32 subDoc(qint32 index) const; + qint32 subSearcher(qint32 index) const; + qint32 searcherIndex(qint32 index) const; + bool doc(qint32 i, QCLuceneDocument &document); +}; + +QT_END_NAMESPACE + +#endif // QSEARCHABLE_P_H diff --git a/src/assistant/lib/fulltextsearch/qsort.cpp b/src/assistant/lib/fulltextsearch/qsort.cpp new file mode 100644 index 000000000..4dface005 --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qsort.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#include "qsort_p.h" +#include "qclucene_global_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +QCLuceneSortPrivate::QCLuceneSortPrivate() + : QSharedData() +{ + sort = 0; + deleteCLuceneSort = true; +} + +QCLuceneSortPrivate::QCLuceneSortPrivate (const QCLuceneSortPrivate &other) + : QSharedData() +{ + sort = _CL_POINTER(other.sort); + deleteCLuceneSort = other.deleteCLuceneSort; +} + +QCLuceneSortPrivate::~QCLuceneSortPrivate() +{ + if (deleteCLuceneSort) + _CLDECDELETE(sort); +} + + +QCLuceneSort::QCLuceneSort() + : d(new QCLuceneSortPrivate()) +{ + d->sort = new lucene::search::Sort(); +} + +QCLuceneSort::QCLuceneSort(const QStringList &fieldNames) + : d(new QCLuceneSortPrivate()) +{ + d->sort = new lucene::search::Sort(); + setSort(fieldNames); +} + +QCLuceneSort::QCLuceneSort(const QString &field, bool reverse) + : d(new QCLuceneSortPrivate()) +{ + d->sort = new lucene::search::Sort(); + setSort(field, reverse); +} + +QCLuceneSort::~QCLuceneSort() +{ + // nothing todo +} + +QString QCLuceneSort::toString() const +{ + return TCharToQString(d->sort->toString()); +} + +void QCLuceneSort::setSort(const QStringList &fieldNames) +{ + TCHAR **nameArray = new TCHAR*[fieldNames.count()]; + for (int i = 0; i < fieldNames.count(); ++i) + nameArray[i] = QStringToTChar(fieldNames.at(i)); + + d->sort->setSort((const TCHAR**)nameArray); + + for (int i = 0; i < fieldNames.count(); ++i) + delete [] nameArray[i]; + delete [] nameArray; +} + +void QCLuceneSort::setSort(const QString &field, bool reverse) +{ + TCHAR *name = QStringToTChar(field); + d->sort->setSort(name, reverse); + delete [] name; +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/fulltextsearch/qsort_p.h b/src/assistant/lib/fulltextsearch/qsort_p.h new file mode 100644 index 000000000..5d9372b11 --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qsort_p.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#ifndef QSORT_P_H +#define QSORT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qclucene_global_p.h" + +#include +#include +#include +#include + +CL_NS_DEF(search) + class Sort; +CL_NS_END +CL_NS_USE(search) + +QT_BEGIN_NAMESPACE + +class QCLuceneHits; +class QCLuceneField; + +class QHELP_EXPORT QCLuceneSortPrivate : public QSharedData +{ +public: + QCLuceneSortPrivate(); + QCLuceneSortPrivate (const QCLuceneSortPrivate &other); + + ~QCLuceneSortPrivate(); + + Sort *sort; + bool deleteCLuceneSort; + +private: + QCLuceneSortPrivate &operator=(const QCLuceneSortPrivate &other); +}; + +class QHELP_EXPORT QCLuceneSort +{ +public: + QCLuceneSort(); + explicit QCLuceneSort(const QStringList &fieldNames); + explicit QCLuceneSort(const QString &field, bool reverse = false); + + virtual ~QCLuceneSort(); + + QString toString() const; + void setSort(const QStringList &fieldNames); + void setSort(const QString &field, bool reverse = false); + +protected: + friend class QCLuceneHits; + QSharedDataPointer d; +}; + +QT_END_NAMESPACE + +#endif // QSORT_P_H diff --git a/src/assistant/lib/fulltextsearch/qterm.cpp b/src/assistant/lib/fulltextsearch/qterm.cpp new file mode 100644 index 000000000..eeebf53c8 --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qterm.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#include "qterm_p.h" +#include "qclucene_global_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +QCLuceneTermPrivate::QCLuceneTermPrivate() + : QSharedData() +{ + term = 0; + deleteCLuceneTerm = true; +} + +QCLuceneTermPrivate::QCLuceneTermPrivate(const QCLuceneTermPrivate &other) + : QSharedData() +{ + term = _CL_POINTER(other.term); + deleteCLuceneTerm = other.deleteCLuceneTerm; +} + +QCLuceneTermPrivate::~QCLuceneTermPrivate() +{ + if (deleteCLuceneTerm) + _CLDECDELETE(term); +} + + +QCLuceneTerm::QCLuceneTerm() + : d(new QCLuceneTermPrivate()) +{ + d->term = new lucene::index::Term(); +} + +QCLuceneTerm::QCLuceneTerm(const QString &field, const QString &text) + : d(new QCLuceneTermPrivate()) +{ + TCHAR *fieldName = QStringToTChar(field); + TCHAR *termText = QStringToTChar(text); + + d->term = new lucene::index::Term(fieldName, termText); + + delete [] fieldName; + delete [] termText; +} + +QCLuceneTerm::QCLuceneTerm(const QCLuceneTerm &fieldTerm, const QString &text) + : d(new QCLuceneTermPrivate()) +{ + TCHAR *termText = QStringToTChar(text); + d->term = new lucene::index::Term(fieldTerm.d->term, termText); + delete [] termText; +} + +QCLuceneTerm::~QCLuceneTerm() +{ + // nothing todo +} + +QString QCLuceneTerm::field() const +{ + return TCharToQString(d->term->field()); +} + +QString QCLuceneTerm::text() const +{ + return TCharToQString(d->term->text()); +} + +void QCLuceneTerm::set(const QString &field, const QString &text) +{ + set(field, text, true); +} + +void QCLuceneTerm::set(const QCLuceneTerm &fieldTerm, const QString &text) +{ + set(fieldTerm.field(), text, false); +} + +void QCLuceneTerm::set(const QString &field, const QString &text, bool internField) +{ + TCHAR *fieldName = QStringToTChar(field); + TCHAR *termText = QStringToTChar(text); + + d->term->set(fieldName, termText, internField); + + delete [] fieldName; + delete [] termText; +} + +bool QCLuceneTerm::equals(const QCLuceneTerm &other) const +{ + return d->term->equals(other.d->term); +} + +qint32 QCLuceneTerm::compareTo(const QCLuceneTerm &other) const +{ + return quint32(d->term->compareTo(other.d->term)); +} + +QString QCLuceneTerm::toString() const +{ + return TCharToQString(d->term->toString()); +} + +quint32 QCLuceneTerm::hashCode() const +{ + return quint32(d->term->hashCode()); +} + +quint32 QCLuceneTerm::textLength() const +{ + return quint32(d->term->textLength()); +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/fulltextsearch/qterm_p.h b/src/assistant/lib/fulltextsearch/qterm_p.h new file mode 100644 index 000000000..5b981dc53 --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qterm_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#ifndef QTERM_P_H +#define QTERM_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qclucene_global_p.h" + +#include +#include +#include + +CL_NS_DEF(index) + class Term; +CL_NS_END +CL_NS_USE(index) + +QT_BEGIN_NAMESPACE + +class QCLuceneTermQuery; +class QCLuceneRangeQuery; +class QCLucenePrefixQuery; +class QCLuceneIndexReader; +class QCLucenePhraseQuery; + +class QHELP_EXPORT QCLuceneTermPrivate : public QSharedData +{ +public: + QCLuceneTermPrivate(); + QCLuceneTermPrivate(const QCLuceneTermPrivate &other); + + ~QCLuceneTermPrivate(); + + Term *term; + bool deleteCLuceneTerm; + +private: + QCLuceneTermPrivate &operator=(const QCLuceneTermPrivate &other); +}; + +class QHELP_EXPORT QCLuceneTerm +{ +public: + QCLuceneTerm(); + QCLuceneTerm(const QString &field, const QString &text); + QCLuceneTerm(const QCLuceneTerm &fieldTerm, const QString &text); + + virtual ~QCLuceneTerm(); + + QString field() const; + QString text() const; + + void set(const QString &field, const QString &text); + void set(const QCLuceneTerm &fieldTerm, const QString &text); + void set(const QString &field, const QString &text, bool internField); + + bool equals(const QCLuceneTerm &other) const; + qint32 compareTo(const QCLuceneTerm &other) const; + + QString toString() const; + quint32 hashCode() const; + quint32 textLength() const; + +protected: + friend class QCLuceneTermQuery; + friend class QCLuceneRangeQuery; + friend class QCLucenePrefixQuery; + friend class QCLuceneIndexReader; + friend class QCLucenePhraseQuery; + QSharedDataPointer d; +}; + +QT_END_NAMESPACE + +#endif // QTERM_P_H diff --git a/src/assistant/lib/fulltextsearch/qtoken.cpp b/src/assistant/lib/fulltextsearch/qtoken.cpp new file mode 100644 index 000000000..537d9e675 --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qtoken.cpp @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#include "qtoken_p.h" +#include "qclucene_global_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +QCLuceneTokenPrivate::QCLuceneTokenPrivate() + : QSharedData() +{ + token = 0; + deleteCLuceneToken = true; +} + +QCLuceneTokenPrivate::QCLuceneTokenPrivate(const QCLuceneTokenPrivate &other) + : QSharedData() +{ + token = _CL_POINTER(other.token); + deleteCLuceneToken = other.deleteCLuceneToken; +} + +QCLuceneTokenPrivate::~QCLuceneTokenPrivate() +{ + if (deleteCLuceneToken) + _CLDECDELETE(token); +} + + +QCLuceneToken::QCLuceneToken() + : d(new QCLuceneTokenPrivate()) + , tokenText(0) + , tokenType(0) +{ + d->token = new lucene::analysis::Token(); +} + +QCLuceneToken::QCLuceneToken(const QString &text, qint32 startOffset, + qint32 endOffset, const QString &defaultTyp) + : d(new QCLuceneTokenPrivate()) + , tokenText(QStringToTChar(text)) + , tokenType(QStringToTChar(defaultTyp)) +{ + d->token = new lucene::analysis::Token(tokenText, int32_t(startOffset), + int32_t(endOffset), tokenType); +} + +QCLuceneToken::~QCLuceneToken() +{ + delete [] tokenText; + delete [] tokenType; +} + +quint32 QCLuceneToken::bufferLength() const +{ + return quint32(d->token->bufferLength()); +} + +void QCLuceneToken::growBuffer(quint32 size) +{ + d->token->growBuffer(size_t(size)); +} + +qint32 QCLuceneToken::positionIncrement() const +{ + return qint32(d->token->getPositionIncrement()); +} + +void QCLuceneToken::setPositionIncrement(qint32 positionIncrement) +{ + d->token->setPositionIncrement(int32_t(positionIncrement)); +} + +QString QCLuceneToken::termText() const +{ + return TCharToQString(d->token->termText()); +} + +void QCLuceneToken::setTermText(const QString &text) +{ + delete [] tokenText; + tokenText = QStringToTChar(text); + d->token->setText(tokenText); +} + +quint32 QCLuceneToken::termTextLength() const +{ + return quint32(d->token->termTextLength()); +} + +void QCLuceneToken::resetTermTextLength() const +{ + d->token->resetTermTextLen(); +} + +qint32 QCLuceneToken::startOffset() const +{ + return quint32(d->token->startOffset()); +} + +void QCLuceneToken::setStartOffset(qint32 value) +{ + d->token->setStartOffset(int32_t(value)); +} + +qint32 QCLuceneToken::endOffset() const +{ + return quint32(d->token->endOffset()); +} + +void QCLuceneToken::setEndOffset(qint32 value) +{ + d->token->setEndOffset(int32_t(value)); +} + +QString QCLuceneToken::type() const +{ + return TCharToQString(d->token->type()); +} + +void QCLuceneToken::setType(const QString &type) +{ + delete [] tokenType; + tokenType = QStringToTChar(type); + d->token->setType(tokenType); +} + +QString QCLuceneToken::toString() const +{ + return TCharToQString(d->token->toString()); +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/fulltextsearch/qtoken_p.h b/src/assistant/lib/fulltextsearch/qtoken_p.h new file mode 100644 index 000000000..f3d25c4ff --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qtoken_p.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#ifndef QTOKEN_P_H +#define QTOKEN_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qclucene_global_p.h" + +#include +#include +#include + +CL_NS_DEF(analysis) + class Token; +CL_NS_END +CL_NS_USE(analysis) + +QT_BEGIN_NAMESPACE + +class QCLuceneTokenizer; +class QCLuceneTokenStream; +class QCLuceneStandardTokenizer; + +class QHELP_EXPORT QCLuceneTokenPrivate : public QSharedData +{ +public: + QCLuceneTokenPrivate(); + QCLuceneTokenPrivate(const QCLuceneTokenPrivate &other); + + ~QCLuceneTokenPrivate(); + + Token *token; + bool deleteCLuceneToken; + +private: + QCLuceneTokenPrivate &operator=(const QCLuceneTokenPrivate &other); +}; + +class QHELP_EXPORT QCLuceneToken +{ +public: + QCLuceneToken(); + QCLuceneToken(const QString &text, qint32 startOffset, + qint32 endOffset, const QString &defaultTyp = QLatin1String("word")); + + virtual ~QCLuceneToken(); + + void set(const QString &text, qint32 startOffset, + qint32 endOffset, const QString &defaultTyp = QLatin1String("word")); + + quint32 bufferLength() const; + void growBuffer(quint32 size); + + qint32 positionIncrement() const; + void setPositionIncrement(qint32 positionIncrement); + + QString termText() const; + void setTermText(const QString &text); + + quint32 termTextLength() const; + void resetTermTextLength() const; + + qint32 startOffset() const; + void setStartOffset(qint32 value); + + qint32 endOffset() const; + void setEndOffset(qint32 value); + + QString type() const; + void setType(const QString &type); + + QString toString() const; + +protected: + friend class QCLuceneTokenizer; + friend class QCLuceneTokenStream; + friend class QCLuceneStandardTokenizer; + QSharedDataPointer d; + +private: + TCHAR *tokenText; + TCHAR *tokenType; +}; + +QT_END_NAMESPACE + +#endif // QTOKEN_P_H diff --git a/src/assistant/lib/fulltextsearch/qtokenizer.cpp b/src/assistant/lib/fulltextsearch/qtokenizer.cpp new file mode 100644 index 000000000..8a79b21e6 --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qtokenizer.cpp @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#include "qtokenizer_p.h" +#include "qclucene_global_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +QCLuceneTokenizer::QCLuceneTokenizer() + : QCLuceneTokenStream() +{ + // nothing todo +} + +QCLuceneTokenizer::QCLuceneTokenizer(const QCLuceneReader &reader) + : QCLuceneTokenStream() + , reader(reader) +{ + // nothing todo +} + +QCLuceneTokenizer::~QCLuceneTokenizer() +{ + close(); +} + +void QCLuceneTokenizer::close() +{ + d->tokenStream->close(); +} + +bool QCLuceneTokenizer::next(QCLuceneToken &token) +{ + return d->tokenStream->next(token.d->token); +} + + +QCLuceneStandardTokenizer::QCLuceneStandardTokenizer(const QCLuceneReader &reader) + : QCLuceneTokenizer(reader) +{ + d->tokenStream = + new lucene::analysis::standard::StandardTokenizer(reader.d->reader); +} + +QCLuceneStandardTokenizer::~QCLuceneStandardTokenizer() +{ + // nothing todo +} + +bool QCLuceneStandardTokenizer::readApostrophe(const QString &string, + QCLuceneToken &token) +{ + lucene::analysis::standard::StandardTokenizer *stdTokenizer = + static_cast (d->tokenStream); + + if (stdTokenizer == 0) + return false; + + TCHAR* value = QStringToTChar(string); + lucene::util::StringBuffer buffer(value); + bool retValue = stdTokenizer->ReadApostrophe(&buffer, token.d->token); + delete [] value; + + return retValue; +} + +bool QCLuceneStandardTokenizer::readAt(const QString &string, QCLuceneToken &token) +{ + lucene::analysis::standard::StandardTokenizer *stdTokenizer = + static_cast (d->tokenStream); + + if (stdTokenizer == 0) + return false; + + TCHAR* value = QStringToTChar(string); + lucene::util::StringBuffer buffer(value); + bool retValue = stdTokenizer->ReadAt(&buffer, token.d->token); + delete [] value; + + return retValue; +} + +bool QCLuceneStandardTokenizer::readCompany(const QString &string, + QCLuceneToken &token) +{ + lucene::analysis::standard::StandardTokenizer *stdTokenizer = + static_cast (d->tokenStream); + + if (stdTokenizer == 0) + return false; + + TCHAR* value = QStringToTChar(string); + lucene::util::StringBuffer buffer(value); + bool retValue = stdTokenizer->ReadCompany(&buffer, token.d->token); + delete [] value; + + return retValue; +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/fulltextsearch/qtokenizer_p.h b/src/assistant/lib/fulltextsearch/qtokenizer_p.h new file mode 100644 index 000000000..0c6e8ea1d --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qtokenizer_p.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#ifndef QTOKENIZER_P_H +#define QTOKENIZER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qtoken_p.h" +#include "qreader_p.h" +#include "qtokenstream_p.h" +#include "qclucene_global_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class QHELP_EXPORT QCLuceneTokenizer : public QCLuceneTokenStream +{ +public: + QCLuceneTokenizer(const QCLuceneReader &reader); + virtual ~QCLuceneTokenizer(); + + void close(); + bool next(QCLuceneToken &token); + +protected: + friend class QCLuceneStandardTokenizer; + +private: + QCLuceneTokenizer(); + QCLuceneReader reader; +}; + +class QHELP_EXPORT QCLuceneStandardTokenizer : public QCLuceneTokenizer +{ +public: + QCLuceneStandardTokenizer(const QCLuceneReader &reader); + ~QCLuceneStandardTokenizer(); + + bool readApostrophe(const QString &string, QCLuceneToken &token); + bool readAt(const QString &string, QCLuceneToken &token); + bool readCompany(const QString &string, QCLuceneToken &token); +}; + +class QCLuceneCharTokenizer : public QCLuceneTokenizer +{ + +}; + +class QCLuceneLetterTokenizer : public QCLuceneCharTokenizer +{ + +}; + +class QCLuceneLowerCaseTokenizer : public QCLuceneLetterTokenizer +{ + +}; + +class QCLuceneWhitespaceTokenizer : public QCLuceneCharTokenizer +{ + +}; + +class QCLuceneKeywordTokenizer : public QCLuceneTokenizer +{ + +}; + +QT_END_NAMESPACE + +#endif // QTOKENIZER_P_H diff --git a/src/assistant/lib/fulltextsearch/qtokenstream.cpp b/src/assistant/lib/fulltextsearch/qtokenstream.cpp new file mode 100644 index 000000000..337ebf1e3 --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qtokenstream.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#include "qtokenstream_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +QCLuceneTokenStreamPrivate::QCLuceneTokenStreamPrivate() + : QSharedData() +{ + tokenStream = 0; + deleteCLuceneTokenStream = true; +} + +QCLuceneTokenStreamPrivate::QCLuceneTokenStreamPrivate(const QCLuceneTokenStreamPrivate &other) + : QSharedData() +{ + tokenStream = _CL_POINTER(other.tokenStream); + deleteCLuceneTokenStream = other.deleteCLuceneTokenStream; +} + +QCLuceneTokenStreamPrivate::~QCLuceneTokenStreamPrivate() +{ + if (deleteCLuceneTokenStream) + _CLDECDELETE(tokenStream); +} + + +QCLuceneTokenStream::QCLuceneTokenStream() + : d(new QCLuceneTokenStreamPrivate()) +{ + // nothing todo +} + +QCLuceneTokenStream::~QCLuceneTokenStream() +{ + // nothing todo +} + +void QCLuceneTokenStream::close() +{ + d->tokenStream->close(); +} + +bool QCLuceneTokenStream::next(QCLuceneToken &token) +{ + return d->tokenStream->next(token.d->token); +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/fulltextsearch/qtokenstream_p.h b/src/assistant/lib/fulltextsearch/qtokenstream_p.h new file mode 100644 index 000000000..8f4b9d06a --- /dev/null +++ b/src/assistant/lib/fulltextsearch/qtokenstream_p.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team. +** All rights reserved. +** +** Portion Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +****************************************************************************/ + +#ifndef QTOKENSTREAM_P_H +#define QTOKENSTREAM_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qtoken_p.h" +#include "qclucene_global_p.h" + +#include +#include +#include + +CL_NS_DEF(analysis) + class TokenStream; +CL_NS_END +CL_NS_USE(analysis) + +QT_BEGIN_NAMESPACE + +class QCLuceneAnalyzer; +class QCLuceneTokenizer; +class QCLuceneStopAnalyzer; +class QCLuceneSimpleAnalyzer; +class QCLuceneKeywordAnalyzer; +class QCLuceneStandardAnalyzer; +class QCLuceneWhitespaceAnalyzer; +class QCLucenePerFieldAnalyzerWrapper; + +class QHELP_EXPORT QCLuceneTokenStreamPrivate : public QSharedData +{ +public: + QCLuceneTokenStreamPrivate(); + QCLuceneTokenStreamPrivate(const QCLuceneTokenStreamPrivate &other); + + ~QCLuceneTokenStreamPrivate(); + + TokenStream *tokenStream; + bool deleteCLuceneTokenStream; + +private: + QCLuceneTokenStreamPrivate &operator=(const QCLuceneTokenStreamPrivate &other); +}; + +class QHELP_EXPORT QCLuceneTokenStream +{ +public: + virtual ~QCLuceneTokenStream(); + + void close(); + bool next(QCLuceneToken &token); + +protected: + friend class QCLuceneAnalyzer; + friend class QCLuceneTokenizer; + friend class QCLuceneStopAnalyzer; + friend class QCLuceneSimpleAnalyzer; + friend class QCLuceneKeywordAnalyzer; + friend class QCLuceneStandardAnalyzer; + friend class QCLuceneWhitespaceAnalyzer; + friend class QCLucenePerFieldAnalyzerWrapper; + QSharedDataPointer d; + +private: + QCLuceneTokenStream(); +}; + +QT_END_NAMESPACE + +#endif // QTOKENSTREAM_P_H diff --git a/src/assistant/lib/helpsystem.qrc b/src/assistant/lib/helpsystem.qrc new file mode 100644 index 000000000..10efc6df1 --- /dev/null +++ b/src/assistant/lib/helpsystem.qrc @@ -0,0 +1,8 @@ + + + images/1leftarrow.png + images/1rightarrow.png + images/3leftarrow.png + images/3rightarrow.png + + diff --git a/src/assistant/lib/images/1leftarrow.png b/src/assistant/lib/images/1leftarrow.png new file mode 100644 index 000000000..bd1a5a249 Binary files /dev/null and b/src/assistant/lib/images/1leftarrow.png differ diff --git a/src/assistant/lib/images/1rightarrow.png b/src/assistant/lib/images/1rightarrow.png new file mode 100644 index 000000000..0c0c44ae6 Binary files /dev/null and b/src/assistant/lib/images/1rightarrow.png differ diff --git a/src/assistant/lib/images/3leftarrow.png b/src/assistant/lib/images/3leftarrow.png new file mode 100644 index 000000000..8d38b0f57 Binary files /dev/null and b/src/assistant/lib/images/3leftarrow.png differ diff --git a/src/assistant/lib/images/3rightarrow.png b/src/assistant/lib/images/3rightarrow.png new file mode 100644 index 000000000..c2faf501c Binary files /dev/null and b/src/assistant/lib/images/3rightarrow.png differ diff --git a/src/assistant/lib/lib.pro b/src/assistant/lib/lib.pro new file mode 100644 index 000000000..03821b2a7 --- /dev/null +++ b/src/assistant/lib/lib.pro @@ -0,0 +1,71 @@ +QT += sql \ + xml \ + network +TEMPLATE = lib +TARGET = QtHelp +DEFINES += QHELP_LIB \ + QT_CLUCENE_SUPPORT +CONFIG += qt \ + warn_on +include(../../../src/qbase.pri) +QMAKE_TARGET_PRODUCT = Help +QMAKE_TARGET_DESCRIPTION = Help \ + application \ + framework. +DEFINES -= QT_ASCII_CAST_WARNINGS +qclucene = QtCLucene$${QT_LIBINFIX} +if(!debug_and_release|build_pass):CONFIG(debug, debug|release) { + mac:qclucene = $${qclucene}_debug + win32:qclucene = $${qclucene}d +} +linux-lsb-g++:LIBS_PRIVATE += --lsb-shared-libs=$$qclucene +unix|win32-g++*:QMAKE_PKGCONFIG_REQUIRES += QtNetwork \ + QtSql \ + QtXml +LIBS_PRIVATE += -l$$qclucene +RESOURCES += helpsystem.qrc +SOURCES += qhelpenginecore.cpp \ + qhelpengine.cpp \ + qhelpdbreader.cpp \ + qhelpcontentwidget.cpp \ + qhelpindexwidget.cpp \ + qhelpgenerator.cpp \ + qhelpdatainterface.cpp \ + qhelpprojectdata.cpp \ + qhelpcollectionhandler.cpp \ + qhelpsearchengine.cpp \ + qhelpsearchquerywidget.cpp \ + qhelpsearchresultwidget.cpp \ + qhelpsearchindex_default.cpp \ + qhelpsearchindexwriter_default.cpp \ + qhelpsearchindexreader_default.cpp \ + qhelpsearchindexreader.cpp \ + qclucenefieldnames.cpp \ + qhelp_global.cpp + +# access to clucene +SOURCES += qhelpsearchindexwriter_clucene.cpp \ + qhelpsearchindexreader_clucene.cpp +HEADERS += qhelpenginecore.h \ + qhelpengine.h \ + qhelpengine_p.h \ + qhelp_global.h \ + qhelpdbreader_p.h \ + qhelpcontentwidget.h \ + qhelpindexwidget.h \ + qhelpgenerator_p.h \ + qhelpdatainterface_p.h \ + qhelpprojectdata_p.h \ + qhelpcollectionhandler_p.h \ + qhelpsearchengine.h \ + qhelpsearchquerywidget.h \ + qhelpsearchresultwidget.h \ + qhelpsearchindex_default_p.h \ + qhelpsearchindexwriter_default_p.h \ + qhelpsearchindexreader_default_p.h \ + qhelpsearchindexreader_p.h \ + qclucenefieldnames_p.h + +# access to clucene +HEADERS += qhelpsearchindexwriter_clucene_p.h \ + qhelpsearchindexreader_clucene_p.h diff --git a/src/assistant/lib/qclucenefieldnames.cpp b/src/assistant/lib/qclucenefieldnames.cpp new file mode 100644 index 000000000..31ef415af --- /dev/null +++ b/src/assistant/lib/qclucenefieldnames.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qclucenefieldnames_p.h" + +QT_BEGIN_NAMESPACE + +namespace fulltextsearch { +namespace clucene { +const QString AttributeField(QLatin1String("attribute")); +const QString ContentField(QLatin1String("content")); +const QString NamespaceField(QLatin1String("namespace")); +const QString PathField(QLatin1String("path")); +const QString TitleField(QLatin1String("title")); +const QString TitleTokenizedField(QLatin1String("titleTokenized")); +} // namespace clucene +} // namespace fulltextsearch + +QT_END_NAMESPACE diff --git a/src/assistant/lib/qclucenefieldnames_p.h b/src/assistant/lib/qclucenefieldnames_p.h new file mode 100644 index 000000000..733e27121 --- /dev/null +++ b/src/assistant/lib/qclucenefieldnames_p.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCLUCENEFIELDNAMES_P_H +#define QCLUCENEFIELDNAMES_P_H + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace fulltextsearch { +namespace clucene { + extern const QString AttributeField; + extern const QString ContentField; + extern const QString NamespaceField; + extern const QString PathField; + extern const QString TitleField; + extern const QString TitleTokenizedField; +} // namespace clucene +} // namespace fulltextsearch + +QT_END_NAMESPACE + +#endif // QCLUCENEFIELDNAMES_P_H diff --git a/src/assistant/lib/qhelp_global.cpp b/src/assistant/lib/qhelp_global.cpp new file mode 100644 index 000000000..2c7ca6214 --- /dev/null +++ b/src/assistant/lib/qhelp_global.cpp @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +#include "qhelp_global.h" + +QString QHelpGlobal::uniquifyConnectionName(const QString &name, void *pointer) +{ + static int counter = 0; + static QMutex mutex; + + QMutexLocker locker(&mutex); + if (++counter > 1000) + counter = 0; + + return QString::fromLatin1("%1-%2-%3"). + arg(name).arg(quintptr(pointer)).arg(counter); +} + +QString QHelpGlobal::documentTitle(const QString &content) +{ + QString title = QCoreApplication::translate("QHelp", "Untitled"); + if (!content.isEmpty()) { + int start = content.indexOf(QLatin1String(""), 0, Qt::CaseInsensitive) + 7; + int end = content.indexOf(QLatin1String(""), 0, Qt::CaseInsensitive); + if ((end - start) > 0) { + title = content.mid(start, end - start); + if (Qt::mightBeRichText(title) || title.contains(QLatin1Char('&'))) { + QTextDocument doc; + doc.setHtml(title); + title = doc.toPlainText(); + } + } + } + return title; +} + +QString QHelpGlobal::codecFromData(const QByteArray &data) +{ + QString codec = codecFromXmlData(data); + if (codec.isEmpty()) + codec = codecFromHtmlData(data); + return codec.isEmpty() ? QLatin1String("utf-8") : codec; +} + +QString QHelpGlobal::codecFromHtmlData(const QByteArray &data) +{ + QString head = QString::fromUtf8(data.constData(), qMin(1000, data.size())); + int start = head.indexOf(QLatin1String(" 0) { + QRegExp r(QLatin1String("charset=([^\"\\s]+)")); + while (start != -1) { + const int end = head.indexOf(QLatin1Char('>'), start) + 1; + if (end <= start) + break; + const QString &meta = head.mid(start, end - start).toLower(); + if (r.indexIn(meta) != -1) + return r.cap(1); + start = head.indexOf(QLatin1String(".*")); + return encodingExp.exactMatch(head) ? encodingExp.cap(1) : QString(); +} diff --git a/src/assistant/lib/qhelp_global.h b/src/assistant/lib/qhelp_global.h new file mode 100644 index 000000000..182298fc2 --- /dev/null +++ b/src/assistant/lib/qhelp_global.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELP_GLOBAL_H +#define QHELP_GLOBAL_H + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +#if !defined(QT_SHARED) && !defined(QT_DLL) +# define QHELP_EXPORT +#elif defined(QHELP_LIB) +# define QHELP_EXPORT Q_DECL_EXPORT +#else +# define QHELP_EXPORT Q_DECL_IMPORT +#endif + +class QHelpGlobal { +public: + static QString uniquifyConnectionName(const QString &name, void *pointer); + static QString documentTitle(const QString &content); + static QString codecFromData(const QByteArray &data); + +private: + static QString codecFromHtmlData(const QByteArray &data); + static QString codecFromXmlData(const QByteArray &data); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QHELP_GLOBAL_H diff --git a/src/assistant/lib/qhelpcollectionhandler.cpp b/src/assistant/lib/qhelpcollectionhandler.cpp new file mode 100644 index 000000000..169d37e05 --- /dev/null +++ b/src/assistant/lib/qhelpcollectionhandler.cpp @@ -0,0 +1,603 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpcollectionhandler_p.h" +#include "qhelp_global.h" +#include "qhelpdbreader_p.h" + +#include +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +QHelpCollectionHandler::QHelpCollectionHandler(const QString &collectionFile, QObject *parent) + : QObject(parent) + , m_dbOpened(false) + , m_collectionFile(collectionFile) + , m_connectionName(QString()) +{ + QFileInfo fi(m_collectionFile); + if (!fi.isAbsolute()) + m_collectionFile = fi.absoluteFilePath(); + m_query.clear(); +} + +QHelpCollectionHandler::~QHelpCollectionHandler() +{ + m_query.clear(); + if (m_dbOpened) + QSqlDatabase::removeDatabase(m_connectionName); +} + +bool QHelpCollectionHandler::isDBOpened() +{ + if (m_dbOpened) + return true; + emit error(tr("The collection file '%1' is not set up yet!"). + arg(m_collectionFile)); + return false; +} + +QString QHelpCollectionHandler::collectionFile() const +{ + return m_collectionFile; +} + +bool QHelpCollectionHandler::openCollectionFile() +{ + if (m_dbOpened) + return m_dbOpened; + + m_connectionName = QHelpGlobal::uniquifyConnectionName( + QLatin1String("QHelpCollectionHandler"), this); + bool openingOk = true; + { + QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), + m_connectionName); + if (db.driver() + && db.driver()->lastError().type() == QSqlError::ConnectionError) { + emit error(tr("Cannot load sqlite database driver!")); + return false; + } + + db.setDatabaseName(collectionFile()); + openingOk = db.open(); + if (openingOk) + m_query = QSqlQuery(db); + } + if (!openingOk) { + QSqlDatabase::removeDatabase(m_connectionName); + emit error(tr("Cannot open collection file: %1").arg(collectionFile())); + return false; + } + + m_query.exec(QLatin1String("PRAGMA synchronous=OFF")); + m_query.exec(QLatin1String("PRAGMA cache_size=3000")); + + m_query.exec(QLatin1String("SELECT COUNT(*) FROM sqlite_master WHERE TYPE=\'table\'" + "AND Name=\'NamespaceTable\'")); + m_query.next(); + if (m_query.value(0).toInt() < 1) { + if (!createTables(&m_query)) { + emit error(tr("Cannot create tables in file %1!").arg(collectionFile())); + return false; + } + } + + m_dbOpened = true; + return m_dbOpened; +} + +bool QHelpCollectionHandler::copyCollectionFile(const QString &fileName) +{ + if (!m_dbOpened) + return false; + + QFileInfo fi(fileName); + if (fi.exists()) { + emit error(tr("The collection file '%1' already exists!"). + arg(fileName)); + return false; + } + + if (!fi.absoluteDir().exists() && !QDir().mkpath(fi.absolutePath())) { + emit error(tr("Cannot create directory: %1").arg(fi.absolutePath())); + return false; + } + + QString colFile = fi.absoluteFilePath(); + QString connectionName = QHelpGlobal::uniquifyConnectionName( + QLatin1String("QHelpCollectionHandlerCopy"), this); + QSqlQuery *copyQuery = 0; + bool openingOk = true; + { + QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), connectionName); + db.setDatabaseName(colFile); + openingOk = db.open(); + if (openingOk) + copyQuery = new QSqlQuery(db); + } + + if (!openingOk) { + emit error(tr("Cannot open collection file: %1").arg(colFile)); + return false; + } + + copyQuery->exec(QLatin1String("PRAGMA synchronous=OFF")); + copyQuery->exec(QLatin1String("PRAGMA cache_size=3000")); + + if (!createTables(copyQuery)) { + emit error(tr("Cannot copy collection file: %1").arg(colFile)); + return false; + } + + QString oldBaseDir = QFileInfo(collectionFile()).absolutePath(); + QString oldFilePath; + QFileInfo newColFi(colFile); + m_query.exec(QLatin1String("SELECT Name, FilePath FROM NamespaceTable")); + while (m_query.next()) { + copyQuery->prepare(QLatin1String("INSERT INTO NamespaceTable VALUES(NULL, ?, ?)")); + copyQuery->bindValue(0, m_query.value(0).toString()); + oldFilePath = m_query.value(1).toString(); + if (!QDir::isAbsolutePath(oldFilePath)) + oldFilePath = oldBaseDir + QDir::separator() + oldFilePath; + copyQuery->bindValue(1, newColFi.absoluteDir().relativeFilePath(oldFilePath)); + copyQuery->exec(); + } + + m_query.exec(QLatin1String("SELECT NamespaceId, Name FROM FolderTable")); + while (m_query.next()) { + copyQuery->prepare(QLatin1String("INSERT INTO FolderTable VALUES(NULL, ?, ?)")); + copyQuery->bindValue(0, m_query.value(0).toString()); + copyQuery->bindValue(1, m_query.value(1).toString()); + copyQuery->exec(); + } + + m_query.exec(QLatin1String("SELECT Name FROM FilterAttributeTable")); + while (m_query.next()) { + copyQuery->prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)")); + copyQuery->bindValue(0, m_query.value(0).toString()); + copyQuery->exec(); + } + + m_query.exec(QLatin1String("SELECT Name FROM FilterNameTable")); + while (m_query.next()) { + copyQuery->prepare(QLatin1String("INSERT INTO FilterNameTable VALUES(NULL, ?)")); + copyQuery->bindValue(0, m_query.value(0).toString()); + copyQuery->exec(); + } + + m_query.exec(QLatin1String("SELECT NameId, FilterAttributeId FROM FilterTable")); + while (m_query.next()) { + copyQuery->prepare(QLatin1String("INSERT INTO FilterTable VALUES(?, ?)")); + copyQuery->bindValue(0, m_query.value(0).toInt()); + copyQuery->bindValue(1, m_query.value(1).toInt()); + copyQuery->exec(); + } + + m_query.exec(QLatin1String("SELECT Key, Value FROM SettingsTable")); + while (m_query.next()) { + if (m_query.value(0).toString() == QLatin1String("CluceneSearchNamespaces")) + continue; + copyQuery->prepare(QLatin1String("INSERT INTO SettingsTable VALUES(?, ?)")); + copyQuery->bindValue(0, m_query.value(0).toString()); + copyQuery->bindValue(1, m_query.value(1)); + copyQuery->exec(); + } + + copyQuery->clear(); + delete copyQuery; + QSqlDatabase::removeDatabase(connectionName); + return true; +} + +bool QHelpCollectionHandler::createTables(QSqlQuery *query) +{ + QStringList tables; + tables << QLatin1String("CREATE TABLE NamespaceTable (" + "Id INTEGER PRIMARY KEY, " + "Name TEXT, " + "FilePath TEXT )") + << QLatin1String("CREATE TABLE FolderTable (" + "Id INTEGER PRIMARY KEY, " + "NamespaceId INTEGER, " + "Name TEXT )") + << QLatin1String("CREATE TABLE FilterAttributeTable (" + "Id INTEGER PRIMARY KEY, " + "Name TEXT )") + << QLatin1String("CREATE TABLE FilterNameTable (" + "Id INTEGER PRIMARY KEY, " + "Name TEXT )") + << QLatin1String("CREATE TABLE FilterTable (" + "NameId INTEGER, " + "FilterAttributeId INTEGER )") + << QLatin1String("CREATE TABLE SettingsTable (" + "Key TEXT PRIMARY KEY, " + "Value BLOB )"); + + foreach (const QString &q, tables) { + if (!query->exec(q)) + return false; + } + return true; +} + +QStringList QHelpCollectionHandler::customFilters() const +{ + QStringList list; + if (m_dbOpened) { + m_query.exec(QLatin1String("SELECT Name FROM FilterNameTable")); + while (m_query.next()) + list.append(m_query.value(0).toString()); + } + return list; +} + +bool QHelpCollectionHandler::removeCustomFilter(const QString &filterName) +{ + if (!isDBOpened() || filterName.isEmpty()) + return false; + + int filterNameId = -1; + m_query.prepare(QLatin1String("SELECT Id FROM FilterNameTable WHERE Name=?")); + m_query.bindValue(0, filterName); + m_query.exec(); + if (m_query.next()) + filterNameId = m_query.value(0).toInt(); + + if (filterNameId < 0) { + emit error(tr("Unknown filter '%1'!").arg(filterName)); + return false; + } + + m_query.prepare(QLatin1String("DELETE FROM FilterTable WHERE NameId=?")); + m_query.bindValue(0, filterNameId); + m_query.exec(); + + m_query.prepare(QLatin1String("DELETE FROM FilterNameTable WHERE Id=?")); + m_query.bindValue(0, filterNameId); + m_query.exec(); + + return true; +} + +bool QHelpCollectionHandler::addCustomFilter(const QString &filterName, + const QStringList &attributes) +{ + if (!isDBOpened() || filterName.isEmpty()) + return false; + + int nameId = -1; + m_query.prepare(QLatin1String("SELECT Id FROM FilterNameTable WHERE Name=?")); + m_query.bindValue(0, filterName); + m_query.exec(); + if (m_query.next()) + nameId = m_query.value(0).toInt(); + + m_query.exec(QLatin1String("SELECT Id, Name FROM FilterAttributeTable")); + QStringList idsToInsert = attributes; + QMap attributeMap; + while (m_query.next()) { + attributeMap.insert(m_query.value(1).toString(), + m_query.value(0).toInt()); + if (idsToInsert.contains(m_query.value(1).toString())) + idsToInsert.removeAll(m_query.value(1).toString()); + } + + foreach (const QString &id, idsToInsert) { + m_query.prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)")); + m_query.bindValue(0, id); + m_query.exec(); + attributeMap.insert(id, m_query.lastInsertId().toInt()); + } + + if (nameId < 0) { + m_query.prepare(QLatin1String("INSERT INTO FilterNameTable VALUES(NULL, ?)")); + m_query.bindValue(0, filterName); + if (m_query.exec()) + nameId = m_query.lastInsertId().toInt(); + } + + if (nameId < 0) { + emit error(tr("Cannot register filter %1!").arg(filterName)); + return false; + } + + m_query.prepare(QLatin1String("DELETE FROM FilterTable WHERE NameId=?")); + m_query.bindValue(0, nameId); + m_query.exec(); + + foreach (const QString &att, attributes) { + m_query.prepare(QLatin1String("INSERT INTO FilterTable VALUES(?, ?)")); + m_query.bindValue(0, nameId); + m_query.bindValue(1, attributeMap[att]); + if (!m_query.exec()) + return false; + } + return true; +} + +QHelpCollectionHandler::DocInfoList QHelpCollectionHandler::registeredDocumentations() const +{ + DocInfoList list; + if (m_dbOpened) { + m_query.exec(QLatin1String("SELECT a.Name, a.FilePath, b.Name " + "FROM NamespaceTable a, FolderTable b WHERE a.Id=b.NamespaceId")); + + while (m_query.next()) { + DocInfo info; + info.fileName = m_query.value(1).toString(); + info.folderName = m_query.value(2).toString(); + info.namespaceName = m_query.value(0).toString(); + list.append(info); + } + } + return list; +} + +bool QHelpCollectionHandler::registerDocumentation(const QString &fileName) +{ + if (!isDBOpened()) + return false; + + QHelpDBReader reader(fileName, QHelpGlobal::uniquifyConnectionName( + QLatin1String("QHelpCollectionHandler"), this), 0); + if (!reader.init()) { + emit error(tr("Cannot open documentation file %1!").arg(fileName)); + return false; + } + + QString ns = reader.namespaceName(); + if (ns.isEmpty()) { + emit error(tr("Invalid documentation file '%1'!").arg(fileName)); + return false; + } + + int nsId = registerNamespace(ns, fileName); + if (nsId < 1) + return false; + + if (!registerVirtualFolder(reader.virtualFolder(), nsId)) + return false; + + addFilterAttributes(reader.filterAttributes()); + foreach (const QString &filterName, reader.customFilters()) + addCustomFilter(filterName, reader.filterAttributes(filterName)); + + optimizeDatabase(fileName); + + return true; +} + +bool QHelpCollectionHandler::unregisterDocumentation(const QString &namespaceName) +{ + if (!isDBOpened()) + return false; + + m_query.prepare(QLatin1String("SELECT Id FROM NamespaceTable WHERE Name=?")); + m_query.bindValue(0, namespaceName); + m_query.exec(); + + int nsId = -1; + if (m_query.next()) + nsId = m_query.value(0).toInt(); + + if (nsId < 0) { + emit error(tr("The namespace %1 was not registered!").arg(namespaceName)); + return false; + } + + m_query.prepare(QLatin1String("DELETE FROM NamespaceTable WHERE Id=?")); + m_query.bindValue(0, nsId); + m_query.exec(); + + m_query.prepare(QLatin1String("DELETE FROM FolderTable WHERE NamespaceId=?")); + m_query.bindValue(0, nsId); + return m_query.exec(); +} + +bool QHelpCollectionHandler::removeCustomValue(const QString &key) +{ + if (!isDBOpened()) + return false; + + m_query.prepare(QLatin1String("DELETE FROM SettingsTable WHERE Key=?")); + m_query.bindValue(0, key); + return m_query.exec(); +} + +QVariant QHelpCollectionHandler::customValue(const QString &key, + const QVariant &defaultValue) const +{ + QVariant value = defaultValue; + if (m_dbOpened) { + m_query.prepare(QLatin1String("SELECT COUNT(Key) FROM SettingsTable WHERE Key=?")); + m_query.bindValue(0, key); + if (!m_query.exec() || !m_query.next() || !m_query.value(0).toInt()) { + m_query.clear(); + return defaultValue; + } + + m_query.clear(); + m_query.prepare(QLatin1String("SELECT Value FROM SettingsTable WHERE Key=?")); + m_query.bindValue(0, key); + if (m_query.exec() && m_query.next()) + value = m_query.value(0); + m_query.clear(); + } + return value; +} + +bool QHelpCollectionHandler::setCustomValue(const QString &key, + const QVariant &value) +{ + if (!isDBOpened()) + return false; + + m_query.prepare(QLatin1String("SELECT Value FROM SettingsTable WHERE Key=?")); + m_query.bindValue(0, key); + m_query.exec(); + if (m_query.next()) { + m_query.prepare(QLatin1String("UPDATE SettingsTable SET Value=? where Key=?")); + m_query.bindValue(0, value); + m_query.bindValue(1, key); + } + else { + m_query.prepare(QLatin1String("INSERT INTO SettingsTable VALUES(?, ?)")); + m_query.bindValue(0, key); + m_query.bindValue(1, value); + } + return m_query.exec(); +} + +bool QHelpCollectionHandler::addFilterAttributes(const QStringList &attributes) +{ + if (!isDBOpened()) + return false; + + m_query.exec(QLatin1String("SELECT Name FROM FilterAttributeTable")); + QSet atts; + while (m_query.next()) + atts.insert(m_query.value(0).toString()); + + foreach (const QString &s, attributes) { + if (!atts.contains(s)) { + m_query.prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)")); + m_query.bindValue(0, s); + m_query.exec(); + } + } + return true; +} + +QStringList QHelpCollectionHandler::filterAttributes() const +{ + QStringList list; + if (m_dbOpened) { + m_query.exec(QLatin1String("SELECT Name FROM FilterAttributeTable")); + while (m_query.next()) + list.append(m_query.value(0).toString()); + } + return list; +} + +QStringList QHelpCollectionHandler::filterAttributes(const QString &filterName) const +{ + QStringList list; + if (m_dbOpened) { + m_query.prepare(QLatin1String("SELECT a.Name FROM FilterAttributeTable a, " + "FilterTable b, FilterNameTable c WHERE a.Id=b.FilterAttributeId " + "AND b.NameId=c.Id AND c.Name=?")); + m_query.bindValue(0, filterName); + m_query.exec(); + while (m_query.next()) + list.append(m_query.value(0).toString()); + } + return list; +} + +int QHelpCollectionHandler::registerNamespace(const QString &nspace, const QString &fileName) +{ + m_query.prepare(QLatin1String("SELECT COUNT(Id) FROM NamespaceTable WHERE Name=?")); + m_query.bindValue(0, nspace); + m_query.exec(); + while (m_query.next()) { + if (m_query.value(0).toInt() > 0) { + emit error(tr("Namespace %1 already exists!").arg(nspace)); + return -1; + } + } + + QFileInfo fi(m_collectionFile); + m_query.prepare(QLatin1String("INSERT INTO NamespaceTable VALUES(NULL, ?, ?)")); + m_query.bindValue(0, nspace); + m_query.bindValue(1, fi.absoluteDir().relativeFilePath(fileName)); + int namespaceId = -1; + if (m_query.exec()) + namespaceId = m_query.lastInsertId().toInt(); + if (namespaceId < 1) { + emit error(tr("Cannot register namespace '%1'!").arg(nspace)); + return -1; + } + return namespaceId; +} + +bool QHelpCollectionHandler::registerVirtualFolder(const QString &folderName, int namespaceId) +{ + m_query.prepare(QLatin1String("INSERT INTO FolderTable VALUES(NULL, ?, ?)")); + m_query.bindValue(0, namespaceId); + m_query.bindValue(1, folderName); + return m_query.exec(); +} + +void QHelpCollectionHandler::optimizeDatabase(const QString &fileName) +{ + if (!QFile::exists(fileName)) + return; + + { // according to removeDatabase() documentation + QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), QLatin1String("optimize")); + db.setDatabaseName(fileName); + if (!db.open()) { + QSqlDatabase::removeDatabase(QLatin1String("optimize")); + emit error(tr("Cannot open database '%1' to optimize!").arg(fileName)); + return; + } + + QSqlQuery query(db); + db.exec(QLatin1String("PRAGMA synchronous=OFF")); + db.exec(QLatin1String("PRAGMA cache_size=3000")); + db.exec(QLatin1String("CREATE INDEX IF NOT EXISTS NameIndex ON IndexTable(Name)")); + db.exec(QLatin1String("CREATE INDEX IF NOT EXISTS FileNameIndex ON FileNameTable(Name)")); + db.exec(QLatin1String("CREATE INDEX IF NOT EXISTS FileIdIndex ON FileNameTable(FileId)")); + + db.close(); + } + + QSqlDatabase::removeDatabase(QLatin1String("optimize")); +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/qhelpcollectionhandler_p.h b/src/assistant/lib/qhelpcollectionhandler_p.h new file mode 100644 index 000000000..a97af8fa9 --- /dev/null +++ b/src/assistant/lib/qhelpcollectionhandler_p.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPCOLLECTIONHANDLER_H +#define QHELPCOLLECTIONHANDLER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QHelpCollectionHandler : public QObject +{ + Q_OBJECT + +public: + struct DocInfo + { + QString fileName; + QString folderName; + QString namespaceName; + }; + typedef QList DocInfoList; + + explicit QHelpCollectionHandler(const QString &collectionFile, + QObject *parent = 0); + ~QHelpCollectionHandler(); + + QString collectionFile() const; + + bool openCollectionFile(); + bool copyCollectionFile(const QString &fileName); + + QStringList customFilters() const; + bool removeCustomFilter(const QString &filterName); + bool addCustomFilter(const QString &filterName, + const QStringList &attributes); + + DocInfoList registeredDocumentations() const; + bool registerDocumentation(const QString &fileName); + bool unregisterDocumentation(const QString &namespaceName); + + bool removeCustomValue(const QString &key); + QVariant customValue(const QString &key, const QVariant &defaultValue) const; + bool setCustomValue(const QString &key, const QVariant &value); + + bool addFilterAttributes(const QStringList &attributes); + QStringList filterAttributes() const; + QStringList filterAttributes(const QString &filterName) const; + + int registerNamespace(const QString &nspace, const QString &fileName); + bool registerVirtualFolder(const QString &folderName, int namespaceId); + void optimizeDatabase(const QString &fileName); + +signals: + void error(const QString &msg); + +private: + bool isDBOpened(); + bool createTables(QSqlQuery *query); + + bool m_dbOpened; + QString m_collectionFile; + QString m_connectionName; + mutable QSqlQuery m_query; +}; + +QT_END_NAMESPACE + +#endif //QHELPCOLLECTIONHANDLER_H diff --git a/src/assistant/lib/qhelpcontentwidget.cpp b/src/assistant/lib/qhelpcontentwidget.cpp new file mode 100644 index 000000000..988a909e0 --- /dev/null +++ b/src/assistant/lib/qhelpcontentwidget.cpp @@ -0,0 +1,586 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpcontentwidget.h" +#include "qhelpenginecore.h" +#include "qhelpengine_p.h" +#include "qhelpdbreader_p.h" + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QHelpContentItemPrivate +{ +public: + QHelpContentItemPrivate(const QString &t, const QString &l, + QHelpDBReader *r, QHelpContentItem *p) + { + parent = p; + title = t; + link = l; + helpDBReader = r; + } + + QList childItems; + QHelpContentItem *parent; + QString title; + QString link; + QHelpDBReader *helpDBReader; +}; + +class QHelpContentProvider : public QThread +{ +public: + QHelpContentProvider(QHelpEnginePrivate *helpEngine); + ~QHelpContentProvider(); + void collectContents(const QString &customFilterName); + void stopCollecting(); + QHelpContentItem *rootItem(); + int nextChildCount() const; + +private: + void run(); + + QHelpEnginePrivate *m_helpEngine; + QHelpContentItem *m_rootItem; + QStringList m_filterAttributes; + QQueue m_rootItems; + QMutex m_mutex; + bool m_abort; +}; + +class QHelpContentModelPrivate +{ +public: + QHelpContentItem *rootItem; + QHelpContentProvider *qhelpContentProvider; +}; + + + +/*! + \class QHelpContentItem + \inmodule QtHelp + \brief The QHelpContentItem class provides an item for use with QHelpContentModel. + \since 4.4 +*/ + +QHelpContentItem::QHelpContentItem(const QString &name, const QString &link, + QHelpDBReader *reader, QHelpContentItem *parent) +{ + d = new QHelpContentItemPrivate(name, link, reader, parent); +} + +/*! + Destroys the help content item. +*/ +QHelpContentItem::~QHelpContentItem() +{ + qDeleteAll(d->childItems); + delete d; +} + +void QHelpContentItem::appendChild(QHelpContentItem *item) +{ + d->childItems.append(item); +} + +/*! + Returns the child of the content item in the give \a row. + + \sa parent() +*/ +QHelpContentItem *QHelpContentItem::child(int row) const +{ + if (row >= childCount()) + return 0; + return d->childItems.value(row); +} + +/*! + Returns the number of child items. +*/ +int QHelpContentItem::childCount() const +{ + return d->childItems.count(); +} + +/*! + Returns the row of this item from its parents view. +*/ +int QHelpContentItem::row() const +{ + if (d->parent) + return d->parent->d->childItems.indexOf(const_cast(this)); + return 0; +} + +/*! + Returns the title of the content item. +*/ +QString QHelpContentItem::title() const +{ + return d->title; +} + +/*! + Returns the URL of this content item. +*/ +QUrl QHelpContentItem::url() const +{ + return d->helpDBReader->urlOfPath(d->link); +} + +/*! + Returns the parent content item. +*/ +QHelpContentItem *QHelpContentItem::parent() const +{ + return d->parent; +} + +/*! + Returns the position of a given \a child. +*/ +int QHelpContentItem::childPosition(QHelpContentItem *child) const +{ + return d->childItems.indexOf(child); +} + + + +QHelpContentProvider::QHelpContentProvider(QHelpEnginePrivate *helpEngine) + : QThread(helpEngine) +{ + m_helpEngine = helpEngine; + m_rootItem = 0; + m_abort = false; +} + +QHelpContentProvider::~QHelpContentProvider() +{ + stopCollecting(); +} + +void QHelpContentProvider::collectContents(const QString &customFilterName) +{ + m_mutex.lock(); + m_filterAttributes = m_helpEngine->q->filterAttributes(customFilterName); + m_mutex.unlock(); + if (!isRunning()) { + start(LowPriority); + } else { + stopCollecting(); + start(LowPriority); + } +} + +void QHelpContentProvider::stopCollecting() +{ + if (!isRunning()) + return; + m_mutex.lock(); + m_abort = true; + m_mutex.unlock(); + wait(); +} + +QHelpContentItem *QHelpContentProvider::rootItem() +{ + QMutexLocker locker(&m_mutex); + return m_rootItems.dequeue(); +} + +int QHelpContentProvider::nextChildCount() const +{ + return m_rootItems.head()->childCount(); +} + +void QHelpContentProvider::run() +{ + QString title; + QString link; + int depth = 0; + QHelpContentItem *item = 0; + + m_mutex.lock(); + m_rootItem = new QHelpContentItem(QString(), QString(), 0); + m_rootItems.enqueue(m_rootItem); + QStringList atts = m_filterAttributes; + const QStringList fileNames = m_helpEngine->orderedFileNameList; + m_mutex.unlock(); + + foreach (const QString &dbFileName, fileNames) { + m_mutex.lock(); + if (m_abort) { + m_abort = false; + m_mutex.unlock(); + break; + } + m_mutex.unlock(); + QHelpDBReader reader(dbFileName, + QHelpGlobal::uniquifyConnectionName(dbFileName + + QLatin1String("FromQHelpContentProvider"), + QThread::currentThread()), 0); + if (!reader.init()) + continue; + foreach (const QByteArray& ba, reader.contentsForFilter(atts)) { + if (ba.size() < 1) + continue; + + int _depth = 0; + bool _root = false; + QStack stack; + + QDataStream s(ba); + for (;;) { + s >> depth; + s >> link; + s >> title; + if (title.isEmpty()) + break; +CHECK_DEPTH: + if (depth == 0) { + m_mutex.lock(); + item = new QHelpContentItem(title, link, + m_helpEngine->fileNameReaderMap.value(dbFileName), m_rootItem); + m_rootItem->appendChild(item); + m_mutex.unlock(); + stack.push(item); + _depth = 1; + _root = true; + } else { + if (depth > _depth && _root) { + _depth = depth; + stack.push(item); + } + if (depth == _depth) { + item = new QHelpContentItem(title, link, + m_helpEngine->fileNameReaderMap.value(dbFileName), stack.top()); + stack.top()->appendChild(item); + } else if (depth < _depth) { + stack.pop(); + --_depth; + goto CHECK_DEPTH; + } + } + } + } + } + m_mutex.lock(); + m_abort = false; + m_mutex.unlock(); +} + + + +/*! + \class QHelpContentModel + \inmodule QtHelp + \brief The QHelpContentModel class provides a model that supplies content to views. + \since 4.4 +*/ + +/*! + \fn void QHelpContentModel::contentsCreationStarted() + + This signal is emitted when the creation of the contents has + started. The current contents are invalid from this point on + until the signal contentsCreated() is emitted. + + \sa isCreatingContents() +*/ + +/*! + \fn void QHelpContentModel::contentsCreated() + + This signal is emitted when the contents have been created. +*/ + +QHelpContentModel::QHelpContentModel(QHelpEnginePrivate *helpEngine) + : QAbstractItemModel(helpEngine) +{ + d = new QHelpContentModelPrivate(); + d->rootItem = 0; + d->qhelpContentProvider = new QHelpContentProvider(helpEngine); + + connect(d->qhelpContentProvider, SIGNAL(finished()), + this, SLOT(insertContents()), Qt::QueuedConnection); + connect(helpEngine->q, SIGNAL(setupStarted()), this, SLOT(invalidateContents())); +} + +/*! + Destroys the help content model. +*/ +QHelpContentModel::~QHelpContentModel() +{ + delete d->rootItem; + delete d; +} + +void QHelpContentModel::invalidateContents(bool onShutDown) +{ + if (onShutDown) + disconnect(this, SLOT(insertContents())); + d->qhelpContentProvider->stopCollecting(); + if (d->rootItem) { + delete d->rootItem; + d->rootItem = 0; + } + if (!onShutDown) + reset(); +} + +/*! + Creates new contents by querying the help system + for contents specified for the \a customFilterName. +*/ +void QHelpContentModel::createContents(const QString &customFilterName) +{ + d->qhelpContentProvider->collectContents(customFilterName); + emit contentsCreationStarted(); +} + +void QHelpContentModel::insertContents() +{ + int count; + if (d->rootItem) { + count = d->rootItem->childCount() - 1; + beginRemoveRows(QModelIndex(), 0, count > 0 ? count : 0); + delete d->rootItem; + d->rootItem = 0; + endRemoveRows(); + } + + count = d->qhelpContentProvider->nextChildCount() - 1; + beginInsertRows(QModelIndex(), 0, count > 0 ? count : 0); + d->rootItem = d->qhelpContentProvider->rootItem(); + endInsertRows(); + reset(); + emit contentsCreated(); +} + +/*! + Returns true if the contents are currently rebuilt, otherwise + false. +*/ +bool QHelpContentModel::isCreatingContents() const +{ + return d->qhelpContentProvider->isRunning(); +} + +/*! + Returns the help content item at the model index position + \a index. +*/ +QHelpContentItem *QHelpContentModel::contentItemAt(const QModelIndex &index) const +{ + if (index.isValid()) + return static_cast(index.internalPointer()); + else + return d->rootItem; +} + +/*! + Returns the index of the item in the model specified by + the given \a row, \a column and \a parent index. +*/ +QModelIndex QHelpContentModel::index(int row, int column, const QModelIndex &parent) const +{ + if (!d->rootItem) + return QModelIndex(); + + QHelpContentItem *parentItem = contentItemAt(parent); + QHelpContentItem *item = parentItem->child(row); + if (!item) + return QModelIndex(); + return createIndex(row, column, item); +} + +/*! + Returns the parent of the model item with the given + \a index, or QModelIndex() if it has no parent. +*/ +QModelIndex QHelpContentModel::parent(const QModelIndex &index) const +{ + QHelpContentItem *item = contentItemAt(index); + if (!item) + return QModelIndex(); + + QHelpContentItem *parentItem = static_cast(item->parent()); + if (!parentItem) + return QModelIndex(); + + QHelpContentItem *grandparentItem = static_cast(parentItem->parent()); + if (!grandparentItem) + return QModelIndex(); + + int row = grandparentItem->childPosition(parentItem); + return createIndex(row, index.column(), parentItem); +} + +/*! + Returns the number of rows under the given \a parent. +*/ +int QHelpContentModel::rowCount(const QModelIndex &parent) const +{ + QHelpContentItem *parentItem = contentItemAt(parent); + if (!parentItem) + return 0; + return parentItem->childCount(); +} + +/*! + Returns the number of columns under the given \a parent. Currently returns always 1. +*/ +int QHelpContentModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent) + + return 1; +} + +/*! + Returns the data stored under the given \a role for + the item referred to by the \a index. +*/ +QVariant QHelpContentModel::data(const QModelIndex &index, int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + QHelpContentItem *item = contentItemAt(index); + if (!item) + return QVariant(); + return item->title(); +} + + + +/*! + \class QHelpContentWidget + \inmodule QtHelp + \brief The QHelpContentWidget class provides a tree view for displaying help content model items. + \since 4.4 +*/ + +/*! + \fn void QHelpContentWidget::linkActivated(const QUrl &link) + + This signal is emitted when a content item is activated and + its associated \a link should be shown. +*/ + +QHelpContentWidget::QHelpContentWidget() + : QTreeView(0) +{ + header()->hide(); + setUniformRowHeights(true); + connect(this, SIGNAL(activated(QModelIndex)), + this, SLOT(showLink(QModelIndex))); +} + +/*! + Returns the index of the content item with the \a link. + An invalid index is returned if no such an item exists. +*/ +QModelIndex QHelpContentWidget::indexOf(const QUrl &link) +{ + QHelpContentModel *contentModel = + qobject_cast(model()); + if (!contentModel || link.scheme() != QLatin1String("qthelp")) + return QModelIndex(); + + m_syncIndex = QModelIndex(); + for (int i=0; irowCount(); ++i) { + QHelpContentItem *itm = + contentModel->contentItemAt(contentModel->index(i, 0)); + if (itm && itm->url().host() == link.host()) { + QString path = link.path(); + if (path.startsWith(QLatin1Char('/'))) + path = path.mid(1); + if (searchContentItem(contentModel, contentModel->index(i, 0), path)) { + return m_syncIndex; + } + } + } + return QModelIndex(); +} + +bool QHelpContentWidget::searchContentItem(QHelpContentModel *model, + const QModelIndex &parent, const QString &path) +{ + QHelpContentItem *parentItem = model->contentItemAt(parent); + if (!parentItem) + return false; + + if (QDir::cleanPath(parentItem->url().path()) == path) { + m_syncIndex = parent; + return true; + } + + for (int i=0; ichildCount(); ++i) { + if (searchContentItem(model, model->index(i, 0, parent), path)) + return true; + } + return false; +} + +void QHelpContentWidget::showLink(const QModelIndex &index) +{ + QHelpContentModel *contentModel = qobject_cast(model()); + if (!contentModel) + return; + + QHelpContentItem *item = contentModel->contentItemAt(index); + if (!item) + return; + QUrl url = item->url(); + if (url.isValid()) + emit linkActivated(url); +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/qhelpcontentwidget.h b/src/assistant/lib/qhelpcontentwidget.h new file mode 100644 index 000000000..0e7567e20 --- /dev/null +++ b/src/assistant/lib/qhelpcontentwidget.h @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPCONTENTWIDGET_H +#define QHELPCONTENTWIDGET_H + +#include + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +class QHelpEnginePrivate; +class QHelpDBReader; +class QHelpContentItemPrivate; +class QHelpContentModelPrivate; +class QHelpEngine; +class QHelpContentProvider; + +class QHELP_EXPORT QHelpContentItem +{ +public: + ~QHelpContentItem(); + + QHelpContentItem *child(int row) const; + int childCount() const; + QString title() const; + QUrl url() const; + int row() const; + QHelpContentItem *parent() const; + int childPosition(QHelpContentItem *child) const; + +private: + QHelpContentItem(const QString &name, const QString &link, + QHelpDBReader *reader, QHelpContentItem *parent = 0); + void appendChild(QHelpContentItem *child); + + QHelpContentItemPrivate *d; + friend class QHelpContentProvider; +}; + +class QHELP_EXPORT QHelpContentModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + ~QHelpContentModel(); + + void createContents(const QString &customFilterName); + QHelpContentItem *contentItemAt(const QModelIndex &index) const; + + QVariant data(const QModelIndex &index, int role) const; + QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &index) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + bool isCreatingContents() const; + +Q_SIGNALS: + void contentsCreationStarted(); + void contentsCreated(); + +private Q_SLOTS: + void insertContents(); + void invalidateContents(bool onShutDown = false); + +private: + QHelpContentModel(QHelpEnginePrivate *helpEngine); + QHelpContentModelPrivate *d; + friend class QHelpEnginePrivate; +}; + +class QHELP_EXPORT QHelpContentWidget : public QTreeView +{ + Q_OBJECT + +public: + QModelIndex indexOf(const QUrl &link); + +Q_SIGNALS: + void linkActivated(const QUrl &link); + +private Q_SLOTS: + void showLink(const QModelIndex &index); + +private: + bool searchContentItem(QHelpContentModel *model, + const QModelIndex &parent, const QString &path); + QModelIndex m_syncIndex; + +private: + QHelpContentWidget(); + friend class QHelpEngine; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif + diff --git a/src/assistant/lib/qhelpdatainterface.cpp b/src/assistant/lib/qhelpdatainterface.cpp new file mode 100644 index 000000000..d3f07c756 --- /dev/null +++ b/src/assistant/lib/qhelpdatainterface.cpp @@ -0,0 +1,273 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpdatainterface_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \internal + \class QHelpDataContentItem + \since 4.4 + \brief The QHelpDataContentItem class provides an item which represents + a topic or section of the contents. + + Every item holds several pieces of information, most notably the title + which can later be displayed in a contents overview. The reference is used + to store a relative file link to the corresponding section in the + documentation. +*/ + +/*! + Constructs a new content item with \a parent as parent item. + The constucted item has the title \a title and links to the + location specified by \a reference. +*/ +QHelpDataContentItem::QHelpDataContentItem(QHelpDataContentItem *parent, + const QString &title, const QString &reference) + : m_title(title), m_reference(reference) +{ + if (parent) + parent->m_children.append(this); +} + +/*! + Destructs the item and its children. +*/ +QHelpDataContentItem::~QHelpDataContentItem() +{ + qDeleteAll(m_children); +} + +/*! + Returns the title of the item. +*/ +QString QHelpDataContentItem::title() const +{ + return m_title; +} + +/*! + Returns the file reference of the item. +*/ +QString QHelpDataContentItem::reference() const +{ + return m_reference; +} + +/*! + Returns a list of all its child items. +*/ +QList QHelpDataContentItem::children() const +{ + return m_children; +} + +bool QHelpDataIndexItem::operator==(const QHelpDataIndexItem & other) const +{ + return (other.name == name) + && (other.reference == reference); +} + + + +/*! + \internal + \class QHelpDataFilterSection + \since 4.4 +*/ + +/*! + Constructs a help data filter section. +*/ +QHelpDataFilterSection::QHelpDataFilterSection() +{ + d = new QHelpDataFilterSectionData(); +} + +/*! + Adds the filter attribute \a filter to the filter attributes of + this section. +*/ +void QHelpDataFilterSection::addFilterAttribute(const QString &filter) +{ + d->filterAttributes.append(filter); +} + +/*! + Returns a list of all filter attributes defined for this section. +*/ +QStringList QHelpDataFilterSection::filterAttributes() const +{ + return d->filterAttributes; +} + +/*! + Adds the index item \a index to the list of indices. +*/ +void QHelpDataFilterSection::addIndex(const QHelpDataIndexItem &index) +{ + d->indices.append(index); +} + +/*! + Sets the filter sections list of indices to \a indices. +*/ +void QHelpDataFilterSection::setIndices(const QList &indices) +{ + d->indices = indices; +} + +/*! + Returns the list of indices. +*/ +QList QHelpDataFilterSection::indices() const +{ + return d->indices; +} + +/*! + Adds the top level content item \a content to the filter section. +*/ +void QHelpDataFilterSection::addContent(QHelpDataContentItem *content) +{ + d->contents.append(content); +} + +/*! + Sets the list of top level content items of the filter section to + \a contents. +*/ +void QHelpDataFilterSection::setContents(const QList &contents) +{ + qDeleteAll(d->contents); + d->contents = contents; +} + +/*! + Returns a list of top level content items. +*/ +QList QHelpDataFilterSection::contents() const +{ + return d->contents; +} + +/*! + Adds the file \a file to the filter section. +*/ +void QHelpDataFilterSection::addFile(const QString &file) +{ + d->files.append(file); +} + +/*! + Set the list of files to \a files. +*/ +void QHelpDataFilterSection::setFiles(const QStringList &files) +{ + d->files = files; +} + +/*! + Returns the list of files. +*/ +QStringList QHelpDataFilterSection::files() const +{ + return d->files; +} + +/*! + \internal + \class QHelpDataInterface + \since 4.4 +*/ + +/*! + \fn QHelpDataInterface::QHelpDataInterface() + + Constructs a new help data interface. +*/ + +/*! + \fn QHelpDataInterface::~QHelpDataInterface() + + Destroys the help data interface. +*/ + +/*! + \fn QString QHelpDataInterface::namespaceName() const = 0 + + Returns the namespace name of the help data set. +*/ + +/*! + \fn QString QHelpDataInterface::virtualFolder() const = 0 + + Returns the virtual folder of the help data set. +*/ + +/*! + \fn QList QHelpDataInterface::customFilters () const = 0 + + Returns a list of custom filters. Defining custom filters is optional. +*/ + +/*! + \fn QList QHelpDataInterface::filterSections() const = 0 + + Returns a list of filter sections. +*/ + +/*! + \fn QMap QHelpDataInterface::metaData() const = 0 + + Returns a map of meta data. A meta data item can hold almost any data + and is identified by its name. +*/ + +/*! + \fn QString QHelpDataInterface::rootPath() const = 0 + + Returns the root file path of the documentation data. All referenced file + path or links of content items are relative to this path. +*/ + +QT_END_NAMESPACE diff --git a/src/assistant/lib/qhelpdatainterface_p.h b/src/assistant/lib/qhelpdatainterface_p.h new file mode 100644 index 000000000..886d68650 --- /dev/null +++ b/src/assistant/lib/qhelpdatainterface_p.h @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPDATAINTERFACE_H +#define QHELPDATAINTERFACE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhelp_global.h" + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QHELP_EXPORT QHelpDataContentItem +{ +public: + QHelpDataContentItem(QHelpDataContentItem *parent, const QString &title, + const QString &reference); + ~QHelpDataContentItem(); + + QString title() const; + QString reference() const; + QList children() const; + +private: + QString m_title; + QString m_reference; + QList m_children; +}; + +struct QHELP_EXPORT QHelpDataIndexItem { + QHelpDataIndexItem() {} + QHelpDataIndexItem(const QString &n, const QString &id, const QString &r) + : name(n), identifier(id), reference(r) {} + + QString name; + QString identifier; + QString reference; + + bool operator==(const QHelpDataIndexItem & other) const; +}; + +class QHelpDataFilterSectionData : public QSharedData +{ +public: + ~QHelpDataFilterSectionData() + { + qDeleteAll(contents); + } + + QStringList filterAttributes; + QList indices; + QList contents; + QStringList files; +}; + +class QHELP_EXPORT QHelpDataFilterSection +{ +public: + QHelpDataFilterSection(); + + void addFilterAttribute(const QString &filter); + QStringList filterAttributes() const; + + void addIndex(const QHelpDataIndexItem &index); + void setIndices(const QList &indices); + QList indices() const; + + void addContent(QHelpDataContentItem *content); + void setContents(const QList &contents); + QList contents() const; + + void addFile(const QString &file); + void setFiles(const QStringList &files); + QStringList files() const; + +private: + QSharedDataPointer d; +}; + +struct QHELP_EXPORT QHelpDataCustomFilter { + QStringList filterAttributes; + QString name; +}; + +class QHELP_EXPORT QHelpDataInterface +{ +public: + QHelpDataInterface() {} + virtual ~QHelpDataInterface() {} + + virtual QString namespaceName() const = 0; + virtual QString virtualFolder() const = 0; + virtual QList customFilters() const = 0; + virtual QList filterSections() const = 0; + virtual QMap metaData() const = 0; + virtual QString rootPath() const = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QHELPDATAINTERFACE_H diff --git a/src/assistant/lib/qhelpdbreader.cpp b/src/assistant/lib/qhelpdbreader.cpp new file mode 100644 index 000000000..c4735f8b8 --- /dev/null +++ b/src/assistant/lib/qhelpdbreader.cpp @@ -0,0 +1,583 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpdbreader_p.h" +#include "qhelp_global.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +QHelpDBReader::QHelpDBReader(const QString &dbName) + : QObject(0) +{ + initObject(dbName, + QHelpGlobal::uniquifyConnectionName(QLatin1String("QHelpDBReader"), + this)); +} + +QHelpDBReader::QHelpDBReader(const QString &dbName, const QString &uniqueId, + QObject *parent) + : QObject(parent) +{ + initObject(dbName, uniqueId); +} + +void QHelpDBReader::initObject(const QString &dbName, const QString &uniqueId) +{ + m_dbName = dbName; + m_uniqueId = uniqueId; + m_initDone = false; + m_query = 0; + m_useAttributesCache = false; +} + +QHelpDBReader::~QHelpDBReader() +{ + if (m_initDone) { + delete m_query; + QSqlDatabase::removeDatabase(m_uniqueId); + } +} + +bool QHelpDBReader::init() +{ + if (m_initDone) + return true; + + if (!QFile::exists(m_dbName)) + return false; + + QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), m_uniqueId); + db.setDatabaseName(m_dbName); + if (!db.open()) { + /*: The placeholders are: %1 - The name of the database which cannot be opened + %2 - The unique id for the connection + %3 - The actual error string */ + m_error = tr("Cannot open database '%1' '%2': %3").arg(m_dbName, m_uniqueId, db.lastError().text()); + QSqlDatabase::removeDatabase(m_uniqueId); + return false; + } + + m_initDone = true; + m_query = new QSqlQuery(db); + + return true; +} + +QString QHelpDBReader::databaseName() const +{ + return m_dbName; +} + +QString QHelpDBReader::errorMessage() const +{ + return m_error; +} + +QString QHelpDBReader::namespaceName() const +{ + if (!m_namespace.isEmpty()) + return m_namespace; + if (m_query) { + m_query->exec(QLatin1String("SELECT Name FROM NamespaceTable")); + if (m_query->next()) + m_namespace = m_query->value(0).toString(); + } + return m_namespace; +} + +QString QHelpDBReader::virtualFolder() const +{ + if (m_query) { + m_query->exec(QLatin1String("SELECT Name FROM FolderTable WHERE Id=1")); + if (m_query->next()) + return m_query->value(0).toString(); + } + return QString(); +} + +QList QHelpDBReader::filterAttributeSets() const +{ + QList result; + if (m_query) { + m_query->exec(QLatin1String("SELECT a.Id, b.Name FROM FileAttributeSetTable a, " + "FilterAttributeTable b WHERE a.FilterAttributeId=b.Id ORDER BY a.Id")); + int oldId = -1; + while (m_query->next()) { + int id = m_query->value(0).toInt(); + if (id != oldId) { + result.append(QStringList()); + oldId = id; + } + result.last().append(m_query->value(1).toString()); + } + } + return result; +} + +bool QHelpDBReader::fileExists(const QString &virtualFolder, + const QString &filePath, + const QStringList &filterAttributes) const +{ + if (virtualFolder.isEmpty() || filePath.isEmpty() || !m_query) + return false; + +//SELECT COUNT(a.Name) FROM FileNameTable a, FolderTable b, FileFilterTable c, FilterAttributeTable d WHERE a.FolderId=b.Id AND b.Name='qtdoc' AND a.Name='qstring.html' AND a.FileId=c.FileId AND c.FilterAttributeId=d.Id AND d.Name='qtrefdoc' + + QString query; + namespaceName(); + if (filterAttributes.isEmpty()) { + query = QString(QLatin1String("SELECT COUNT(a.Name) FROM FileNameTable a, FolderTable b " + "WHERE a.FolderId=b.Id AND b.Name=\'%1\' AND a.Name=\'%2\'")).arg(quote(virtualFolder)).arg(quote(filePath)); + } else { + query = QString(QLatin1String("SELECT COUNT(a.Name) FROM FileNameTable a, FolderTable b, " + "FileFilterTable c, FilterAttributeTable d WHERE a.FolderId=b.Id " + "AND b.Name=\'%1\' AND a.Name=\'%2\' AND a.FileId=c.FileId AND " + "c.FilterAttributeId=d.Id AND d.Name=\'%3\'")) + .arg(quote(virtualFolder)).arg(quote(filePath)) + .arg(quote(filterAttributes.first())); + for (int i=1; iexec(query); + if (m_query->next() && m_query->isValid() && m_query->value(0).toInt()) + return true; + return false; +} + +QByteArray QHelpDBReader::fileData(const QString &virtualFolder, + const QString &filePath) const +{ + QByteArray ba; + if (virtualFolder.isEmpty() || filePath.isEmpty() || !m_query) + return ba; + + namespaceName(); + m_query->prepare(QLatin1String("SELECT a.Data FROM FileDataTable a, FileNameTable b, FolderTable c, " + "NamespaceTable d WHERE a.Id=b.FileId AND (b.Name=? OR b.Name=?) AND b.FolderId=c.Id " + "AND c.Name=? AND c.NamespaceId=d.Id AND d.Name=?")); + m_query->bindValue(0, filePath); + m_query->bindValue(1, QString(QLatin1String("./") + filePath)); + m_query->bindValue(2, virtualFolder); + m_query->bindValue(3, m_namespace); + m_query->exec(); + if (m_query->next() && m_query->isValid()) + ba = qUncompress(m_query->value(0).toByteArray()); + return ba; +} + +QStringList QHelpDBReader::customFilters() const +{ + QStringList lst; + if (m_query) { + m_query->exec(QLatin1String("SELECT Name FROM FilterNameTable")); + while (m_query->next()) + lst.append(m_query->value(0).toString()); + } + return lst; +} + +QStringList QHelpDBReader::filterAttributes(const QString &filterName) const +{ + QStringList lst; + if (m_query) { + if (filterName.isEmpty()) { + m_query->prepare(QLatin1String("SELECT Name FROM FilterAttributeTable")); + } else { + m_query->prepare(QLatin1String("SELECT a.Name FROM FilterAttributeTable a, " + "FilterTable b, FilterNameTable c WHERE c.Name=? " + "AND c.Id=b.NameId AND b.FilterAttributeId=a.Id")); + m_query->bindValue(0, filterName); + } + m_query->exec(); + while (m_query->next()) + lst.append(m_query->value(0).toString()); + } + return lst; +} + +QStringList QHelpDBReader::indicesForFilter(const QStringList &filterAttributes) const +{ + QStringList indices; + if (!m_query) + return indices; + + //SELECT DISTINCT a.Name FROM IndexTable a, IndexFilterTable b, FilterAttributeTable c WHERE a.Id=b.IndexId AND b.FilterAttributeId=c.Id AND c.Name in ('4.2.3', 'qt') + + QString query; + if (filterAttributes.isEmpty()) { + query = QLatin1String("SELECT DISTINCT Name FROM IndexTable"); + } else { + query = QString(QLatin1String("SELECT DISTINCT a.Name FROM IndexTable a, " + "IndexFilterTable b, FilterAttributeTable c WHERE a.Id=b.IndexId " + "AND b.FilterAttributeId=c.Id AND c.Name='%1'")).arg(quote(filterAttributes.first())); + for (int i=1; iexec(query); + while (m_query->next()) { + if (!m_query->value(0).toString().isEmpty()) + indices.append(m_query->value(0).toString()); + } + return indices; +} + +void QHelpDBReader::linksForKeyword(const QString &keyword, const QStringList &filterAttributes, + QMap &linkMap) const +{ + if (!m_query) + return; + + QString query; + if (filterAttributes.isEmpty()) { + query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor " + "FROM IndexTable a, FileNameTable d, " + "FolderTable e, NamespaceTable f WHERE " + "a.FileId=d.FileId AND d.FolderId=e.Id AND a.NamespaceId=f.Id " + "AND a.Name='%1'")).arg(quote(keyword)); + } else if (m_useAttributesCache) { + query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor, a.Id " + "FROM IndexTable a, " + "FileNameTable d, FolderTable e, NamespaceTable f WHERE " + "a.FileId=d.FileId AND d.FolderId=e.Id " + "AND a.NamespaceId=f.Id AND a.Name='%1'")) + .arg(quote(keyword)); + m_query->exec(query); + while (m_query->next()) { + if (m_indicesCache.contains(m_query->value(5).toInt())) { + linkMap.insertMulti(m_query->value(0).toString(), buildQUrl(m_query->value(1).toString(), + m_query->value(2).toString(), m_query->value(3).toString(), + m_query->value(4).toString())); + } + } + return; + } else { + query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor " + "FROM IndexTable a, IndexFilterTable b, FilterAttributeTable c, " + "FileNameTable d, FolderTable e, NamespaceTable f " + "WHERE a.FileId=d.FileId AND d.FolderId=e.Id " + "AND a.NamespaceId=f.Id AND b.IndexId=a.Id AND b.FilterAttributeId=c.Id " + "AND a.Name='%1' AND c.Name='%2'")).arg(quote(keyword)) + .arg(quote(filterAttributes.first())); + for (int i=1; iexec(query); + while (m_query->next()) { + title = m_query->value(0).toString(); + if (title.isEmpty()) // generate a title + corresponding path + title = keyword + QLatin1String(" : ") + m_query->value(3).toString(); + linkMap.insertMulti(title, buildQUrl(m_query->value(1).toString(), + m_query->value(2).toString(), m_query->value(3).toString(), + m_query->value(4).toString())); + } +} + +void QHelpDBReader::linksForIdentifier(const QString &id, + const QStringList &filterAttributes, + QMap &linkMap) const +{ + if (!m_query) + return; + + QString query; + if (filterAttributes.isEmpty()) { + query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor " + "FROM IndexTable a, FileNameTable d, FolderTable e, " + "NamespaceTable f WHERE a.FileId=d.FileId AND " + "d.FolderId=e.Id AND a.NamespaceId=f.Id AND a.Identifier='%1'")) + .arg(quote(id)); + } else if (m_useAttributesCache) { + query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor, a.Id " + "FROM IndexTable a," + "FileNameTable d, FolderTable e, NamespaceTable f WHERE " + "a.FileId=d.FileId AND d.FolderId=e.Id " + "AND a.NamespaceId=f.Id AND a.Identifier='%1'")) + .arg(quote(id)); + m_query->exec(query); + while (m_query->next()) { + if (m_indicesCache.contains(m_query->value(5).toInt())) { + linkMap.insertMulti(m_query->value(0).toString(), buildQUrl(m_query->value(1).toString(), + m_query->value(2).toString(), m_query->value(3).toString(), + m_query->value(4).toString())); + } + } + return; + } else { + query = QString(QLatin1String("SELECT d.Title, f.Name, e.Name, d.Name, a.Anchor " + "FROM IndexTable a, IndexFilterTable b, FilterAttributeTable c, " + "FileNameTable d, FolderTable e, NamespaceTable f " + "WHERE a.FileId=d.FileId AND d.FolderId=e.Id " + "AND a.NamespaceId=f.Id AND b.IndexId=a.Id AND b.FilterAttributeId=c.Id " + "AND a.Identifier='%1' AND c.Name='%2'")).arg(quote(id)) + .arg(quote(filterAttributes.first())); + for (int i=0; iexec(query); + while (m_query->next()) { + linkMap.insertMulti(m_query->value(0).toString(), buildQUrl(m_query->value(1).toString(), + m_query->value(2).toString(), m_query->value(3).toString(), + m_query->value(4).toString())); + } +} + +QUrl QHelpDBReader::buildQUrl(const QString &ns, const QString &folder, + const QString &relFileName, const QString &anchor) const +{ + QUrl url; + url.setScheme(QLatin1String("qthelp")); + url.setAuthority(ns); + url.setPath(folder + QLatin1Char('/') + relFileName); + url.setFragment(anchor); + return url; +} + +QList QHelpDBReader::contentsForFilter(const QStringList &filterAttributes) const +{ + QList contents; + if (!m_query) + return contents; + + //SELECT DISTINCT a.Data FROM ContentsTable a, ContentsFilterTable b, FilterAttributeTable c WHERE a.Id=b.ContentsId AND b.FilterAttributeId=c.Id AND c.Name='qt' INTERSECT SELECT DISTINCT a.Data FROM ContentsTable a, ContentsFilterTable b, FilterAttributeTable c WHERE a.Id=b.ContentsId AND b.FilterAttributeId=c.Id AND c.Name='3.3.8'; + + QString query; + if (filterAttributes.isEmpty()) { + query = QLatin1String("SELECT Data from ContentsTable"); + } else { + query = QString(QLatin1String("SELECT a.Data FROM ContentsTable a, " + "ContentsFilterTable b, FilterAttributeTable c " + "WHERE a.Id=b.ContentsId AND b.FilterAttributeId=c.Id " + "AND c.Name='%1'")).arg(quote(filterAttributes.first())); + for (int i=1; iexec(query); + while (m_query->next()) { + contents.append(m_query->value(0).toByteArray()); + } + return contents; +} + +QUrl QHelpDBReader::urlOfPath(const QString &relativePath) const +{ + QUrl url; + if (!m_query) + return url; + + m_query->exec(QLatin1String("SELECT a.Name, b.Name FROM NamespaceTable a, " + "FolderTable b WHERE a.id=b.NamespaceId and a.Id=1")); + if (m_query->next()) { + QString rp = relativePath; + QString anchor; + int i = rp.indexOf(QLatin1Char('#')); + if (i > -1) { + rp = relativePath.left(i); + anchor = relativePath.mid(i+1); + } + url = buildQUrl(m_query->value(0).toString(), + m_query->value(1).toString(), rp, anchor); + } + return url; +} + +QStringList QHelpDBReader::files(const QStringList &filterAttributes, + const QString &extensionFilter) const +{ + QStringList lst; + if (!m_query) + return lst; + + QString query; + QString extension; + if (!extensionFilter.isEmpty()) + extension = QString(QLatin1String("AND b.Name like \'%.%1\'")).arg(extensionFilter); + + if (filterAttributes.isEmpty()) { + query = QString(QLatin1String("SELECT a.Name, b.Name FROM FolderTable a, " + "FileNameTable b WHERE b.FolderId=a.Id %1")) + .arg(extension); + } else { + query = QString(QLatin1String("SELECT a.Name, b.Name FROM FolderTable a, " + "FileNameTable b, FileFilterTable c, FilterAttributeTable d " + "WHERE b.FolderId=a.Id AND b.FileId=c.FileId " + "AND c.FilterAttributeId=d.Id AND d.Name=\'%1\' %2")) + .arg(quote(filterAttributes.first())).arg(extension); + for (int i=1; iexec(query); + while (m_query->next()) { + lst.append(m_query->value(0).toString() + QLatin1Char('/') + + m_query->value(1).toString()); + } + + return lst; +} + +QVariant QHelpDBReader::metaData(const QString &name) const +{ + QVariant v; + if (!m_query) + return v; + + m_query->prepare(QLatin1String("SELECT COUNT(Value), Value FROM MetaDataTable " + "WHERE Name=?")); + m_query->bindValue(0, name); + if (m_query->exec() && m_query->next() + && m_query->value(0).toInt() == 1) + v = m_query->value(1); + return v; +} + +QString QHelpDBReader::mergeList(const QStringList &list) const +{ + QString str; + foreach (const QString &s, list) + str.append(QLatin1Char('\'') + quote(s) + QLatin1String("\', ")); + if (str.endsWith(QLatin1String(", "))) + str = str.left(str.length()-2); + return str; +} + +QString QHelpDBReader::quote(const QString &string) const +{ + QString s = string; + s.replace(QLatin1Char('\''), QLatin1String("\'\'")); + return s; +} + +QSet QHelpDBReader::indexIds(const QStringList &attributes) const +{ + QSet ids; + + if (attributes.isEmpty()) + return ids; + + QString query = QString(QLatin1String("SELECT a.IndexId FROM IndexFilterTable a, " + "FilterAttributeTable b WHERE a.FilterAttributeId=b.Id " + "AND b.Name='%1'")).arg(attributes.first()); + for (int i=0; iexec(query)) + return ids; + + while (m_query->next()) + ids.insert(m_query->value(0).toInt()); + + return ids; +} + +bool QHelpDBReader::createAttributesCache(const QStringList &attributes, + const QSet &indexIds) +{ + m_useAttributesCache = false; + + if (attributes.count() < 2) { + m_viewAttributes.clear(); + return true; + } + + bool needUpdate = !m_viewAttributes.count(); + + foreach (const QString &s, attributes) + m_viewAttributes.remove(s); + + if (m_viewAttributes.count() || needUpdate) { + m_viewAttributes.clear(); + m_indicesCache = indexIds; + } + foreach (const QString &s, attributes) + m_viewAttributes.insert(s); + m_useAttributesCache = true; + return true; +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/qhelpdbreader_p.h b/src/assistant/lib/qhelpdbreader_p.h new file mode 100644 index 000000000..5fdf2e90b --- /dev/null +++ b/src/assistant/lib/qhelpdbreader_p.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPDBREADER_H +#define QHELPDBREADER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QSqlQuery; + +class QHelpDBReader : public QObject +{ + Q_OBJECT + +public: + QHelpDBReader(const QString &dbName); + QHelpDBReader(const QString &dbName, const QString &uniqueId, + QObject *parent); + ~QHelpDBReader(); + + bool init(); + + QString errorMessage() const; + + QString databaseName() const; + QString namespaceName() const; + QString virtualFolder() const; + QList filterAttributeSets() const; + QStringList files(const QStringList &filterAttributes, + const QString &extensionFilter = QString()) const; + bool fileExists(const QString &virtualFolder, const QString &filePath, + const QStringList &filterAttributes = QStringList()) const; + QByteArray fileData(const QString &virtualFolder, + const QString &filePath) const; + + QStringList customFilters() const; + QStringList filterAttributes(const QString &filterName = QString()) const; + QStringList indicesForFilter(const QStringList &filterAttributes) const; + void linksForKeyword(const QString &keyword, const QStringList &filterAttributes, + QMap &linkMap) const; + + void linksForIdentifier(const QString &id, const QStringList &filterAttributes, + QMap &linkMap) const; + + QList contentsForFilter(const QStringList &filterAttributes) const; + QUrl urlOfPath(const QString &relativePath) const; + + QSet indexIds(const QStringList &attributes) const; + bool createAttributesCache(const QStringList &attributes, + const QSet &indexIds); + QVariant metaData(const QString &name) const; + +private: + void initObject(const QString &dbName, const QString &uniqueId); + QUrl buildQUrl(const QString &ns, const QString &folder, + const QString &relFileName, const QString &anchor) const; + QString mergeList(const QStringList &list) const; + QString quote(const QString &string) const; + + bool m_initDone; + QString m_dbName; + QString m_uniqueId; + QString m_error; + QSqlQuery *m_query; + mutable QString m_namespace; + QSet m_viewAttributes; + bool m_useAttributesCache; + QSet m_indicesCache; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/assistant/lib/qhelpengine.cpp b/src/assistant/lib/qhelpengine.cpp new file mode 100644 index 000000000..f11b52a9c --- /dev/null +++ b/src/assistant/lib/qhelpengine.cpp @@ -0,0 +1,213 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpengine.h" +#include "qhelpengine_p.h" +#include "qhelpdbreader_p.h" +#include "qhelpcontentwidget.h" +#include "qhelpindexwidget.h" +#include "qhelpsearchengine.h" +#include "qhelpcollectionhandler_p.h" + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +QHelpEnginePrivate::QHelpEnginePrivate() + : QHelpEngineCorePrivate() + , contentModel(0) + , contentWidget(0) + , indexModel(0) + , indexWidget(0) + , searchEngine(0) +{ +} + +QHelpEnginePrivate::~QHelpEnginePrivate() +{ +} + +void QHelpEnginePrivate::init(const QString &collectionFile, + QHelpEngineCore *helpEngineCore) +{ + QHelpEngineCorePrivate::init(collectionFile, helpEngineCore); + + if (!contentModel) + contentModel = new QHelpContentModel(this); + if (!indexModel) + indexModel = new QHelpIndexModel(this); + + connect(helpEngineCore, SIGNAL(setupFinished()), this, + SLOT(applyCurrentFilter())); + connect(helpEngineCore, SIGNAL(currentFilterChanged(QString)), this, + SLOT(applyCurrentFilter())); +} + +void QHelpEnginePrivate::applyCurrentFilter() +{ + if (!error.isEmpty()) + return; + contentModel->createContents(currentFilter); + indexModel->createIndex(currentFilter); +} + +void QHelpEnginePrivate::setContentsWidgetBusy() +{ + contentWidget->setCursor(Qt::WaitCursor); +} + +void QHelpEnginePrivate::unsetContentsWidgetBusy() +{ + contentWidget->unsetCursor(); +} + +void QHelpEnginePrivate::setIndexWidgetBusy() +{ + indexWidget->setCursor(Qt::WaitCursor); +} + +void QHelpEnginePrivate::unsetIndexWidgetBusy() +{ + indexWidget->unsetCursor(); +} + +void QHelpEnginePrivate::stopDataCollection() +{ + contentModel->invalidateContents(true); + indexModel->invalidateIndex(true); +} + + + +/*! + \class QHelpEngine + \since 4.4 + \inmodule QtHelp + \brief The QHelpEngine class provides access to contents and + indices of the help engine. + + +*/ + +/*! + Constructs a new help engine with the given \a parent. The help + engine uses the information stored in the \a collectionFile for + providing help. If the collection file does not already exist, + it will be created. +*/ +QHelpEngine::QHelpEngine(const QString &collectionFile, QObject *parent) + : QHelpEngineCore(d = new QHelpEnginePrivate(), parent) +{ + d->init(collectionFile, this); +} + +/*! + Destroys the help engine object. +*/ +QHelpEngine::~QHelpEngine() +{ + d->stopDataCollection(); +} + +/*! + Returns the content model. +*/ +QHelpContentModel *QHelpEngine::contentModel() const +{ + return d->contentModel; +} + +/*! + Returns the index model. +*/ +QHelpIndexModel *QHelpEngine::indexModel() const +{ + return d->indexModel; +} + +/*! + Returns the content widget. +*/ +QHelpContentWidget *QHelpEngine::contentWidget() +{ + if (!d->contentWidget) { + d->contentWidget = new QHelpContentWidget(); + d->contentWidget->setModel(d->contentModel); + connect(d->contentModel, SIGNAL(contentsCreationStarted()), + d, SLOT(setContentsWidgetBusy())); + connect(d->contentModel, SIGNAL(contentsCreated()), + d, SLOT(unsetContentsWidgetBusy())); + } + return d->contentWidget; +} + +/*! + Returns the index widget. +*/ +QHelpIndexWidget *QHelpEngine::indexWidget() +{ + if (!d->indexWidget) { + d->indexWidget = new QHelpIndexWidget(); + d->indexWidget->setModel(d->indexModel); + connect(d->indexModel, SIGNAL(indexCreationStarted()), + d, SLOT(setIndexWidgetBusy())); + connect(d->indexModel, SIGNAL(indexCreated()), + d, SLOT(unsetIndexWidgetBusy())); + } + return d->indexWidget; +} + +/*! + Returns the default search engine. +*/ +QHelpSearchEngine* QHelpEngine::searchEngine() +{ + if (!d->searchEngine) + d->searchEngine = new QHelpSearchEngine(this, this); + return d->searchEngine; +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/qhelpengine.h b/src/assistant/lib/qhelpengine.h new file mode 100644 index 000000000..cc0bca299 --- /dev/null +++ b/src/assistant/lib/qhelpengine.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPENGINE_H +#define QHELPENGINE_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +class QHelpContentModel; +class QHelpContentWidget; +class QHelpIndexModel; +class QHelpIndexWidget; +class QHelpEnginePrivate; +class QHelpSearchEngine; + +class QHELP_EXPORT QHelpEngine : public QHelpEngineCore +{ + Q_OBJECT + +public: + explicit QHelpEngine(const QString &collectionFile, QObject *parent = 0); + ~QHelpEngine(); + + QHelpContentModel *contentModel() const; + QHelpIndexModel *indexModel() const; + + QHelpContentWidget *contentWidget(); + QHelpIndexWidget *indexWidget(); + + QHelpSearchEngine *searchEngine(); + +private: + QHelpEnginePrivate *d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/assistant/lib/qhelpengine_p.h b/src/assistant/lib/qhelpengine_p.h new file mode 100644 index 000000000..5a7c30184 --- /dev/null +++ b/src/assistant/lib/qhelpengine_p.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPENGINE_P_H +#define QHELPENGINE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QSqlQuery; + +class QHelpEngineCore; +class QHelpDBReader; +class QHelpContentModel; +class QHelpContentWidget; +class QHelpIndexModel; +class QHelpIndexWidget; +class QHelpSearchEngine; +class QHelpCollectionHandler; + +class QHelpEngineCorePrivate : public QObject +{ + Q_OBJECT + +public: + QHelpEngineCorePrivate(); + virtual ~QHelpEngineCorePrivate(); + + virtual void init(const QString &collectionFile, + QHelpEngineCore *helpEngineCore); + + void clearMaps(); + bool setup(); + + QMap readerMap; + QMap fileNameReaderMap; + QMultiMap virtualFolderMap; + QStringList orderedFileNameList; + + QHelpCollectionHandler *collectionHandler; + QString currentFilter; + QString error; + bool needsSetup; + bool autoSaveFilter; + +protected: + QHelpEngineCore *q; + +private slots: + void errorReceived(const QString &msg); +}; + + +class QHelpEnginePrivate : public QHelpEngineCorePrivate +{ + Q_OBJECT + +public: + QHelpEnginePrivate(); + ~QHelpEnginePrivate(); + + void init(const QString &collectionFile, + QHelpEngineCore *helpEngineCore); + + QHelpContentModel *contentModel; + QHelpContentWidget *contentWidget; + + QHelpIndexModel *indexModel; + QHelpIndexWidget *indexWidget; + + QHelpSearchEngine *searchEngine; + + void stopDataCollection(); + + friend class QHelpContentProvider; + friend class QHelpContentModel; + friend class QHelpIndexProvider; + friend class QHelpIndexModel; + +public slots: + void setContentsWidgetBusy(); + void unsetContentsWidgetBusy(); + void setIndexWidgetBusy(); + void unsetIndexWidgetBusy(); + +private slots: + void applyCurrentFilter(); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/assistant/lib/qhelpenginecore.cpp b/src/assistant/lib/qhelpenginecore.cpp new file mode 100644 index 000000000..1fd22428d --- /dev/null +++ b/src/assistant/lib/qhelpenginecore.cpp @@ -0,0 +1,737 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpenginecore.h" +#include "qhelpengine_p.h" +#include "qhelpdbreader_p.h" +#include "qhelpcollectionhandler_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +QHelpEngineCorePrivate::QHelpEngineCorePrivate() +{ + QHelpGlobal::uniquifyConnectionName(QString(), this); + autoSaveFilter = true; +} + +void QHelpEngineCorePrivate::init(const QString &collectionFile, + QHelpEngineCore *helpEngineCore) +{ + q = helpEngineCore; + collectionHandler = new QHelpCollectionHandler(collectionFile, helpEngineCore); + connect(collectionHandler, SIGNAL(error(QString)), + this, SLOT(errorReceived(QString))); + needsSetup = true; +} + +QHelpEngineCorePrivate::~QHelpEngineCorePrivate() +{ + delete collectionHandler; + clearMaps(); +} + +void QHelpEngineCorePrivate::clearMaps() +{ + QMap::iterator it = readerMap.begin(); + while (it != readerMap.end()) { + delete it.value(); + ++it; + } + readerMap.clear(); + fileNameReaderMap.clear(); + virtualFolderMap.clear(); + orderedFileNameList.clear(); +} + +bool QHelpEngineCorePrivate::setup() +{ + error.clear(); + if (!needsSetup) + return true; + + needsSetup = false; + emit q->setupStarted(); + clearMaps(); + + if (!collectionHandler->openCollectionFile()) { + emit q->setupFinished(); + return false; + } + + const QHelpCollectionHandler::DocInfoList docList = + collectionHandler->registeredDocumentations(); + QFileInfo fi(collectionHandler->collectionFile()); + QString absFileName; + foreach(const QHelpCollectionHandler::DocInfo &info, docList) { + if (QDir::isAbsolutePath(info.fileName)) { + absFileName = info.fileName; + } else { + absFileName = QFileInfo(fi.absolutePath() + QDir::separator() + info.fileName) + .absoluteFilePath(); + } + QHelpDBReader *reader = new QHelpDBReader(absFileName, + QHelpGlobal::uniquifyConnectionName(info.fileName, this), this); + if (!reader->init()) { + emit q->warning(QHelpEngineCore::tr("Cannot open documentation file %1: %2!") + .arg(absFileName, reader->errorMessage())); + continue; + } + + readerMap.insert(info.namespaceName, reader); + fileNameReaderMap.insert(absFileName, reader); + virtualFolderMap.insert(info.folderName, reader); + orderedFileNameList.append(absFileName); + } + q->currentFilter(); + emit q->setupFinished(); + return true; +} + +void QHelpEngineCorePrivate::errorReceived(const QString &msg) +{ + error = msg; +} + + + +/*! + \class QHelpEngineCore + \since 4.4 + \inmodule QtHelp + \brief The QHelpEngineCore class provides the core functionality + of the help system. + + Before the help engine can be used, it must be initialized by + calling setupData(). At the beginning of the setup process the + signal setupStarted() is emitted. From this point on until + the signal setupFinished() is emitted, is the help data in an + undefined meaning unusable state. + + The core help engine can be used to perform different tasks. + By calling linksForIdentifier() the engine returns + urls specifying the file locations inside the help system. The + actual file data can then be retrived by calling fileData(). In + contrast to all other functions in this class, linksForIdentifier() + depends on the currently set custom filter. Depending on the filter, + the function may return different hits. + + Every help engine can contain any number of custom filters. A custom + filter is defined by a name and set of filter attributes and can be + added to the help engine by calling addCustomFilter(). Analogous, + it is removed by calling removeCustomFilter(). customFilters() returns + all defined filters. + + The help engine also offers the possibility to set and read values + in a persistant way comparable to ini files or Windows registry + entries. For more information see setValue() or value(). + + This class does not offer any GUI components or functionality for + indices or contents. If you need one of those use QHelpEngine + instead. + + When creating a custom help viewer the viewer can be + configured by writing a custom collection file which could contain various + keywords to be used to configure the help engine. These keywords and values + and their meaning can be found in the help information for + \l{assistant-custom-help-viewer.html#creating-a-custom-help-collection-file} + {creating a custom help collection file} for Assistant. +*/ + +/*! + \fn void QHelpEngineCore::setupStarted() + + This signal is emitted when setup is started. +*/ + +/*! + \fn void QHelpEngineCore::setupFinished() + + This signal is emitted when the setup is complete. +*/ + +/*! + \fn void QHelpEngineCore::currentFilterChanged(const QString &newFilter) + + This signal is emitted when the current filter is changed to + \a newFilter. +*/ + +/*! + \fn void QHelpEngineCore::warning(const QString &msg) + + This signal is emitted when a non critical error occurs. + The warning message is stored in \a msg. +*/ + +/*! + Constructs a new core help engine with a \a parent. The help engine + uses the information stored in the \a collectionFile to provide help. + If the collection file does not exist yet, it'll be created. +*/ +QHelpEngineCore::QHelpEngineCore(const QString &collectionFile, QObject *parent) + : QObject(parent) +{ + d = new QHelpEngineCorePrivate(); + d->init(collectionFile, this); +} + +/*! + \internal +*/ +QHelpEngineCore::QHelpEngineCore(QHelpEngineCorePrivate *helpEngineCorePrivate, + QObject *parent) + : QObject(parent) +{ + d = helpEngineCorePrivate; +} + +/*! + Destructs the help engine. +*/ +QHelpEngineCore::~QHelpEngineCore() +{ + delete d; +} + +/*! + \property QHelpEngineCore::collectionFile + \brief the absolute file name of the collection file currently used. + \since 4.5 + + Setting this property leaves the help engine in an invalid state. It is + important to invoke setupData() or any getter function in order to setup + the help engine again. +*/ +QString QHelpEngineCore::collectionFile() const +{ + return d->collectionHandler->collectionFile(); +} + +void QHelpEngineCore::setCollectionFile(const QString &fileName) +{ + if (fileName == collectionFile()) + return; + + if (d->collectionHandler) { + delete d->collectionHandler; + d->collectionHandler = 0; + d->clearMaps(); + } + d->init(fileName, this); + d->needsSetup = true; +} + +/*! + Sets up the help engine by processing the information found + in the collection file and returns true if successful; otherwise + returns false. + + By calling the function, the help + engine is forced to initialize itself immediately. Most of + the times, this function does not have to be called + explicitly because getter functions which depend on a correctly + set up help engine do that themselves. + + \note \c{qsqlite4.dll} needs to be deployed with the application as the + help system uses the sqlite driver when loading help collections. +*/ +bool QHelpEngineCore::setupData() +{ + d->needsSetup = true; + return d->setup(); +} + +/*! + Creates the file \a fileName and copies all contents from + the current collection file into the newly created file, + and returns true if successful; otherwise returns false. + + The copying process makes sure that file references to Qt + Collection files (\c{.qch}) files are updated accordingly. +*/ +bool QHelpEngineCore::copyCollectionFile(const QString &fileName) +{ + if (!d->setup()) + return false; + return d->collectionHandler->copyCollectionFile(fileName); +} + +/*! + Returns the namespace name defined for the Qt compressed help file (.qch) + specified by its \a documentationFileName. If the file is not valid, an + empty string is returned. + + \sa documentationFileName() +*/ +QString QHelpEngineCore::namespaceName(const QString &documentationFileName) +{ + QHelpDBReader reader(documentationFileName, + QHelpGlobal::uniquifyConnectionName(QLatin1String("GetNamespaceName"), + QThread::currentThread()), 0); + if (reader.init()) + return reader.namespaceName(); + return QString(); +} + +/*! + Registers the Qt compressed help file (.qch) contained in the file + \a documentationFileName. One compressed help file, uniquely + identified by its namespace can only be registered once. + True is returned if the registration was successful, otherwise + false. + + \sa unregisterDocumentation(), error() +*/ +bool QHelpEngineCore::registerDocumentation(const QString &documentationFileName) +{ + d->error.clear(); + d->needsSetup = true; + return d->collectionHandler->registerDocumentation(documentationFileName); +} + +/*! + Unregisters the Qt compressed help file (.qch) identified by its + \a namespaceName from the help collection. Returns true + on success, otherwise false. + + \sa registerDocumentation(), error() +*/ +bool QHelpEngineCore::unregisterDocumentation(const QString &namespaceName) +{ + d->error.clear(); + d->needsSetup = true; + return d->collectionHandler->unregisterDocumentation(namespaceName); +} + +/*! + Returns the absolute file name of the Qt compressed help file (.qch) + identified by the \a namespaceName. If there is no Qt compressed help file + with the specified namespace registered, an empty string is returned. + + \sa namespaceName() +*/ +QString QHelpEngineCore::documentationFileName(const QString &namespaceName) +{ + if (d->setup()) { + const QHelpCollectionHandler::DocInfoList docList = + d->collectionHandler->registeredDocumentations(); + foreach(const QHelpCollectionHandler::DocInfo &info, docList) { + if (info.namespaceName == namespaceName) { + if (QDir::isAbsolutePath(info.fileName)) + return QDir::cleanPath(info.fileName); + + QFileInfo fi(d->collectionHandler->collectionFile()); + fi.setFile(fi.absolutePath() + QDir::separator() + info.fileName); + return QDir::cleanPath(fi.absoluteFilePath()); + } + } + } + return QString(); +} + +/*! + Returns a list of all registered Qt compressed help files of the current collection file. + The returned names are the namespaces of the registered Qt compressed help files (.qch). +*/ +QStringList QHelpEngineCore::registeredDocumentations() const +{ + QStringList list; + if (!d->setup()) + return list; + const QHelpCollectionHandler::DocInfoList docList = d->collectionHandler->registeredDocumentations(); + foreach(const QHelpCollectionHandler::DocInfo &info, docList) { + list.append(info.namespaceName); + } + return list; +} + +/*! + Returns a list of custom filters. + + \sa addCustomFilter(), removeCustomFilter() +*/ +QStringList QHelpEngineCore::customFilters() const +{ + if (!d->setup()) + return QStringList(); + return d->collectionHandler->customFilters(); +} + +/*! + Adds the new custom filter \a filterName. The filter attributes + are specified by \a attributes. If the filter already exists, + its attribute set is replaced. The function returns true if + the operation succeeded, otherwise it returns false. + + \sa customFilters(), removeCustomFilter() +*/ +bool QHelpEngineCore::addCustomFilter(const QString &filterName, + const QStringList &attributes) +{ + d->error.clear(); + d->needsSetup = true; + return d->collectionHandler->addCustomFilter(filterName, + attributes); +} + +/*! + Returns true if the filter \a filterName was removed successfully, + otherwise false. + + \sa addCustomFilter(), customFilters() +*/ +bool QHelpEngineCore::removeCustomFilter(const QString &filterName) +{ + d->error.clear(); + d->needsSetup = true; + return d->collectionHandler->removeCustomFilter(filterName); +} + +/*! + Returns a list of all defined filter attributes. +*/ +QStringList QHelpEngineCore::filterAttributes() const +{ + if (!d->setup()) + return QStringList(); + return d->collectionHandler->filterAttributes(); +} + +/*! + Returns a list of filter attributes used by the custom + filter \a filterName. +*/ +QStringList QHelpEngineCore::filterAttributes(const QString &filterName) const +{ + if (!d->setup()) + return QStringList(); + return d->collectionHandler->filterAttributes(filterName); +} + +/*! + \property QHelpEngineCore::currentFilter + \brief the name of the custom filter currently applied. + \since 4.5 + + Setting this property will save the new custom filter permanently in the + help collection file. To set a custom filter without saving it + permanently, disable the auto save filter mode. + + \sa autoSaveFilter() +*/ +QString QHelpEngineCore::currentFilter() const +{ + if (!d->setup()) + return QString(); + + if (d->currentFilter.isEmpty()) { + QString filter = + d->collectionHandler->customValue(QLatin1String("CurrentFilter"), + QString()).toString(); + if (!filter.isEmpty() + && d->collectionHandler->customFilters().contains(filter)) + d->currentFilter = filter; + } + return d->currentFilter; +} + +void QHelpEngineCore::setCurrentFilter(const QString &filterName) +{ + if (!d->setup() || filterName == d->currentFilter) + return; + d->currentFilter = filterName; + if (d->autoSaveFilter) { + d->collectionHandler->setCustomValue(QLatin1String("CurrentFilter"), + d->currentFilter); + } + emit currentFilterChanged(d->currentFilter); +} + +/*! + Returns a list of filter attributes for the different filter sections + defined in the Qt compressed help file with the given namespace + \a namespaceName. +*/ +QList QHelpEngineCore::filterAttributeSets(const QString &namespaceName) const +{ + if (d->setup()) { + QHelpDBReader *reader = d->readerMap.value(namespaceName); + if (reader) + return reader->filterAttributeSets(); + } + return QList(); +} + +/*! + Returns a list of files contained in the Qt compressed help file \a + namespaceName. The files can be filtered by \a filterAttributes as + well as by their extension \a extensionFilter (e.g. 'html'). +*/ +QList QHelpEngineCore::files(const QString namespaceName, + const QStringList &filterAttributes, + const QString &extensionFilter) +{ + QList res; + if (!d->setup()) + return res; + QHelpDBReader *reader = d->readerMap.value(namespaceName); + if (!reader) { + d->error = tr("The specified namespace does not exist!"); + return res; + } + + QUrl url; + url.setScheme(QLatin1String("qthelp")); + url.setAuthority(namespaceName); + + const QStringList files = reader->files(filterAttributes, extensionFilter); + foreach (const QString &file, files) { + url.setPath(QLatin1String("/") + file); + res.append(url); + } + return res; +} + +/*! + Returns an invalid URL if the file \a url cannot be found. + If the file exists, either the same url is returned or a + different url if the file is located in a different namespace + which is merged via a common virtual folder. +*/ +QUrl QHelpEngineCore::findFile(const QUrl &url) const +{ + QUrl res; + if (!d->setup() || !url.isValid() || url.toString().count(QLatin1Char('/')) < 4 + || url.scheme() != QLatin1String("qthelp")) + return res; + + QString ns = url.authority(); + QString filePath = QDir::cleanPath(url.path()); + if (filePath.startsWith(QLatin1Char('/'))) + filePath = filePath.mid(1); + QString virtualFolder = filePath.mid(0, filePath.indexOf(QLatin1Char('/'), 1)); + filePath = filePath.mid(virtualFolder.length()+1); + + QHelpDBReader *defaultReader = 0; + if (d->readerMap.contains(ns)) { + defaultReader = d->readerMap.value(ns); + if (defaultReader->fileExists(virtualFolder, filePath)) + return url; + } + + QStringList filterAtts = filterAttributes(currentFilter()); + foreach (QHelpDBReader *reader, d->virtualFolderMap.values(virtualFolder)) { + if (reader == defaultReader) + continue; + if (reader->fileExists(virtualFolder, filePath, filterAtts)) { + res = url; + res.setAuthority(reader->namespaceName()); + return res; + } + } + + foreach (QHelpDBReader *reader, d->virtualFolderMap.values(virtualFolder)) { + if (reader == defaultReader) + continue; + if (reader->fileExists(virtualFolder, filePath)) { + res = url; + res.setAuthority(reader->namespaceName()); + break; + } + } + + return res; +} + +/*! + Returns the data of the file specified by \a url. If the + file does not exist, an empty QByteArray is returned. + + \sa findFile() +*/ +QByteArray QHelpEngineCore::fileData(const QUrl &url) const +{ + if (!d->setup() || !url.isValid() || url.toString().count(QLatin1Char('/')) < 4 + || url.scheme() != QLatin1String("qthelp")) + return QByteArray(); + + QString ns = url.authority(); + QString filePath = QDir::cleanPath(url.path()); + if (filePath.startsWith(QLatin1Char('/'))) + filePath = filePath.mid(1); + QString virtualFolder = filePath.mid(0, filePath.indexOf(QLatin1Char('/'), 1)); + filePath = filePath.mid(virtualFolder.length()+1); + + QByteArray ba; + QHelpDBReader *defaultReader = 0; + if (d->readerMap.contains(ns)) { + defaultReader = d->readerMap.value(ns); + ba = defaultReader->fileData(virtualFolder, filePath); + } + + if (ba.isEmpty()) { + foreach (QHelpDBReader *reader, d->virtualFolderMap.values(virtualFolder)) { + if (reader == defaultReader) + continue; + ba = reader->fileData(virtualFolder, filePath); + if (!ba.isEmpty()) + return ba; + } + } + return ba; +} + +/*! + Returns a map of hits found for the \a id. A hit contains the + title of the document and the url where the keyword is located. + The result depends on the current filter, meaning only the keywords + registered for the current filter will be returned. +*/ +QMap QHelpEngineCore::linksForIdentifier(const QString &id) const +{ + QMap linkMap; + if (!d->setup()) + return linkMap; + + QStringList atts = filterAttributes(d->currentFilter); + foreach (QHelpDBReader *reader, d->readerMap) + reader->linksForIdentifier(id, atts, linkMap); + + return linkMap; +} + +/*! + Removes the \a key from the settings section in the + collection file. Returns true if the value was removed + successfully, otherwise false. + + \sa customValue(), setCustomValue() +*/ +bool QHelpEngineCore::removeCustomValue(const QString &key) +{ + d->error.clear(); + return d->collectionHandler->removeCustomValue(key); +} + +/*! + Returns the value assigned to the \a key. If the requested + key does not exist, the specified \a defaultValue is + returned. + + \sa setCustomValue(), removeCustomValue() +*/ +QVariant QHelpEngineCore::customValue(const QString &key, const QVariant &defaultValue) const +{ + if (!d->setup()) + return QVariant(); + return d->collectionHandler->customValue(key, defaultValue); +} + +/*! + Save the \a value under the \a key. If the key already exist, + the value will be overwritten. Returns true if the value was + saved successfully, otherwise false. + + \sa customValue(), removeCustomValue() +*/ +bool QHelpEngineCore::setCustomValue(const QString &key, const QVariant &value) +{ + d->error.clear(); + return d->collectionHandler->setCustomValue(key, value); +} + +/*! + Returns the meta data for the Qt compressed help file \a + documentationFileName. If there is no data available for + \a name, an invalid QVariant() is returned. The meta + data is defined when creating the Qt compressed help file and + cannot be modified later. Common meta data includes e.g. + the author of the documentation. +*/ +QVariant QHelpEngineCore::metaData(const QString &documentationFileName, + const QString &name) +{ + QHelpDBReader reader(documentationFileName, QLatin1String("GetMetaData"), 0); + + if (reader.init()) + return reader.metaData(name); + return QVariant(); +} + +/*! + Returns a description of the last error that occurred. +*/ +QString QHelpEngineCore::error() const +{ + return d->error; +} + +/*! + \property QHelpEngineCore::autoSaveFilter + \brief whether QHelpEngineCore is in auto save filter mode or not. + \since 4.5 + + If QHelpEngineCore is in auto save filter mode, the current filter is + automatically saved when it is changed by the setCurrentFilter() + function. The filter is saved persistently in the help collection file. + + By default, this mode is on. +*/ +void QHelpEngineCore::setAutoSaveFilter(bool save) +{ + d->autoSaveFilter = save; +} + +bool QHelpEngineCore::autoSaveFilter() const +{ + return d->autoSaveFilter; +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/qhelpenginecore.h b/src/assistant/lib/qhelpenginecore.h new file mode 100644 index 000000000..fbfb8a0e8 --- /dev/null +++ b/src/assistant/lib/qhelpenginecore.h @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPENGINECORE_H +#define QHELPENGINECORE_H + +#include + +#include +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +class QHelpEngineCorePrivate; + +class QHELP_EXPORT QHelpEngineCore : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool autoSaveFilter READ autoSaveFilter WRITE setAutoSaveFilter) + Q_PROPERTY(QString collectionFile READ collectionFile WRITE setCollectionFile) + Q_PROPERTY(QString currentFilter READ currentFilter WRITE setCurrentFilter) + +public: + explicit QHelpEngineCore(const QString &collectionFile, QObject *parent = 0); + virtual ~QHelpEngineCore(); + + bool setupData(); + + QString collectionFile() const; + void setCollectionFile(const QString &fileName); + + bool copyCollectionFile(const QString &fileName); + + static QString namespaceName(const QString &documentationFileName); + bool registerDocumentation(const QString &documentationFileName); + bool unregisterDocumentation(const QString &namespaceName); + QString documentationFileName(const QString &namespaceName); + + QStringList customFilters() const; + bool removeCustomFilter(const QString &filterName); + bool addCustomFilter(const QString &filterName, + const QStringList &attributes); + + QStringList filterAttributes() const; + QStringList filterAttributes(const QString &filterName) const; + + QString currentFilter() const; + void setCurrentFilter(const QString &filterName); + + QStringList registeredDocumentations() const; + QList filterAttributeSets(const QString &namespaceName) const; + QList files(const QString namespaceName, + const QStringList &filterAttributes, + const QString &extensionFilter = QString()); + QUrl findFile(const QUrl &url) const; + QByteArray fileData(const QUrl &url) const; + + QMap linksForIdentifier(const QString &id) const; + + bool removeCustomValue(const QString &key); + QVariant customValue(const QString &key, + const QVariant &defaultValue = QVariant()) const; + bool setCustomValue(const QString &key, const QVariant &value); + + static QVariant metaData(const QString &documentationFileName, + const QString &name); + + QString error() const; + + void setAutoSaveFilter(bool save); + bool autoSaveFilter() const; + +Q_SIGNALS: + void setupStarted(); + void setupFinished(); + void currentFilterChanged(const QString &newFilter); + void warning(const QString &msg); + +protected: + QHelpEngineCore(QHelpEngineCorePrivate *helpEngineCorePrivate, + QObject *parent); + +private: + QHelpEngineCorePrivate *d; + friend class QHelpEngineCorePrivate; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QHELPENGINECORE_H diff --git a/src/assistant/lib/qhelpgenerator.cpp b/src/assistant/lib/qhelpgenerator.cpp new file mode 100644 index 000000000..ce9c8562d --- /dev/null +++ b/src/assistant/lib/qhelpgenerator.cpp @@ -0,0 +1,909 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpgenerator_p.h" +#include "qhelpdatainterface_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QHelpGeneratorPrivate +{ +public: + QHelpGeneratorPrivate(); + ~QHelpGeneratorPrivate(); + + QString error; + QSqlQuery *query; + + int namespaceId; + int virtualFolderId; + + QMap fileMap; + QMap > fileFilterMap; + + double progress; + double oldProgress; + double contentStep; + double fileStep; + double indexStep; +}; + +QHelpGeneratorPrivate::QHelpGeneratorPrivate() +{ + query = 0; + namespaceId = -1; + virtualFolderId = -1; +} + +QHelpGeneratorPrivate::~QHelpGeneratorPrivate() +{ +} + + + +/*! + \internal + \class QHelpGenerator + \since 4.4 + \brief The QHelpGenerator class generates a new + Qt compressed help file (.qch). + + The help generator takes a help data structure as + input for generating a new Qt compressed help files. Since + the generation may takes some time, the generator emits + various signals to inform about its current state. +*/ + +/*! + \fn void QHelpGenerator::statusChanged(const QString &msg) + + This signal is emitted when the generation status changes. + The status is basically a specific task like inserting + files or building up the keyword index. The parameter + \a msg contains the detailed status description. +*/ + +/*! + \fn void QHelpGenerator::progressChanged(double progress) + + This signal is emitted when the progress changes. The + \a progress ranges from 0 to 100. +*/ + +/*! + \fn void QHelpGenerator::warning(const QString &msg) + + This signal is emitted when a non critical error occurs, + e.g. when a referenced file cannot be found. \a msg + contains the exact warning message. +*/ + +/*! + Constructs a new help generator with the give \a parent. +*/ +QHelpGenerator::QHelpGenerator(QObject *parent) + : QObject(parent) +{ + d = new QHelpGeneratorPrivate; +} + +/*! + Destructs the help generator. +*/ +QHelpGenerator::~QHelpGenerator() +{ + delete d; +} + +/*! + Takes the \a helpData and generates a new documentation + set from it. The Qt compressed help file is written to \a + outputFileName. Returns true on success, otherwise false. +*/ +bool QHelpGenerator::generate(QHelpDataInterface *helpData, + const QString &outputFileName) +{ + emit progressChanged(0); + d->error.clear(); + if (!helpData || helpData->namespaceName().isEmpty()) { + d->error = tr("Invalid help data!"); + return false; + } + + QString outFileName = outputFileName; + if (outFileName.isEmpty()) { + d->error = tr("No output file name specified!"); + return false; + } + + QFileInfo fi(outFileName); + if (fi.exists()) { + if (!fi.dir().remove(fi.fileName())) { + d->error = tr("The file %1 cannot be overwritten!").arg(outFileName); + return false; + } + } + + setupProgress(helpData); + + emit statusChanged(tr("Building up file structure...")); + bool openingOk = true; + { + QSqlDatabase db = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), QLatin1String("builder")); + db.setDatabaseName(outFileName); + openingOk = db.open(); + if (openingOk) + d->query = new QSqlQuery(db); + } + + if (!openingOk) { + d->error = tr("Cannot open data base file %1!").arg(outFileName); + cleanupDB(); + return false; + } + + d->query->exec(QLatin1String("PRAGMA synchronous=OFF")); + d->query->exec(QLatin1String("PRAGMA cache_size=3000")); + + addProgress(1.0); + createTables(); + insertFileNotFoundFile(); + insertMetaData(helpData->metaData()); + + if (!registerVirtualFolder(helpData->virtualFolder(), helpData->namespaceName())) { + d->error = tr("Cannot register namespace %1!").arg(helpData->namespaceName()); + cleanupDB(); + return false; + } + addProgress(1.0); + + emit statusChanged(tr("Insert custom filters...")); + foreach (const QHelpDataCustomFilter &f, helpData->customFilters()) { + if (!registerCustomFilter(f.name, f.filterAttributes, true)) { + cleanupDB(); + return false; + } + } + addProgress(1.0); + + int i = 1; + QList::const_iterator it = helpData->filterSections().constBegin(); + while (it != helpData->filterSections().constEnd()) { + emit statusChanged(tr("Insert help data for filter section (%1 of %2)...") + .arg(i++).arg(helpData->filterSections().count())); + insertFilterAttributes((*it).filterAttributes()); + QByteArray ba; + QDataStream s(&ba, QIODevice::WriteOnly); + foreach (QHelpDataContentItem *itm, (*it).contents()) + writeTree(s, itm, 0); + if (!insertFiles((*it).files(), helpData->rootPath(), (*it).filterAttributes()) + || !insertContents(ba, (*it).filterAttributes()) + || !insertKeywords((*it).indices(), (*it).filterAttributes())) { + cleanupDB(); + return false; + } + ++it; + } + + cleanupDB(); + emit progressChanged(100); + emit statusChanged(tr("Documentation successfully generated.")); + return true; +} + +void QHelpGenerator::setupProgress(QHelpDataInterface *helpData) +{ + d->progress = 0; + d->oldProgress = 0; + + int numberOfFiles = 0; + int numberOfIndices = 0; + QList::const_iterator it = helpData->filterSections().constBegin(); + while (it != helpData->filterSections().constEnd()) { + numberOfFiles += (*it).files().count(); + numberOfIndices += (*it).indices().count(); + ++it; + } + // init 2% + // filters 1% + // contents 10% + // files 60% + // indices 27% + d->contentStep = 10.0/(double)helpData->customFilters().count(); + d->fileStep = 60.0/(double)numberOfFiles; + d->indexStep = 27.0/(double)numberOfIndices; +} + +void QHelpGenerator::addProgress(double step) +{ + d->progress += step; + if ((d->progress-d->oldProgress) >= 1.0 && d->progress <= 100.0) { + d->oldProgress = d->progress; + emit progressChanged(ceil(d->progress)); + } +} + +void QHelpGenerator::cleanupDB() +{ + if (d->query) { + d->query->clear(); + delete d->query; + d->query = 0; + } + QSqlDatabase::removeDatabase(QLatin1String("builder")); +} + +void QHelpGenerator::writeTree(QDataStream &s, QHelpDataContentItem *item, int depth) +{ + QString fReference = QDir::cleanPath(item->reference()); + if (fReference.startsWith(QLatin1String("./"))) + fReference = fReference.mid(2); + + s << depth; + s << fReference; + s << item->title(); + foreach (QHelpDataContentItem *i, item->children()) + writeTree(s, i, depth+1); +} + +/*! + Returns the last error message. +*/ +QString QHelpGenerator::error() const +{ + return d->error; +} + +bool QHelpGenerator::createTables() +{ + if (!d->query) + return false; + + d->query->exec(QLatin1String("SELECT COUNT(*) FROM sqlite_master WHERE TYPE=\'table\'" + "AND Name=\'NamespaceTable\'")); + d->query->next(); + if (d->query->value(0).toInt() > 0) { + d->error = tr("Some tables already exist!"); + return false; + } + + QStringList tables; + tables << QLatin1String("CREATE TABLE NamespaceTable (" + "Id INTEGER PRIMARY KEY," + "Name TEXT )") + << QLatin1String("CREATE TABLE FilterAttributeTable (" + "Id INTEGER PRIMARY KEY, " + "Name TEXT )") + << QLatin1String("CREATE TABLE FilterNameTable (" + "Id INTEGER PRIMARY KEY, " + "Name TEXT )") + << QLatin1String("CREATE TABLE FilterTable (" + "NameId INTEGER, " + "FilterAttributeId INTEGER )") + << QLatin1String("CREATE TABLE IndexTable (" + "Id INTEGER PRIMARY KEY, " + "Name TEXT, " + "Identifier TEXT, " + "NamespaceId INTEGER, " + "FileId INTEGER, " + "Anchor TEXT )") + << QLatin1String("CREATE TABLE IndexItemTable (" + "Id INTEGER, " + "IndexId INTEGER )") + << QLatin1String("CREATE TABLE IndexFilterTable (" + "FilterAttributeId INTEGER, " + "IndexId INTEGER )") + << QLatin1String("CREATE TABLE ContentsTable (" + "Id INTEGER PRIMARY KEY, " + "NamespaceId INTEGER, " + "Data BLOB )") + << QLatin1String("CREATE TABLE ContentsFilterTable (" + "FilterAttributeId INTEGER, " + "ContentsId INTEGER )") + << QLatin1String("CREATE TABLE FileAttributeSetTable (" + "Id INTEGER, " + "FilterAttributeId INTEGER )") + << QLatin1String("CREATE TABLE FileDataTable (" + "Id INTEGER PRIMARY KEY, " + "Data BLOB )") + << QLatin1String("CREATE TABLE FileFilterTable (" + "FilterAttributeId INTEGER, " + "FileId INTEGER )") + << QLatin1String("CREATE TABLE FileNameTable (" + "FolderId INTEGER, " + "Name TEXT, " + "FileId INTEGER, " + "Title TEXT )") + << QLatin1String("CREATE TABLE FolderTable(" + "Id INTEGER PRIMARY KEY, " + "Name Text, " + "NamespaceID INTEGER )") + << QLatin1String("CREATE TABLE MetaDataTable(" + "Name Text, " + "Value BLOB )"); + + foreach (const QString &q, tables) { + if (!d->query->exec(q)) { + d->error = tr("Cannot create tables!"); + return false; + } + } + + d->query->exec(QLatin1String("INSERT INTO MetaDataTable VALUES('qchVersion', '1.0')")); + + d->query->prepare(QLatin1String("INSERT INTO MetaDataTable VALUES('CreationDate', ?)")); + d->query->bindValue(0, QDateTime::currentDateTime().toString(Qt::ISODate)); + d->query->exec(); + + return true; +} + +bool QHelpGenerator::insertFileNotFoundFile() +{ + if (!d->query) + return false; + + d->query->exec(QLatin1String("SELECT id FROM FileNameTable WHERE Name=\'\'")); + if (d->query->next() && d->query->isValid()) + return true; + + d->query->prepare(QLatin1String("INSERT INTO FileDataTable VALUES (Null, ?)")); + d->query->bindValue(0, QByteArray()); + if (!d->query->exec()) + return false; + + int fileId = d->query->lastInsertId().toInt(); + d->query->prepare(QLatin1String("INSERT INTO FileNameTable (FolderId, Name, FileId, Title) " + " VALUES (0, '', ?, '')")); + d->query->bindValue(0, fileId); + if (fileId > -1 && d->query->exec()) { + d->fileMap.insert(QString(), fileId); + return true; + } + return false; +} + +bool QHelpGenerator::registerVirtualFolder(const QString &folderName, const QString &ns) +{ + if (!d->query || folderName.isEmpty() || ns.isEmpty()) + return false; + + d->query->prepare(QLatin1String("SELECT Id FROM FolderTable WHERE Name=?")); + d->query->bindValue(0, folderName); + d->query->exec(); + d->query->next(); + if (d->query->isValid() && d->query->value(0).toInt() > 0) + return true; + + d->namespaceId = -1; + d->query->prepare(QLatin1String("SELECT Id FROM NamespaceTable WHERE Name=?")); + d->query->bindValue(0, ns); + d->query->exec(); + while (d->query->next()) { + d->namespaceId = d->query->value(0).toInt(); + break; + } + + if (d->namespaceId < 0) { + d->query->prepare(QLatin1String("INSERT INTO NamespaceTable VALUES(NULL, ?)")); + d->query->bindValue(0, ns); + if (d->query->exec()) + d->namespaceId = d->query->lastInsertId().toInt(); + } + + if (d->namespaceId > 0) { + d->query->prepare(QLatin1String("SELECT Id FROM FolderTable WHERE Name=?")); + d->query->bindValue(0, folderName); + d->query->exec(); + while (d->query->next()) + d->virtualFolderId = d->query->value(0).toInt(); + + if (d->virtualFolderId > 0) + return true; + + d->query->prepare(QLatin1String("INSERT INTO FolderTable (NamespaceId, Name) " + "VALUES (?, ?)")); + d->query->bindValue(0, d->namespaceId); + d->query->bindValue(1, folderName); + if (d->query->exec()) { + d->virtualFolderId = d->query->lastInsertId().toInt(); + return d->virtualFolderId > 0; + } + } + d->error = tr("Cannot register virtual folder!"); + return false; +} + +bool QHelpGenerator::insertFiles(const QStringList &files, const QString &rootPath, + const QStringList &filterAttributes) +{ + if (!d->query) + return false; + + emit statusChanged(tr("Insert files...")); + QList filterAtts; + foreach (const QString &filterAtt, filterAttributes) { + d->query->prepare(QLatin1String("SELECT Id FROM FilterAttributeTable " + "WHERE Name=?")); + d->query->bindValue(0, filterAtt); + d->query->exec(); + if (d->query->next()) + filterAtts.append(d->query->value(0).toInt()); + } + + int filterSetId = -1; + d->query->exec(QLatin1String("SELECT MAX(Id) FROM FileAttributeSetTable")); + if (d->query->next()) + filterSetId = d->query->value(0).toInt(); + if (filterSetId < 0) + return false; + ++filterSetId; + foreach (const int &attId, filterAtts) { + d->query->prepare(QLatin1String("INSERT INTO FileAttributeSetTable " + "VALUES(?, ?)")); + d->query->bindValue(0, filterSetId); + d->query->bindValue(1, attId); + d->query->exec(); + } + + int tableFileId = 1; + d->query->exec(QLatin1String("SELECT MAX(Id) FROM FileDataTable")); + if (d->query->next()) + tableFileId = d->query->value(0).toInt() + 1; + + QString title; + QString charSet; + FileNameTableData fileNameData; + QList fileDataList; + QMap > tmpFileFilterMap; + QList fileNameDataList; + + int i = 0; + foreach (const QString &file, files) { + const QString fileName = QDir::cleanPath(file); + if (fileName.startsWith(QLatin1String("../"))) { + emit warning(tr("The referenced file %1 must be inside or within a " + "subdirectory of (%2). Skipping it.").arg(fileName).arg(rootPath)); + continue; + } + + QFile fi(rootPath + QDir::separator() + fileName); + if (!fi.exists()) { + emit warning(tr("The file %1 does not exist! Skipping it.") + .arg(QDir::cleanPath(rootPath + QDir::separator() + fileName))); + continue; + } + + if (!fi.open(QIODevice::ReadOnly)) { + emit warning(tr("Cannot open file %1! Skipping it.") + .arg(QDir::cleanPath(rootPath + QDir::separator() + fileName))); + continue; + } + + QByteArray data = fi.readAll(); + if (fileName.endsWith(QLatin1String(".html")) + || fileName.endsWith(QLatin1String(".htm"))) { + charSet = QHelpGlobal::codecFromData(data); + QTextStream stream(&data); + stream.setCodec(QTextCodec::codecForName(charSet.toLatin1().constData())); + title = QHelpGlobal::documentTitle(stream.readAll()); + } else { + title = fileName.mid(fileName.lastIndexOf(QLatin1Char('/')) + 1); + } + + int fileId = -1; + QMap::Iterator fileMapIt = d->fileMap.find(fileName); + if (fileMapIt == d->fileMap.end()) { + fileDataList.append(qCompress(data)); + + fileNameData.name = fileName; + fileNameData.fileId = tableFileId; + fileNameData.title = title; + fileNameDataList.append(fileNameData); + + d->fileMap.insert(fileName, tableFileId); + d->fileFilterMap.insert(tableFileId, filterAtts.toSet()); + tmpFileFilterMap.insert(tableFileId, filterAtts.toSet()); + + ++tableFileId; + } else { + fileId = fileMapIt.value(); + QSet &fileFilterSet = d->fileFilterMap[fileId]; + QSet &tmpFileFilterSet = tmpFileFilterMap[fileId]; + foreach (const int &filter, filterAtts) { + if (!fileFilterSet.contains(filter) + && !tmpFileFilterSet.contains(filter)) { + fileFilterSet.insert(filter); + tmpFileFilterSet.insert(filter); + } + } + } + } + + if (!tmpFileFilterMap.isEmpty()) { + d->query->exec(QLatin1String("BEGIN")); + QMap >::const_iterator it = tmpFileFilterMap.constBegin(); + while (it != tmpFileFilterMap.constEnd()) { + QSet::const_iterator si = it.value().constBegin(); + while (si != it.value().constEnd()) { + d->query->prepare(QLatin1String("INSERT INTO FileFilterTable " + "VALUES(?, ?)")); + d->query->bindValue(0, *si); + d->query->bindValue(1, it.key()); + d->query->exec(); + ++si; + } + ++it; + } + + QList::const_iterator fileIt = fileDataList.constBegin(); + while (fileIt != fileDataList.constEnd()) { + d->query->prepare(QLatin1String("INSERT INTO FileDataTable VALUES " + "(Null, ?)")); + d->query->bindValue(0, *fileIt); + d->query->exec(); + ++fileIt; + if (++i%20 == 0) + addProgress(d->fileStep*20.0); + } + + QList::const_iterator fileNameIt = + fileNameDataList.constBegin(); + while (fileNameIt != fileNameDataList.constEnd()) { + d->query->prepare(QLatin1String("INSERT INTO FileNameTable " + "(FolderId, Name, FileId, Title) VALUES (?, ?, ?, ?)")); + d->query->bindValue(0, 1); + d->query->bindValue(1, (*fileNameIt).name); + d->query->bindValue(2, (*fileNameIt).fileId); + d->query->bindValue(3, (*fileNameIt).title); + d->query->exec(); + ++fileNameIt; + } + d->query->exec(QLatin1String("COMMIT")); + } + + d->query->exec(QLatin1String("SELECT MAX(Id) FROM FileDataTable")); + if (d->query->next() + && d->query->value(0).toInt() == tableFileId-1) { + addProgress(d->fileStep*(i%20)); + return true; + } + return false; +} + +bool QHelpGenerator::registerCustomFilter(const QString &filterName, + const QStringList &filterAttribs, bool forceUpdate) +{ + if (!d->query) + return false; + + d->query->exec(QLatin1String("SELECT Id, Name FROM FilterAttributeTable")); + QStringList idsToInsert = filterAttribs; + QMap attributeMap; + while (d->query->next()) { + attributeMap.insert(d->query->value(1).toString(), + d->query->value(0).toInt()); + idsToInsert.removeAll(d->query->value(1).toString()); + } + + foreach (const QString &id, idsToInsert) { + d->query->prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)")); + d->query->bindValue(0, id); + d->query->exec(); + attributeMap.insert(id, d->query->lastInsertId().toInt()); + } + + int nameId = -1; + d->query->prepare(QLatin1String("SELECT Id FROM FilterNameTable WHERE Name=?")); + d->query->bindValue(0, filterName); + d->query->exec(); + while (d->query->next()) { + nameId = d->query->value(0).toInt(); + break; + } + + if (nameId < 0) { + d->query->prepare(QLatin1String("INSERT INTO FilterNameTable VALUES(NULL, ?)")); + d->query->bindValue(0, filterName); + if (d->query->exec()) + nameId = d->query->lastInsertId().toInt(); + } else if (!forceUpdate) { + d->error = tr("The filter %1 is already registered!").arg(filterName); + return false; + } + + if (nameId < 0) { + d->error = tr("Cannot register filter %1!").arg(filterName); + return false; + } + + d->query->prepare(QLatin1String("DELETE FROM FilterTable WHERE NameId=?")); + d->query->bindValue(0, nameId); + d->query->exec(); + + foreach (const QString &att, filterAttribs) { + d->query->prepare(QLatin1String("INSERT INTO FilterTable VALUES(?, ?)")); + d->query->bindValue(0, nameId); + d->query->bindValue(1, attributeMap[att]); + if (!d->query->exec()) + return false; + } + return true; +} + +bool QHelpGenerator::insertKeywords(const QList &keywords, + const QStringList &filterAttributes) +{ + if (!d->query) + return false; + + emit statusChanged(tr("Insert indices...")); + int indexId = 1; + d->query->exec(QLatin1String("SELECT MAX(Id) FROM IndexTable")); + if (d->query->next()) + indexId = d->query->value(0).toInt() + 1; + + QList filterAtts; + foreach (const QString &filterAtt, filterAttributes) { + d->query->prepare(QLatin1String("SELECT Id FROM FilterAttributeTable WHERE Name=?")); + d->query->bindValue(0, filterAtt); + d->query->exec(); + if (d->query->next()) + filterAtts.append(d->query->value(0).toInt()); + } + + int pos = -1; + QString fileName; + QString anchor; + QString fName; + int fileId = 1; + QList indexFilterTable; + + int i = 0; + d->query->exec(QLatin1String("BEGIN")); + QSet indices; + foreach (const QHelpDataIndexItem &itm, keywords) { + // Identical ids make no sense and just confuse the Assistant user, + // so we ignore all repetitions. + if (indices.contains(itm.identifier)) + continue; + + // Still empty ids should be ignored, as otherwise we will include only + // the first keyword with an empty id. + if (!itm.identifier.isEmpty()) + indices.insert(itm.identifier); + + pos = itm.reference.indexOf(QLatin1Char('#')); + fileName = itm.reference.left(pos); + if (pos > -1) + anchor = itm.reference.mid(pos+1); + else + anchor.clear(); + + fName = QDir::cleanPath(fileName); + if (fName.startsWith(QLatin1String("./"))) + fName = fName.mid(2); + + QMap::ConstIterator it = d->fileMap.find(fName); + if (it != d->fileMap.end()) + fileId = it.value(); + else + fileId = 1; + + d->query->prepare(QLatin1String("INSERT INTO IndexTable (Name, Identifier, NamespaceId, FileId, Anchor) " + "VALUES(?, ?, ?, ?, ?)")); + d->query->bindValue(0, itm.name); + d->query->bindValue(1, itm.identifier); + d->query->bindValue(2, d->namespaceId); + d->query->bindValue(3, fileId); + d->query->bindValue(4, anchor); + d->query->exec(); + + indexFilterTable.append(indexId++); + if (++i%100 == 0) + addProgress(d->indexStep*100.0); + } + d->query->exec(QLatin1String("COMMIT")); + + d->query->exec(QLatin1String("BEGIN")); + foreach (int idx, indexFilterTable) { + foreach (int a, filterAtts) { + d->query->prepare(QLatin1String("INSERT INTO IndexFilterTable (FilterAttributeId, IndexId) " + "VALUES(?, ?)")); + d->query->bindValue(0, a); + d->query->bindValue(1, idx); + d->query->exec(); + } + } + d->query->exec(QLatin1String("COMMIT")); + + d->query->exec(QLatin1String("SELECT COUNT(Id) FROM IndexTable")); + if (d->query->next() && d->query->value(0).toInt() >= indices.count()) + return true; + return false; +} + +bool QHelpGenerator::insertContents(const QByteArray &ba, + const QStringList &filterAttributes) +{ + if (!d->query) + return false; + + emit statusChanged(tr("Insert contents...")); + d->query->prepare(QLatin1String("INSERT INTO ContentsTable (NamespaceId, Data) " + "VALUES(?, ?)")); + d->query->bindValue(0, d->namespaceId); + d->query->bindValue(1, ba); + d->query->exec(); + int contentId = d->query->lastInsertId().toInt(); + if (contentId < 1) { + d->error = tr("Cannot insert contents!"); + return false; + } + + // associate the filter attributes + foreach (const QString &filterAtt, filterAttributes) { + d->query->prepare(QLatin1String("INSERT INTO ContentsFilterTable (FilterAttributeId, ContentsId) " + "SELECT Id, ? FROM FilterAttributeTable WHERE Name=?")); + d->query->bindValue(0, contentId); + d->query->bindValue(1, filterAtt); + d->query->exec(); + if (!d->query->isActive()) { + d->error = tr("Cannot register contents!"); + return false; + } + } + addProgress(d->contentStep); + return true; +} + +bool QHelpGenerator::insertFilterAttributes(const QStringList &attributes) +{ + if (!d->query) + return false; + + d->query->exec(QLatin1String("SELECT Name FROM FilterAttributeTable")); + QSet atts; + while (d->query->next()) + atts.insert(d->query->value(0).toString()); + + foreach (const QString &s, attributes) { + if (!atts.contains(s)) { + d->query->prepare(QLatin1String("INSERT INTO FilterAttributeTable VALUES(NULL, ?)")); + d->query->bindValue(0, s); + d->query->exec(); + } + } + return true; +} + +bool QHelpGenerator::insertMetaData(const QMap &metaData) +{ + if (!d->query) + return false; + + QMap::const_iterator it = metaData.constBegin(); + while (it != metaData.constEnd()) { + d->query->prepare(QLatin1String("INSERT INTO MetaDataTable VALUES(?, ?)")); + d->query->bindValue(0, it.key()); + d->query->bindValue(1, it.value()); + d->query->exec(); + ++it; + } + return true; +} + +bool QHelpGenerator::checkLinks(const QHelpDataInterface &helpData) +{ + /* + * Step 1: Gather the canoncal file paths of all files in the project. + * We use a set, because there will be a lot of look-ups. + */ + QSet files; + foreach (const QHelpDataFilterSection &filterSection, helpData.filterSections()) { + foreach (const QString &file, filterSection.files()) { + QFileInfo fileInfo(helpData.rootPath() + QDir::separator() + file); + const QString &canonicalFileName = fileInfo.canonicalFilePath(); + if (!fileInfo.exists()) + emit warning(tr("File '%1' does not exist.").arg(file)); + else + files.insert(canonicalFileName); + } + } + + /* + * Step 2: Check the hypertext and image references of all HTML files. + * Note that we don't parse the files, but simply grep for the + * respective HTML elements. Therefore. contents that are e.g. + * commented out can cause false warning. + */ + bool allLinksOk = true; + foreach (const QString &fileName, files) { + if (!fileName.endsWith(QLatin1String("html")) + && !fileName.endsWith(QLatin1String("htm"))) + continue; + QFile htmlFile(fileName); + if (!htmlFile.open(QIODevice::ReadOnly)) { + emit warning(tr("File '%1' cannot be opened.").arg(fileName)); + continue; + } + const QRegExp linkPattern(QLatin1String("<(?:a href|img src)=\"?([^#\">]+)[#\">]")); + QTextStream stream(&htmlFile); + const QString codec = QHelpGlobal::codecFromData(htmlFile.read(1000)); + stream.setCodec(QTextCodec::codecForName(codec.toLatin1().constData())); + const QString &content = stream.readAll(); + QStringList invalidLinks; + for (int pos = linkPattern.indexIn(content); pos != -1; + pos = linkPattern.indexIn(content, pos + 1)) { + const QString& linkedFileName = linkPattern.cap(1); + if (linkedFileName.contains(QLatin1String("://"))) + continue; + const QString curDir = QFileInfo(fileName).dir().path(); + const QString &canonicalLinkedFileName = + QFileInfo(curDir + QDir::separator() + linkedFileName).canonicalFilePath(); + if (!files.contains(canonicalLinkedFileName) + && !invalidLinks.contains(canonicalLinkedFileName)) { + emit warning(tr("File '%1' contains an invalid link to file '%2'"). + arg(fileName).arg(linkedFileName)); + allLinksOk = false; + invalidLinks.append(canonicalLinkedFileName); + } + } + } + + if (!allLinksOk) + d->error = tr("Invalid links in HTML files."); + return allLinksOk; +} + +QT_END_NAMESPACE + diff --git a/src/assistant/lib/qhelpgenerator_p.h b/src/assistant/lib/qhelpgenerator_p.h new file mode 100644 index 000000000..ad32c05de --- /dev/null +++ b/src/assistant/lib/qhelpgenerator_p.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPGENERATOR_H +#define QHELPGENERATOR_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhelp_global.h" +#include "qhelpdatainterface_p.h" + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QHelpGeneratorPrivate; + +class QHELP_EXPORT QHelpGenerator : public QObject +{ + Q_OBJECT + +public: + QHelpGenerator(QObject *parent = 0); + ~QHelpGenerator(); + + bool generate(QHelpDataInterface *helpData, + const QString &outputFileName); + bool checkLinks(const QHelpDataInterface &helpData); + QString error() const; + +Q_SIGNALS: + void statusChanged(const QString &msg); + void progressChanged(double progress); + void warning(const QString &msg); + +private: + struct FileNameTableData + { + QString name; + int fileId; + QString title; + }; + + void writeTree(QDataStream &s, QHelpDataContentItem *item, int depth); + bool createTables(); + bool insertFileNotFoundFile(); + bool registerCustomFilter(const QString &filterName, + const QStringList &filterAttribs, bool forceUpdate = false); + bool registerVirtualFolder(const QString &folderName, const QString &ns); + bool insertFilterAttributes(const QStringList &attributes); + bool insertKeywords(const QList &keywords, + const QStringList &filterAttributes); + bool insertFiles(const QStringList &files, const QString &rootPath, + const QStringList &filterAttributes); + bool insertContents(const QByteArray &ba, + const QStringList &filterAttributes); + bool insertMetaData(const QMap &metaData); + void cleanupDB(); + void setupProgress(QHelpDataInterface *helpData); + void addProgress(double step); + + QHelpGeneratorPrivate *d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/assistant/lib/qhelpindexwidget.cpp b/src/assistant/lib/qhelpindexwidget.cpp new file mode 100644 index 000000000..82d402442 --- /dev/null +++ b/src/assistant/lib/qhelpindexwidget.cpp @@ -0,0 +1,444 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpindexwidget.h" +#include "qhelpenginecore.h" +#include "qhelpengine_p.h" +#include "qhelpdbreader_p.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QHelpIndexProvider : public QThread +{ +public: + QHelpIndexProvider(QHelpEnginePrivate *helpEngine); + ~QHelpIndexProvider(); + void collectIndices(const QString &customFilterName); + void stopCollecting(); + QStringList indices() const; + QList activeReaders() const; + QSet indexIds(QHelpDBReader *reader) const; + +private: + void run(); + + QHelpEnginePrivate *m_helpEngine; + QStringList m_indices; + QList m_activeReaders; + QMap > m_indexIds; + QStringList m_filterAttributes; + mutable QMutex m_mutex; + bool m_abort; +}; + +class QHelpIndexModelPrivate +{ +public: + QHelpIndexModelPrivate(QHelpEnginePrivate *hE) + { + helpEngine = hE; + indexProvider = new QHelpIndexProvider(helpEngine); + insertedRows = 0; + } + + QHelpEnginePrivate *helpEngine; + QHelpIndexProvider *indexProvider; + QStringList indices; + int insertedRows; + QString currentFilter; + QList activeReaders; +}; + +static bool caseInsensitiveLessThan(const QString &as, const QString &bs) +{ + return QString::compare(as, bs, Qt::CaseInsensitive) < 0; +} + +QHelpIndexProvider::QHelpIndexProvider(QHelpEnginePrivate *helpEngine) + : QThread(helpEngine) +{ + m_helpEngine = helpEngine; + m_abort = false; +} + +QHelpIndexProvider::~QHelpIndexProvider() +{ + stopCollecting(); +} + +void QHelpIndexProvider::collectIndices(const QString &customFilterName) +{ + m_mutex.lock(); + m_filterAttributes = m_helpEngine->q->filterAttributes(customFilterName); + m_mutex.unlock(); + if (!isRunning()) { + start(LowPriority); + } else { + stopCollecting(); + start(LowPriority); + } +} + +void QHelpIndexProvider::stopCollecting() +{ + if (!isRunning()) + return; + m_mutex.lock(); + m_abort = true; + m_mutex.unlock(); + wait(); + m_abort = false; +} + +QStringList QHelpIndexProvider::indices() const +{ + QMutexLocker lck(&m_mutex); + return m_indices; +} + +QList QHelpIndexProvider::activeReaders() const +{ + QMutexLocker lck(&m_mutex); + return m_activeReaders; +} + +QSet QHelpIndexProvider::indexIds(QHelpDBReader *reader) const +{ + QMutexLocker lck(&m_mutex); + if (m_indexIds.contains(reader)) + return m_indexIds.value(reader); + return QSet(); +} + +void QHelpIndexProvider::run() +{ + m_mutex.lock(); + QStringList atts = m_filterAttributes; + m_indices.clear(); + m_activeReaders.clear(); + QSet indicesSet; + m_mutex.unlock(); + + foreach (const QString &dbFileName, m_helpEngine->fileNameReaderMap.keys()) { + m_mutex.lock(); + if (m_abort) { + m_mutex.unlock(); + return; + } + m_mutex.unlock(); + QHelpDBReader reader(dbFileName, + QHelpGlobal::uniquifyConnectionName(dbFileName + + QLatin1String("FromIndexProvider"), + QThread::currentThread()), 0); + if (!reader.init()) + continue; + QStringList lst = reader.indicesForFilter(atts); + if (!lst.isEmpty()) { + m_mutex.lock(); + foreach (const QString &s, lst) + indicesSet.insert(s); + if (m_abort) { + m_mutex.unlock(); + return; + } + QHelpDBReader *orgReader = m_helpEngine->fileNameReaderMap.value(dbFileName); + m_indexIds.insert(orgReader, reader.indexIds(atts)); + m_activeReaders.append(orgReader); + m_mutex.unlock(); + } + } + m_mutex.lock(); + m_indices = indicesSet.values(); + qSort(m_indices.begin(), m_indices.end(), caseInsensitiveLessThan); + m_mutex.unlock(); +} + + + +/*! + \class QHelpIndexModel + \since 4.4 + \inmodule QtHelp + \brief The QHelpIndexModel class provides a model that + supplies index keywords to views. + + +*/ + +/*! + \fn void QHelpIndexModel::indexCreationStarted() + + This signal is emitted when the creation of a new index + has started. The current index is invalid from this + point on until the signal indexCreated() is emitted. + + \sa isCreatingIndex() +*/ + +/*! + \fn void QHelpIndexModel::indexCreated() + + This signal is emitted when the index has been created. +*/ + +QHelpIndexModel::QHelpIndexModel(QHelpEnginePrivate *helpEngine) + : QStringListModel(helpEngine) +{ + d = new QHelpIndexModelPrivate(helpEngine); + + connect(d->indexProvider, SIGNAL(finished()), this, SLOT(insertIndices())); + connect(helpEngine->q, SIGNAL(setupStarted()), this, SLOT(invalidateIndex())); +} + +QHelpIndexModel::~QHelpIndexModel() +{ + delete d; +} + +void QHelpIndexModel::invalidateIndex(bool onShutDown) +{ + if (onShutDown) + disconnect(this, SLOT(insertIndices())); + d->indexProvider->stopCollecting(); + d->indices.clear(); + if (!onShutDown) + filter(QString()); +} + +/*! + Creates a new index by querying the help system for + keywords for the specified \a customFilterName. +*/ +void QHelpIndexModel::createIndex(const QString &customFilterName) +{ + d->currentFilter = customFilterName; + d->indexProvider->collectIndices(customFilterName); + emit indexCreationStarted(); +} + +void QHelpIndexModel::insertIndices() +{ + d->indices = d->indexProvider->indices(); + d->activeReaders = d->indexProvider->activeReaders(); + QStringList attributes = d->helpEngine->q->filterAttributes(d->currentFilter); + if (attributes.count() > 1) { + foreach (QHelpDBReader *r, d->activeReaders) + r->createAttributesCache(attributes, d->indexProvider->indexIds(r)); + } + filter(QString()); + emit indexCreated(); +} + +/*! + Returns true if the index is currently built up, otherwise + false. +*/ +bool QHelpIndexModel::isCreatingIndex() const +{ + return d->indexProvider->isRunning(); +} + +/*! + Returns all hits found for the \a keyword. A hit consists of + the URL and the document title. +*/ +QMap QHelpIndexModel::linksForKeyword(const QString &keyword) const +{ + QMap linkMap; + QStringList filterAttributes = d->helpEngine->q->filterAttributes(d->currentFilter); + foreach (QHelpDBReader *reader, d->activeReaders) + reader->linksForKeyword(keyword, filterAttributes, linkMap); + return linkMap; +} + +/*! + Filters the indices and returns the model index of the best + matching keyword. In a first step, only the keywords containing + \a filter are kept in the model's index list. Analogously, if + \a wildcard is not empty, only the keywords matched are left + in the index list. In a second step, the best match is + determined and its index model returned. When specifying a + wildcard expression, the \a filter string is used to + search for the best match. +*/ +QModelIndex QHelpIndexModel::filter(const QString &filter, const QString &wildcard) +{ + if (filter.isEmpty()) { + setStringList(d->indices); + return index(-1, 0, QModelIndex()); + } + + QStringList lst; + int goodMatch = -1; + int perfectMatch = -1; + + if (!wildcard.isEmpty()) { + QRegExp regExp(wildcard, Qt::CaseInsensitive); + regExp.setPatternSyntax(QRegExp::Wildcard); + foreach (const QString &index, d->indices) { + if (index.contains(regExp)) { + lst.append(index); + if (perfectMatch == -1 && index.startsWith(filter, Qt::CaseInsensitive)) { + if (goodMatch == -1) + goodMatch = lst.count()-1; + if (filter.length() == index.length()){ + perfectMatch = lst.count()-1; + } + } else if (perfectMatch > -1 && index == filter) { + perfectMatch = lst.count()-1; + } + } + } + } else { + foreach (const QString &index, d->indices) { + if (index.contains(filter, Qt::CaseInsensitive)) { + lst.append(index); + if (perfectMatch == -1 && index.startsWith(filter, Qt::CaseInsensitive)) { + if (goodMatch == -1) + goodMatch = lst.count()-1; + if (filter.length() == index.length()){ + perfectMatch = lst.count()-1; + } + } else if (perfectMatch > -1 && index == filter) { + perfectMatch = lst.count()-1; + } + } + } + + } + + if (perfectMatch == -1) + perfectMatch = qMax(0, goodMatch); + + setStringList(lst); + return index(perfectMatch, 0, QModelIndex()); +} + + + +/*! + \class QHelpIndexWidget + \inmodule QtHelp + \since 4.4 + \brief The QHelpIndexWidget class provides a list view + displaying the QHelpIndexModel. +*/ + +/*! + \fn void QHelpIndexWidget::linkActivated(const QUrl &link, + const QString &keyword) + + This signal is emitted when an item is activated and its + associated \a link should be shown. To know where the link + belongs to, the \a keyword is given as a second paremeter. +*/ + +/*! + \fn void QHelpIndexWidget::linksActivated(const QMap &links, + const QString &keyword) + + This signal is emitted when the item representing the \a keyword + is activated and the item has more than one link associated. + The \a links consist of the document title and their URL. +*/ + +QHelpIndexWidget::QHelpIndexWidget() + : QListView(0) +{ + setEditTriggers(QAbstractItemView::NoEditTriggers); + setUniformItemSizes(true); + connect(this, SIGNAL(activated(QModelIndex)), + this, SLOT(showLink(QModelIndex))); +} + +void QHelpIndexWidget::showLink(const QModelIndex &index) +{ + if (!index.isValid()) + return; + + QHelpIndexModel *indexModel = qobject_cast(model()); + if (!indexModel) + return; + QVariant v = indexModel->data(index, Qt::DisplayRole); + QString name; + if (v.isValid()) + name = v.toString(); + + QMap links = indexModel->linksForKeyword(name); + if (links.count() == 1) { + emit linkActivated(links.constBegin().value(), name); + } else if (links.count() > 1) { + emit linksActivated(links, name); + } +} + +/*! + Activates the current item which will result eventually in + the emitting of a linkActivated() or linksActivated() + signal. +*/ +void QHelpIndexWidget::activateCurrentItem() +{ + showLink(currentIndex()); +} + +/*! + Filters the indices according to \a filter or \a wildcard. + The item with the best match is set as current item. + + \sa QHelpIndexModel::filter() +*/ +void QHelpIndexWidget::filterIndices(const QString &filter, const QString &wildcard) +{ + QHelpIndexModel *indexModel = qobject_cast(model()); + if (!indexModel) + return; + QModelIndex idx = indexModel->filter(filter, wildcard); + if (idx.isValid()) + setCurrentIndex(idx); +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/qhelpindexwidget.h b/src/assistant/lib/qhelpindexwidget.h new file mode 100644 index 000000000..0c4d307aa --- /dev/null +++ b/src/assistant/lib/qhelpindexwidget.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPINDEXWIDGET_H +#define QHELPINDEXWIDGET_H + +#include + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +class QHelpEnginePrivate; +class QHelpIndexModelPrivate; + +class QHELP_EXPORT QHelpIndexModel : public QStringListModel +{ + Q_OBJECT + +public: + void createIndex(const QString &customFilterName); + QModelIndex filter(const QString &filter, + const QString &wildcard = QString()); + + QMap linksForKeyword(const QString &keyword) const; + bool isCreatingIndex() const; + +Q_SIGNALS: + void indexCreationStarted(); + void indexCreated(); + +private Q_SLOTS: + void insertIndices(); + void invalidateIndex(bool onShutDown = false); + +private: + QHelpIndexModel(QHelpEnginePrivate *helpEngine); + ~QHelpIndexModel(); + + QHelpIndexModelPrivate *d; + friend class QHelpEnginePrivate; +}; + +class QHELP_EXPORT QHelpIndexWidget : public QListView +{ + Q_OBJECT + +Q_SIGNALS: + void linkActivated(const QUrl &link, const QString &keyword); + void linksActivated(const QMap &links, + const QString &keyword); + +public Q_SLOTS: + void filterIndices(const QString &filter, + const QString &wildcard = QString()); + void activateCurrentItem(); + +private Q_SLOTS: + void showLink(const QModelIndex &index); + +private: + QHelpIndexWidget(); + friend class QHelpEngine; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/assistant/lib/qhelpprojectdata.cpp b/src/assistant/lib/qhelpprojectdata.cpp new file mode 100644 index 000000000..bd59e289c --- /dev/null +++ b/src/assistant/lib/qhelpprojectdata.cpp @@ -0,0 +1,450 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpprojectdata_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QHelpProjectDataPrivate : public QXmlStreamReader +{ +public: + void readData(const QByteArray &contents); + + QString virtualFolder; + QString namespaceName; + QString rootPath; + + QStringList fileList; + QList customFilterList; + QList filterSectionList; + QMap metaData; + + QString errorMsg; + +private: + void readProject(); + void readCustomFilter(); + void readFilterSection(); + void readTOC(); + void readKeywords(); + void readFiles(); + void raiseUnknownTokenError(); + void addMatchingFiles(const QString &pattern); + bool hasValidSyntax(const QString &nameSpace, const QString &vFolder) const; + + QMap dirEntriesCache; +}; + +void QHelpProjectDataPrivate::raiseUnknownTokenError() +{ + raiseError(QCoreApplication::translate("QHelpProject", "Unknown token.")); +} + +void QHelpProjectDataPrivate::readData(const QByteArray &contents) +{ + addData(contents); + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("QtHelpProject") + && attributes().value(QLatin1String("version")) == QLatin1String("1.0")) + readProject(); + else + raiseError(QCoreApplication::translate("QHelpProject", + "Unknown token. Expected \"QtHelpProject\"!")); + } + } + + if (hasError()) { + raiseError(QCoreApplication::translate("QHelpProject", + "Error in line %1: %2").arg(lineNumber()) + .arg(errorString())); + } +} + +void QHelpProjectDataPrivate::readProject() +{ + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("virtualFolder")) { + virtualFolder = readElementText(); + if (!hasValidSyntax(QLatin1String("test"), virtualFolder)) + raiseError(QCoreApplication::translate("QHelpProject", + "Virtual folder has invalid syntax.")); + } else if (name() == QLatin1String("namespace")) { + namespaceName = readElementText(); + if (!hasValidSyntax(namespaceName, QLatin1String("test"))) + raiseError(QCoreApplication::translate("QHelpProject", + "Namespace has invalid syntax.")); + } else if (name() == QLatin1String("customFilter")) { + readCustomFilter(); + } else if (name() == QLatin1String("filterSection")) { + readFilterSection(); + } else if (name() == QLatin1String("metaData")) { + QString n = attributes().value(QLatin1String("name")).toString(); + if (!metaData.contains(n)) + metaData[n] + = attributes().value(QLatin1String("value")).toString(); + else + metaData.insert(n, attributes(). + value(QLatin1String("value")).toString()); + } else { + raiseUnknownTokenError(); + } + } else if (isEndElement() && name() == QLatin1String("QtHelpProject")) { + if (namespaceName.isEmpty()) + raiseError(QCoreApplication::translate("QHelpProject", + "Missing namespace in QtHelpProject.")); + else if (virtualFolder.isEmpty()) + raiseError(QCoreApplication::translate("QHelpProject", + "Missing virtual folder in QtHelpProject")); + break; + } + } +} + +void QHelpProjectDataPrivate::readCustomFilter() +{ + QHelpDataCustomFilter filter; + filter.name = attributes().value(QLatin1String("name")).toString(); + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("filterAttribute")) + filter.filterAttributes.append(readElementText()); + else + raiseUnknownTokenError(); + } else if (isEndElement() && name() == QLatin1String("customFilter")) { + break; + } + } + customFilterList.append(filter); +} + +void QHelpProjectDataPrivate::readFilterSection() +{ + filterSectionList.append(QHelpDataFilterSection()); + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("filterAttribute")) + filterSectionList.last().addFilterAttribute(readElementText()); + else if (name() == QLatin1String("toc")) + readTOC(); + else if (name() == QLatin1String("keywords")) + readKeywords(); + else if (name() == QLatin1String("files")) + readFiles(); + else + raiseUnknownTokenError(); + } else if (isEndElement() && name() == QLatin1String("filterSection")) { + break; + } + } +} + +void QHelpProjectDataPrivate::readTOC() +{ + QStack contentStack; + QHelpDataContentItem *itm = 0; + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("section")) { + QString title = attributes().value(QLatin1String("title")).toString(); + QString ref = attributes().value(QLatin1String("ref")).toString(); + if (contentStack.isEmpty()) { + itm = new QHelpDataContentItem(0, title, ref); + filterSectionList.last().addContent(itm); + } else { + itm = new QHelpDataContentItem(contentStack.top(), title, ref); + } + contentStack.push(itm); + } else { + raiseUnknownTokenError(); + } + } else if (isEndElement()) { + if (name() == QLatin1String("section")) { + contentStack.pop(); + continue; + } else if (name() == QLatin1String("toc") && contentStack.isEmpty()) { + break; + } else { + raiseUnknownTokenError(); + } + } + } +} + +void QHelpProjectDataPrivate::readKeywords() +{ + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("keyword")) { + if (attributes().value(QLatin1String("ref")).toString().isEmpty() + || (attributes().value(QLatin1String("name")).toString().isEmpty() + && attributes().value(QLatin1String("id")).toString().isEmpty())) + raiseError(QCoreApplication::translate("QHelpProject", + "Missing attribute in keyword at line %1.") + .arg(lineNumber())); + filterSectionList.last() + .addIndex(QHelpDataIndexItem(attributes(). + value(QLatin1String("name")).toString(), + attributes().value(QLatin1String("id")).toString(), + attributes().value(QLatin1String("ref")).toString())); + } else { + raiseUnknownTokenError(); + } + } else if (isEndElement()) { + if (name() == QLatin1String("keyword")) + continue; + else if (name() == QLatin1String("keywords")) + break; + else + raiseUnknownTokenError(); + } + } +} + +void QHelpProjectDataPrivate::readFiles() +{ + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("file")) + addMatchingFiles(readElementText()); + else + raiseUnknownTokenError(); + } else if (isEndElement()) { + if (name() == QLatin1String("file")) + continue; + else if (name() == QLatin1String("files")) + break; + else + raiseUnknownTokenError(); + } + } +} + +// Expand file pattern and add matches into list. If the pattern does not match +// any files, insert the pattern itself so the QHelpGenerator will emit a +// meaningful warning later. +void QHelpProjectDataPrivate::addMatchingFiles(const QString &pattern) +{ + // The pattern matching is expensive, so we skip it if no + // wildcard symbols occur in the string. + if (!pattern.contains('?') && !pattern.contains('*') + && !pattern.contains('[') && !pattern.contains(']')) { + filterSectionList.last().addFile(pattern); + return; + } + + QFileInfo fileInfo(rootPath + '/' + pattern); + const QDir &dir = fileInfo.dir(); + const QString &path = dir.canonicalPath(); + + // QDir::entryList() is expensive, so we cache the results. + QMap::ConstIterator it = dirEntriesCache.find(path); + const QStringList &entries = it != dirEntriesCache.constEnd() ? + it.value() : dir.entryList(QDir::Files); + if (it == dirEntriesCache.constEnd()) + dirEntriesCache.insert(path, entries); + + bool matchFound = false; +#ifdef Q_OS_WIN + Qt::CaseSensitivity cs = Qt::CaseInsensitive; +#else + Qt::CaseSensitivity cs = Qt::CaseSensitive; +#endif + QRegExp regExp(fileInfo.fileName(), cs, QRegExp::Wildcard); + foreach (const QString &file, entries) { + if (regExp.exactMatch(file)) { + matchFound = true; + filterSectionList.last(). + addFile(QFileInfo(pattern).dir().path() + '/' + file); + } + } + if (!matchFound) + filterSectionList.last().addFile(pattern); +} + +bool QHelpProjectDataPrivate::hasValidSyntax(const QString &nameSpace, + const QString &vFolder) const +{ + const QLatin1Char slash('/'); + if (nameSpace.contains(slash) || vFolder.contains(slash)) + return false; + QUrl url; + const QLatin1String scheme("qthelp"); + url.setScheme(scheme); + const QString canonicalNamespace = nameSpace.toLower(); + url.setHost(canonicalNamespace); + url.setPath(vFolder); + + const QString expectedUrl(scheme + QLatin1String("://") + + canonicalNamespace + slash + vFolder); + return url.isValid() && url.toString() == expectedUrl; +} + +/*! + \internal + \class QHelpProjectData + \since 4.4 + \brief The QHelpProjectData class stores all information found + in a Qt help project file. + + The structure is filled with data by calling readData(). The + specified file has to have the Qt help project file format in + order to be read successfully. Possible reading errors can be + retrieved by calling errorMessage(). +*/ + +/*! + Constructs a Qt help project data structure. +*/ +QHelpProjectData::QHelpProjectData() +{ + d = new QHelpProjectDataPrivate; +} + +/*! + Destroys the help project data. +*/ +QHelpProjectData::~QHelpProjectData() +{ + delete d; +} + +/*! + Reads the file \a fileName and stores the help data. The file has to + have the Qt help project file format. Returns true if the file + was successfully read, otherwise false. + + \sa errorMessage() +*/ +bool QHelpProjectData::readData(const QString &fileName) +{ + d->rootPath = QFileInfo(fileName).absolutePath(); + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly)) { + d->errorMsg = QCoreApplication::translate("QHelpProject", + "The input file %1 could not be opened!").arg(fileName); + return false; + } + + d->readData(file.readAll()); + return !d->hasError(); +} + +/*! + Returns an error message if the reading of the Qt help project + file failed. Otherwise, an empty QString is returned. + + \sa readData() +*/ +QString QHelpProjectData::errorMessage() const +{ + if (d->hasError()) + return d->errorString(); + return d->errorMsg; +} + +/*! + \internal +*/ +QString QHelpProjectData::namespaceName() const +{ + return d->namespaceName; +} + +/*! + \internal +*/ +QString QHelpProjectData::virtualFolder() const +{ + return d->virtualFolder; +} + +/*! + \internal +*/ +QList QHelpProjectData::customFilters() const +{ + return d->customFilterList; +} + +/*! + \internal +*/ +QList QHelpProjectData::filterSections() const +{ + return d->filterSectionList; +} + +/*! + \internal +*/ +QMap QHelpProjectData::metaData() const +{ + return d->metaData; +} + +/*! + \internal +*/ +QString QHelpProjectData::rootPath() const +{ + return d->rootPath; +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/qhelpprojectdata_p.h b/src/assistant/lib/qhelpprojectdata_p.h new file mode 100644 index 000000000..64ae32505 --- /dev/null +++ b/src/assistant/lib/qhelpprojectdata_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPPROJECTDATA_H +#define QHELPPROJECTDATA_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhelp_global.h" +#include "qhelpdatainterface_p.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QHelpProjectDataPrivate; + +class QHELP_EXPORT QHelpProjectData : public QHelpDataInterface +{ +public: + QHelpProjectData(); + ~QHelpProjectData(); + + bool readData(const QString &fileName); + QString errorMessage() const; + + QString namespaceName() const; + QString virtualFolder() const; + QList customFilters() const; + QList filterSections() const; + QMap metaData() const; + QString rootPath() const; + +private: + QHelpProjectDataPrivate *d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/assistant/lib/qhelpsearchengine.cpp b/src/assistant/lib/qhelpsearchengine.cpp new file mode 100644 index 000000000..f8f8acf44 --- /dev/null +++ b/src/assistant/lib/qhelpsearchengine.cpp @@ -0,0 +1,450 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpenginecore.h" +#include "qhelpsearchengine.h" +#include "qhelpsearchquerywidget.h" +#include "qhelpsearchresultwidget.h" + +#include "qhelpsearchindexreader_p.h" +#if defined(QT_CLUCENE_SUPPORT) +# include "qhelpsearchindexreader_clucene_p.h" +# include "qhelpsearchindexwriter_clucene_p.h" +#else +# include "qhelpsearchindexreader_default_p.h" +# include "qhelpsearchindexwriter_default_p.h" +#endif + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +#if defined(QT_CLUCENE_SUPPORT) + using namespace fulltextsearch::clucene; +#else + using namespace fulltextsearch::std; +#endif + +class QHelpSearchEnginePrivate : public QObject +{ + Q_OBJECT + +signals: + void indexingStarted(); + void indexingFinished(); + + void searchingStarted(); + void searchingFinished(int hits); + +private: + QHelpSearchEnginePrivate(QHelpEngineCore *helpEngine) + : queryWidget(0) + , resultWidget(0) + , helpEngine(helpEngine) + { + indexReader = 0; + indexWriter = 0; + } + + ~QHelpSearchEnginePrivate() + { + delete indexReader; + delete indexWriter; + } + + int hitCount() const + { + int count = 0; + if (indexReader) + count = indexReader->hitCount(); + + return count; + } + + QList hits(int start, int end) const + { + return indexReader ? + indexReader->hits(start, end) : + QList(); + } + + void updateIndex(bool reindex = false) + { + if (helpEngine.isNull()) + return; + + if (!QFile::exists(QFileInfo(helpEngine->collectionFile()).path())) + return; + + if (!indexWriter) { + indexWriter = new QHelpSearchIndexWriter(); + + connect(indexWriter, SIGNAL(indexingStarted()), this, SIGNAL(indexingStarted())); + connect(indexWriter, SIGNAL(indexingFinished()), this, SIGNAL(indexingFinished())); + connect(indexWriter, SIGNAL(indexingFinished()), this, SLOT(optimizeIndex())); + } + + indexWriter->cancelIndexing(); + indexWriter->updateIndex(helpEngine->collectionFile(), + indexFilesFolder(), reindex); + } + + void cancelIndexing() + { + if (indexWriter) + indexWriter->cancelIndexing(); + } + + void search(const QList &queryList) + { + if (helpEngine.isNull()) + return; + + if (!QFile::exists(QFileInfo(helpEngine->collectionFile()).path())) + return; + + if (!indexReader) { +#if defined(QT_CLUCENE_SUPPORT) + indexReader = new QHelpSearchIndexReaderClucene(); +#else + indexReader = new QHelpSearchIndexReaderDefault(); +#endif // QT_CLUCENE_SUPPORT + connect(indexReader, SIGNAL(searchingStarted()), this, SIGNAL(searchingStarted())); + connect(indexReader, SIGNAL(searchingFinished(int)), this, SIGNAL(searchingFinished(int))); + } + + m_queryList = queryList; + indexReader->cancelSearching(); + indexReader->search(helpEngine->collectionFile(), indexFilesFolder(), queryList); + } + + void cancelSearching() + { + if (indexReader) + indexReader->cancelSearching(); + } + + QString indexFilesFolder() const + { + QString indexFilesFolder = QLatin1String(".fulltextsearch"); + if (helpEngine && !helpEngine->collectionFile().isEmpty()) { + QFileInfo fi(helpEngine->collectionFile()); + indexFilesFolder = fi.absolutePath() + QDir::separator() + + QLatin1Char('.') + + fi.fileName().left(fi.fileName().lastIndexOf(QLatin1String(".qhc"))); + } + return indexFilesFolder; + } + +private slots: + void optimizeIndex() + { +#if defined(QT_CLUCENE_SUPPORT) + if (indexWriter && !helpEngine.isNull()) { + indexWriter->optimizeIndex(); + } +#endif + } + +private: + friend class QHelpSearchEngine; + + QHelpSearchQueryWidget *queryWidget; + QHelpSearchResultWidget *resultWidget; + + fulltextsearch::QHelpSearchIndexReader *indexReader; + QHelpSearchIndexWriter *indexWriter; + + QPointer helpEngine; + + QList m_queryList; +}; + +#include "qhelpsearchengine.moc" + + +/*! + \class QHelpSearchQuery + \since 4.4 + \inmodule QtHelp + \brief The QHelpSearchQuery class contains the field name and the associated + search term + + The QHelpSearchQuery class contains the field name and the associated search + term. Depending on the field the search term might get split up into separate + terms to be parsed differently by the search engine. + + \sa QHelpSearchQueryWidget +*/ + +/*! + \fn QHelpSearchQuery::QHelpSearchQuery() + + Constructs a new empty QHelpSearchQuery. +*/ + +/*! + \fn QHelpSearchQuery::QHelpSearchQuery(FieldName field, const QStringList &wordList) + + Constructs a new QHelpSearchQuery and initializes it with the given \a field and \a wordList. +*/ + +/*! + \enum QHelpSearchQuery::FieldName + This enum type specifies the field names that are handled by the search engine. + + \value DEFAULT the default field provided by the search widget, several terms should be + split and stored in the word list except search terms enclosed in quotes. + \value FUZZY a field only provided in use with clucene. Terms should be split in separate + words and passed to the search engine. + \value WITHOUT a field only provided in use with clucene. Terms should be split in separate + words and passed to the search engine. + \value PHRASE a field only provided in use with clucene. Terms should not be split in separate + words. + \value ALL a field only provided in use with clucene. Terms should be split in separate + words and passed to the search engine + \value ATLEAST a field only provided in use with clucene. Terms should be split in separate + words and passed to the search engine +*/ + +/*! + \class QHelpSearchEngine + \since 4.4 + \inmodule QtHelp + \brief The QHelpSearchEngine class provides access to widgets reusable + to integrate fulltext search as well as to index and search documentation. + + Before the search engine can be used, one has to instantiate at least a + QHelpEngineCore object that needs to be passed to the search engines constructor. + This is required as the search engine needs to be connected to the help + engines setupFinished() signal to know when it can start to index documentation. + + After starting the indexing process the signal indexingStarted() is emitted and + on the end of the indexing process the indexingFinished() is emitted. To stop + the indexing one can call cancelIndexing(). + + While the indexing process has finished, the search engine can now be used to search + thru its index for a given term. To do this one may use the possibility of creating the + QHelpSearchQuery list by self or reuse the QHelpSearchQueryWidget which has the inbuild + functionality to set up a proper search queries list that get's passed to the search engines + search() function. + + After the list of querys has been passed to the search engine, the signal searchingStarted() + is emitted and after the search has finished the searchingFinished() signal is emitted. The + search process can be stopped by calling cancelSearching(). + + If the search succeeds, the searchingFinished() will be called with the search hits count, + which can be reused to fetch the search hits from the search engine. Calling the hits() + function with the range of hits you would like to get will return a list of the requested + SearchHits. They basically constist at the moment of a pair of strings where the values + of that pair are the documentation file path and the page title. + + To display the given hits use the QHelpSearchResultWidget or build up your own one if you need + more advanced functionality. Note that the QHelpSearchResultWidget can not be instantiated + directly, you must retrieve the widget from the search engine in use as all connections will be + established for you by the widget itself. +*/ + +/*! + \fn void QHelpSearchEngine::indexingStarted() + + This signal is emitted when indexing process is started. +*/ + +/*! + \fn void QHelpSearchEngine::indexingFinished() + + This signal is emitted when the indexing process is complete. +*/ + +/*! + \fn void QHelpSearchEngine::searchingStarted() + + This signal is emitted when the search process is started. +*/ + +/*! + \fn void QHelpSearchEngine::searchingFinished(int hits) + + This signal is emitted when the search process is complete. + The hit count is stored in \a hits. +*/ + +/*! + Constructs a new search engine with the given \a parent. The search engine + uses the given \a helpEngine to access the documentation that needs to be indexed. + The QHelpEngine's setupFinished() signal is automatically connected to the + QHelpSearchEngine's indexing function, so that new documentation will be indexed + after the signal is emitted. +*/ +QHelpSearchEngine::QHelpSearchEngine(QHelpEngineCore *helpEngine, QObject *parent) + : QObject(parent) +{ + d = new QHelpSearchEnginePrivate(helpEngine); + + connect(helpEngine, SIGNAL(setupFinished()), this, SLOT(indexDocumentation())); + + connect(d, SIGNAL(indexingStarted()), this, SIGNAL(indexingStarted())); + connect(d, SIGNAL(indexingFinished()), this, SIGNAL(indexingFinished())); + connect(d, SIGNAL(searchingStarted()), this, SIGNAL(searchingStarted())); + connect(d, SIGNAL(searchingFinished(int)), this, SIGNAL(searchingFinished(int))); +} + +/*! + Destructs the search engine. +*/ +QHelpSearchEngine::~QHelpSearchEngine() +{ + delete d; +} + +/*! + Returns a widget to use as input widget. Depending on your search engine + configuration you will get a different widget with more or less subwidgets. +*/ +QHelpSearchQueryWidget* QHelpSearchEngine::queryWidget() +{ + if (!d->queryWidget) + d->queryWidget = new QHelpSearchQueryWidget(); + + return d->queryWidget; +} + +/*! + Returns a widget that can hold and display the search results. +*/ +QHelpSearchResultWidget* QHelpSearchEngine::resultWidget() +{ + if (!d->resultWidget) + d->resultWidget = new QHelpSearchResultWidget(this); + + return d->resultWidget; +} + +/*! + \obsolete + Returns the amount of hits the search engine found. + \sa hitCount() +*/ +int QHelpSearchEngine::hitsCount() const +{ + return d->hitCount(); +} + +/*! + \since 4.6 + Returns the amount of hits the search engine found. +*/ +int QHelpSearchEngine::hitCount() const +{ + return d->hitCount(); +} + +/*! + \typedef QHelpSearchEngine::SearchHit + + Typedef for QPair. + The values of that pair are the documentation file path and the page title. + + \sa hits() +*/ + +/*! + Returns a list of search hits within the range of \a start \a end. +*/ +QList QHelpSearchEngine::hits(int start, int end) const +{ + return d->hits(start, end); +} + +/*! + Returns the list of queries last searched for. + \since 4.5 +*/ +QList QHelpSearchEngine::query() const +{ + return d->m_queryList; +} + +/*! + Forces the search engine to reindex all documentation files. +*/ +void QHelpSearchEngine::reindexDocumentation() +{ + d->updateIndex(true); +} + +/*! + Stops the indexing process. +*/ +void QHelpSearchEngine::cancelIndexing() +{ + d->cancelIndexing(); +} + +/*! + Stops the search process. +*/ +void QHelpSearchEngine::cancelSearching() +{ + d->cancelSearching(); +} + +/*! + Starts the search process using the given list of queries \a queryList + build by the search field name and the values to search for. +*/ +void QHelpSearchEngine::search(const QList &queryList) +{ + d->search(queryList); +} + +void QHelpSearchEngine::indexDocumentation() +{ + d->updateIndex(); +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/qhelpsearchengine.h b/src/assistant/lib/qhelpsearchengine.h new file mode 100644 index 000000000..baceb7057 --- /dev/null +++ b/src/assistant/lib/qhelpsearchengine.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHENGINE_H +#define QHELPSEARCHENGINE_H + +#include + +#include +#include +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +class QHelpEngineCore; +class QHelpSearchQueryWidget; +class QHelpSearchResultWidget; +class QHelpSearchEnginePrivate; + +class QHELP_EXPORT QHelpSearchQuery +{ +public: + enum FieldName { DEFAULT = 0, FUZZY, WITHOUT, PHRASE, ALL, ATLEAST }; + + QHelpSearchQuery() + : fieldName(DEFAULT) { wordList.clear(); } + QHelpSearchQuery(FieldName field, const QStringList &wordList) + : fieldName(field), wordList(wordList) {} + + FieldName fieldName; + QStringList wordList; +}; + +class QHELP_EXPORT QHelpSearchEngine : public QObject +{ + Q_OBJECT + +public: + explicit QHelpSearchEngine(QHelpEngineCore *helpEngine, + QObject *parent = 0); + ~QHelpSearchEngine(); + + QHelpSearchQueryWidget* queryWidget(); + QHelpSearchResultWidget* resultWidget(); + +#ifdef QT_DEPRECATED + QT_DEPRECATED int hitsCount() const; +#endif + int hitCount() const; + + typedef QPair SearchHit; + QList hits(int start, int end) const; + + QList query() const; + +public Q_SLOTS: + void reindexDocumentation(); + void cancelIndexing(); + + void search(const QList &queryList); + void cancelSearching(); + +Q_SIGNALS: + void indexingStarted(); + void indexingFinished(); + + void searchingStarted(); + void searchingFinished(int hits); + +private Q_SLOTS: + void indexDocumentation(); + +private: + QHelpSearchEnginePrivate *d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QHELPSEARCHENGINE_H diff --git a/src/assistant/lib/qhelpsearchindex_default.cpp b/src/assistant/lib/qhelpsearchindex_default.cpp new file mode 100644 index 000000000..9974f618d --- /dev/null +++ b/src/assistant/lib/qhelpsearchindex_default.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpsearchindex_default_p.h" + +QT_BEGIN_NAMESPACE + +QDataStream &operator>>(QDataStream &s, Document &l) +{ + s >> l.docNumber; + s >> l.frequency; + return s; +} + +QDataStream &operator<<(QDataStream &s, const Document &l) +{ + s << qint16(l.docNumber); + s << qint16(l.frequency); + return s; +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/qhelpsearchindex_default_p.h b/src/assistant/lib/qhelpsearchindex_default_p.h new file mode 100644 index 000000000..868609960 --- /dev/null +++ b/src/assistant/lib/qhelpsearchindex_default_p.h @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHINDEXDEFAULT_H +#define QHELPSEARCHINDEXDEFAULT_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace QtHelpInternal { + +struct Document { + Document(qint16 d, qint16 f) + : docNumber(d), frequency(f) {} + + Document() + : docNumber(-1), frequency(0) {} + + bool operator==(const Document &doc) const { + return docNumber == doc.docNumber; + } + bool operator<(const Document &doc) const { + return frequency > doc.frequency; + } + bool operator<=(const Document &doc) const { + return frequency >= doc.frequency; + } + bool operator>(const Document &doc) const { + return frequency < doc.frequency; + } + + qint16 docNumber; + qint16 frequency; +}; + +struct DocumentInfo : public Document { + DocumentInfo() + : Document(-1, 0), documentTitle(QString()), documentUrl(QString()) {} + + DocumentInfo(qint16 d, qint16 f, const QString &title, const QString &url) + : Document(d, f), documentTitle(title), documentUrl(url) {} + + DocumentInfo(const Document &document, const QString &title, const QString &url) + : Document(document.docNumber, document.frequency), documentTitle(title), documentUrl(url) {} + + QString documentTitle; + QString documentUrl; +}; + +struct Entry { + Entry(qint16 d) { documents.append(Document(d, 1)); } + Entry(QVector l) : documents(l) {} + + QVector documents; +}; + +struct PosEntry { + PosEntry(int p) { positions.append(p); } + QList positions; +}; + +struct Term { + Term() : frequency(-1) {} + Term(const QString &t, int f, QVector l) : term(t), frequency(f), documents(l) {} + QString term; + int frequency; + QVectordocuments; + bool operator<(const Term &i2) const { return frequency < i2.frequency; } +}; + +struct TermInfo { + TermInfo() : frequency(-1) {} + TermInfo(const QString &t, int f, QVector l) + : term(t), frequency(f), documents(l) {} + + bool operator<(const TermInfo &i2) const { return frequency < i2.frequency; } + + QString term; + int frequency; + QVectordocuments; +}; + +} // namespace QtHelpInternal + +using QtHelpInternal::Document; +using QtHelpInternal::DocumentInfo; +using QtHelpInternal::Entry; +using QtHelpInternal::PosEntry; +using QtHelpInternal::Term; +using QtHelpInternal::TermInfo; + +QDataStream &operator>>(QDataStream &s, Document &l); +QDataStream &operator<<(QDataStream &s, const Document &l); + +QT_END_NAMESPACE + +#endif // QHELPSEARCHINDEXDEFAULT_H diff --git a/src/assistant/lib/qhelpsearchindexreader.cpp b/src/assistant/lib/qhelpsearchindexreader.cpp new file mode 100644 index 000000000..1ee356d2f --- /dev/null +++ b/src/assistant/lib/qhelpsearchindexreader.cpp @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpsearchindexreader_p.h" + +QT_BEGIN_NAMESPACE + +namespace fulltextsearch { + +QHelpSearchIndexReader::QHelpSearchIndexReader() + : QThread() + , m_cancel(false) +{ + // nothing todo +} + +QHelpSearchIndexReader::~QHelpSearchIndexReader() +{ + mutex.lock(); + this->m_cancel = true; + mutex.unlock(); + + wait(); +} + +void QHelpSearchIndexReader::cancelSearching() +{ + mutex.lock(); + this->m_cancel = true; + mutex.unlock(); +} + +void QHelpSearchIndexReader::search(const QString &collectionFile, const QString &indexFilesFolder, + const QList &queryList) +{ + wait(); + + this->hitList.clear(); + this->m_cancel = false; + this->m_query = queryList; + this->m_collectionFile = collectionFile; + this->m_indexFilesFolder = indexFilesFolder; + + start(QThread::NormalPriority); +} + +int QHelpSearchIndexReader::hitCount() const +{ + QMutexLocker lock(&mutex); + return hitList.count(); +} + +QList QHelpSearchIndexReader::hits(int start, + int end) const +{ + QList hits; + QMutexLocker lock(&mutex); + for (int i = start; i < end && i < hitList.count(); ++i) + hits.append(hitList.at(i)); + return hits; +} + + +} // namespace fulltextsearch + +QT_END_NAMESPACE diff --git a/src/assistant/lib/qhelpsearchindexreader_clucene.cpp b/src/assistant/lib/qhelpsearchindexreader_clucene.cpp new file mode 100644 index 000000000..537e1d765 --- /dev/null +++ b/src/assistant/lib/qhelpsearchindexreader_clucene.cpp @@ -0,0 +1,481 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "fulltextsearch/qindexreader_p.h" +#include "fulltextsearch/qqueryparser_p.h" +#include "fulltextsearch/qsearchable_p.h" +#include "qclucenefieldnames_p.h" +#include "qhelpenginecore.h" + +#include "qhelpsearchindexreader_clucene_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace fulltextsearch { +namespace clucene { + +QHelpSearchIndexReaderClucene::QHelpSearchIndexReaderClucene() + : QHelpSearchIndexReader() +{ + // nothing todo +} + +QHelpSearchIndexReaderClucene::~QHelpSearchIndexReaderClucene() +{ +} + + +void QHelpSearchIndexReaderClucene::run() +{ + mutex.lock(); + + if (m_cancel) { + mutex.unlock(); + return; + } + + const QString collectionFile(this->m_collectionFile); + const QList &queryList = this->m_query; + const QString indexPath(m_indexFilesFolder); + + mutex.unlock(); + + QHelpEngineCore engine(collectionFile, 0); + if (!engine.setupData()) + return; + + QFileInfo fInfo(indexPath); + if (fInfo.exists() && !fInfo.isWritable()) { + qWarning("Full Text Search, could not read index (missing permissions)."); + return; + } + + if(QCLuceneIndexReader::indexExists(indexPath)) { + mutex.lock(); + if (m_cancel) { + mutex.unlock(); + return; + } + mutex.unlock(); + + emit searchingStarted(); + +#if !defined(QT_NO_EXCEPTIONS) + try { +#endif + QCLuceneBooleanQuery booleanQueryTitle; + QCLuceneBooleanQuery booleanQueryContent; + QCLuceneStandardAnalyzer analyzer; + const QStringList& attribList = + engine.filterAttributes(engine.currentFilter()); + bool titleQueryIsValid = buildQuery(queryList, TitleTokenizedField, + attribList, booleanQueryTitle, analyzer); + bool contentQueryIsValid = buildQuery(queryList, ContentField, + attribList, booleanQueryContent, analyzer); + if (!titleQueryIsValid && !contentQueryIsValid) { + emit searchingFinished(0); + return; + } + + QCLuceneIndexSearcher indexSearcher(indexPath); + + // QCLuceneHits object must be allocated on the heap, because + // there is no default constructor. + QSharedPointer titleHits; + QSharedPointer contentHits; + if (titleQueryIsValid) { + titleHits = QSharedPointer(new QCLuceneHits( + indexSearcher.search(booleanQueryTitle))); + } + if (contentQueryIsValid) { + contentHits = QSharedPointer(new QCLuceneHits( + indexSearcher.search(booleanQueryContent))); + } + bool boost = true; + if ((titleHits.isNull() || titleHits->length() == 0) + && (contentHits.isNull() || contentHits->length() == 0)) { + booleanQueryTitle = QCLuceneBooleanQuery(); + booleanQueryContent = QCLuceneBooleanQuery(); + titleQueryIsValid = + buildTryHarderQuery(queryList, TitleTokenizedField, + attribList, booleanQueryTitle, analyzer); + contentQueryIsValid = + buildTryHarderQuery(queryList, ContentField, attribList, + booleanQueryContent, analyzer); + if (!titleQueryIsValid && !contentQueryIsValid) { + emit searchingFinished(0); + return; + } + if (titleQueryIsValid) { + titleHits = QSharedPointer(new QCLuceneHits( + indexSearcher.search(booleanQueryTitle))); + } + if (contentQueryIsValid) { + contentHits = QSharedPointer(new QCLuceneHits( + indexSearcher.search(booleanQueryContent))); + } + boost = false; + } + QList > cluceneHitsList; + if (!titleHits.isNull()) + cluceneHitsList.append(titleHits); + if (!contentHits.isNull()) + cluceneHitsList.append(contentHits); + + QSet pathSet; + QCLuceneDocument document; + const QStringList namespaceList = engine.registeredDocumentations(); + + foreach (const QSharedPointer &hits, cluceneHitsList) { + for (qint32 i = 0; i < hits->length(); i++) { + document = hits->document(i); + const QString path = document.get(PathField); + if (!pathSet.contains(path) && namespaceList.contains( + document.get(NamespaceField), Qt::CaseInsensitive)) { + pathSet.insert(path); + hitList.append(qMakePair(path, document.get(TitleField))); + } + document.clear(); + + mutex.lock(); + if (m_cancel) { + mutex.unlock(); + emit searchingFinished(0); + return; + } + mutex.unlock(); + } + } + + indexSearcher.close(); + const int count = hitList.count(); + if ((count > 0) && boost) + boostSearchHits(engine, hitList, queryList); + emit searchingFinished(hitList.count()); + +#if !defined(QT_NO_EXCEPTIONS) + } catch(...) { + mutex.lock(); + hitList.clear(); + mutex.unlock(); + emit searchingFinished(0); + } +#endif + } +} + +bool QHelpSearchIndexReaderClucene::buildQuery( + const QList &queries, const QString &fieldName, + const QStringList &filterAttributes, QCLuceneBooleanQuery &booleanQuery, + QCLuceneAnalyzer &analyzer) +{ + bool queryIsValid = false; + foreach (const QHelpSearchQuery &query, queries) { + if (fieldName != ContentField && isNegativeQuery(query)) { + queryIsValid = false; + break; + } + switch (query.fieldName) { + case QHelpSearchQuery::FUZZY: + if (addFuzzyQuery(query, fieldName, booleanQuery, analyzer)) + queryIsValid = true; + break; + case QHelpSearchQuery::WITHOUT: + if (fieldName != ContentField) + return false; + if (addWithoutQuery(query, fieldName, booleanQuery)) + queryIsValid = true; + break; + case QHelpSearchQuery::PHRASE: + if (addPhraseQuery(query, fieldName, booleanQuery)) + queryIsValid = true; + break; + case QHelpSearchQuery::ALL: + if (addAllQuery(query, fieldName, booleanQuery)) + queryIsValid = true; + break; + case QHelpSearchQuery::DEFAULT: + if (addDefaultQuery(query, fieldName, true, booleanQuery, analyzer)) + queryIsValid = true; + break; + case QHelpSearchQuery::ATLEAST: + if (addAtLeastQuery(query, fieldName, booleanQuery, analyzer)) + queryIsValid = true; + break; + default: + Q_ASSERT(!"Invalid field name"); + } + } + + if (queryIsValid && !filterAttributes.isEmpty()) { + queryIsValid = + addAttributesQuery(filterAttributes, booleanQuery, analyzer); + } + + return queryIsValid; +} + +bool QHelpSearchIndexReaderClucene::buildTryHarderQuery( + const QList &queries, const QString &fieldName, + const QStringList &filterAttributes, QCLuceneBooleanQuery &booleanQuery, + QCLuceneAnalyzer &analyzer) +{ + if (queries.isEmpty()) + return false; + const QHelpSearchQuery &query = queries.front(); + if (query.fieldName != QHelpSearchQuery::DEFAULT) + return false; + if (isNegativeQuery(query)) + return false; + if (!addDefaultQuery(query, fieldName, false, booleanQuery, analyzer)) + return false; + if (filterAttributes.isEmpty()) + return true; + return addAttributesQuery(filterAttributes, booleanQuery, analyzer); +} + +bool QHelpSearchIndexReaderClucene::isNegativeQuery(const QHelpSearchQuery &query) const +{ + const QString &search = query.wordList.join(" "); + return search.contains('!') || search.contains('-') + || search.contains(QLatin1String(" NOT ")); +} + +bool QHelpSearchIndexReaderClucene::addFuzzyQuery(const QHelpSearchQuery &query, + const QString &fieldName, QCLuceneBooleanQuery &booleanQuery, + QCLuceneAnalyzer &analyzer) +{ + bool queryIsValid = false; + const QLatin1String fuzzy("~"); + foreach (const QString &term, query.wordList) { + if (!term.isEmpty()) { + QCLuceneQuery *lQuery = + QCLuceneQueryParser::parse(term + fuzzy, fieldName, analyzer); + if (lQuery != 0) { + booleanQuery.add(lQuery, true, false, false); + queryIsValid = true; + } + } + } + return queryIsValid; +} + +bool QHelpSearchIndexReaderClucene::addWithoutQuery(const QHelpSearchQuery &query, + const QString &fieldName, QCLuceneBooleanQuery &booleanQuery) +{ + bool queryIsValid = false; + const QStringList &stopWords = QCLuceneStopAnalyzer().englishStopWords(); + foreach (const QString &term, query.wordList) { + if (stopWords.contains(term, Qt::CaseInsensitive)) + continue; + QCLuceneQuery *lQuery = new QCLuceneTermQuery(QCLuceneTerm( + fieldName, term.toLower())); + booleanQuery.add(lQuery, true, false, true); + queryIsValid = true; + } + return queryIsValid; +} + +bool QHelpSearchIndexReaderClucene::addPhraseQuery(const QHelpSearchQuery &query, + const QString &fieldName, QCLuceneBooleanQuery &booleanQuery) +{ + bool queryIsValid = false; + const QString &term = query.wordList.at(0).toLower(); + if (term.contains(QLatin1Char(' '))) { + const QStringList termList = term.split(QLatin1String(" ")); + QCLucenePhraseQuery *q = new QCLucenePhraseQuery(); + const QStringList stopWords = QCLuceneStopAnalyzer().englishStopWords(); + foreach (const QString &term, termList) { + if (!stopWords.contains(term, Qt::CaseInsensitive)) + q->addTerm(QCLuceneTerm(fieldName, term.toLower())); + } + if (!q->getTerms().isEmpty()) { + booleanQuery.add(q, true, true, false); + queryIsValid = true; + } + } else { + QCLuceneQuery *lQuery = new QCLuceneTermQuery(QCLuceneTerm( + fieldName, term.toLower())); + booleanQuery.add(lQuery, true, true, false); + queryIsValid = true; + } + return queryIsValid; +} + +bool QHelpSearchIndexReaderClucene::addAllQuery(const QHelpSearchQuery &query, + const QString &fieldName, QCLuceneBooleanQuery &booleanQuery) +{ + bool queryIsValid = false; + const QStringList &stopWords = QCLuceneStopAnalyzer().englishStopWords(); + foreach (const QString &term, query.wordList) { + if (stopWords.contains(term, Qt::CaseInsensitive)) + continue; + QCLuceneQuery *lQuery = new QCLuceneTermQuery(QCLuceneTerm( + fieldName, term.toLower())); + booleanQuery.add(lQuery, true, true, false); + queryIsValid = true; + } + return queryIsValid; +} + +bool QHelpSearchIndexReaderClucene::addDefaultQuery(const QHelpSearchQuery &query, + const QString &fieldName, bool allTermsRequired, + QCLuceneBooleanQuery &booleanQuery, + QCLuceneAnalyzer &analyzer) +{ + bool queryIsValid = false; + foreach (const QString &term, query.wordList) { + QCLuceneQuery *lQuery = + QCLuceneQueryParser::parse(term.toLower(), fieldName, analyzer); + if (lQuery) { + booleanQuery.add(lQuery, true, allTermsRequired, false); + queryIsValid = true; + } + } + return queryIsValid; +} + +bool QHelpSearchIndexReaderClucene::addAtLeastQuery( + const QHelpSearchQuery &query, const QString &fieldName, + QCLuceneBooleanQuery &booleanQuery, QCLuceneAnalyzer &analyzer) +{ + bool queryIsValid = false; + foreach (const QString &term, query.wordList) { + if (!term.isEmpty()) { + QCLuceneQuery *lQuery = + QCLuceneQueryParser::parse(term, fieldName, analyzer); + if (lQuery) { + booleanQuery.add(lQuery, true, false, false); + queryIsValid = true; + } + } + } + return queryIsValid; +} + +bool QHelpSearchIndexReaderClucene::addAttributesQuery( + const QStringList &filterAttributes, QCLuceneBooleanQuery &booleanQuery, + QCLuceneAnalyzer &analyzer) +{ + QCLuceneQuery* lQuery = QCLuceneQueryParser::parse(QLatin1String("+") + + filterAttributes.join(QLatin1String(" +")), AttributeField, analyzer); + if (!lQuery) + return false; + booleanQuery.add(lQuery, true, true, false); + return true; +} + +void QHelpSearchIndexReaderClucene::boostSearchHits(const QHelpEngineCore &engine, + QList &hitList, const QList &queryList) +{ + foreach (const QHelpSearchQuery &query, queryList) { + if (query.fieldName != QHelpSearchQuery::DEFAULT) + continue; + + QString joinedQuery = query.wordList.join(QLatin1String(" ")); + + QCLuceneStandardAnalyzer analyzer; + QCLuceneQuery *parsedQuery = QCLuceneQueryParser::parse( + joinedQuery, ContentField, analyzer); + + if (parsedQuery) { + joinedQuery = parsedQuery->toString(); + delete parsedQuery; + } + + const QString contentString(ContentField + QLatin1String(":")); + int length = contentString.length(); + int index = joinedQuery.indexOf(contentString); + + QString term; + int nextIndex = 0; + QStringList searchTerms; + while (index != -1) { + nextIndex = joinedQuery.indexOf(contentString, index + 1); + term = joinedQuery.mid(index + length, nextIndex - (length + index)).simplified(); + if (term.startsWith(QLatin1String("\"")) + && term.endsWith(QLatin1String("\""))) { + searchTerms.append(term.remove(QLatin1String("\""))); + } else { + searchTerms += term.split(QLatin1Char(' ')); + } + index = nextIndex; + } + searchTerms.removeDuplicates(); + + int count = qMin(75, hitList.count()); + QMap hitMap; + for (int i = 0; i < count; ++i) { + const QHelpSearchEngine::SearchHit &hit = hitList.at(i); + QString data = QString::fromUtf8(engine.fileData(hit.first)); + + int counter = 0; + foreach (const QString &term, searchTerms) + counter += data.count(term, Qt::CaseInsensitive); + hitMap.insertMulti(counter, hit); + } + + QList boostedList; + QMap::const_iterator it = hitMap.constEnd(); + do { + --it; + boostedList.append(it.value()); + } while (it != hitMap.constBegin()); + boostedList += hitList.mid(count, hitList.count()); + mutex.lock(); + hitList = boostedList; + mutex.unlock(); + } +} + +} // namespace clucene +} // namespace fulltextsearch + +QT_END_NAMESPACE diff --git a/src/assistant/lib/qhelpsearchindexreader_clucene_p.h b/src/assistant/lib/qhelpsearchindexreader_clucene_p.h new file mode 100644 index 000000000..dec18a07b --- /dev/null +++ b/src/assistant/lib/qhelpsearchindexreader_clucene_p.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHINDEXREADERCLUCENE_H +#define QHELPSEARCHINDEXREADERCLUCENE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +#include "fulltextsearch/qanalyzer_p.h" +#include "fulltextsearch/qquery_p.h" +#include "qhelpsearchindexreader_p.h" + +QT_BEGIN_NAMESPACE + +namespace fulltextsearch { +namespace clucene { + +class QHelpSearchIndexReaderClucene : public QHelpSearchIndexReader +{ + Q_OBJECT + +public: + QHelpSearchIndexReaderClucene(); + ~QHelpSearchIndexReaderClucene(); + +private: + void run(); + void boostSearchHits(const QHelpEngineCore &engine, QList &hitList, + const QList &queryList); + bool buildQuery(const QList &queries, + const QString &fieldName, + const QStringList &filterAttributes, + QCLuceneBooleanQuery &booleanQuery, + QCLuceneAnalyzer &analyzer); + bool buildTryHarderQuery(const QList &queries, + const QString &fieldName, + const QStringList &filterAttributes, + QCLuceneBooleanQuery &booleanQuery, + QCLuceneAnalyzer &analyzer); + bool addFuzzyQuery(const QHelpSearchQuery &query, const QString &fieldName, + QCLuceneBooleanQuery &booleanQuery, QCLuceneAnalyzer &analyzer); + bool addWithoutQuery(const QHelpSearchQuery &query, const QString &fieldName, + QCLuceneBooleanQuery &booleanQuery); + bool addPhraseQuery(const QHelpSearchQuery &query, const QString &fieldName, + QCLuceneBooleanQuery &booleanQuery); + bool addAllQuery(const QHelpSearchQuery &query, const QString &fieldName, + QCLuceneBooleanQuery &booleanQuery); + bool addDefaultQuery(const QHelpSearchQuery &query, const QString &fieldName, + bool allTermsRequired, QCLuceneBooleanQuery &booleanQuery, + QCLuceneAnalyzer &analyzer); + bool addAtLeastQuery(const QHelpSearchQuery &query, const QString &fieldName, + QCLuceneBooleanQuery &booleanQuery, QCLuceneAnalyzer &analyzer); + bool addAttributesQuery(const QStringList &filterAttributes, + QCLuceneBooleanQuery &booleanQuery, QCLuceneAnalyzer &analyzer); + bool isNegativeQuery(const QHelpSearchQuery &query) const; +}; + +} // namespace clucene +} // namespace fulltextsearch + +QT_END_NAMESPACE + +#endif // QHELPSEARCHINDEXREADERCLUCENE_H diff --git a/src/assistant/lib/qhelpsearchindexreader_default.cpp b/src/assistant/lib/qhelpsearchindexreader_default.cpp new file mode 100644 index 000000000..e49fdfcbd --- /dev/null +++ b/src/assistant/lib/qhelpsearchindexreader_default.cpp @@ -0,0 +1,612 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpenginecore.h" +#include "qhelpsearchindexreader_default_p.h" + +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace fulltextsearch { +namespace std { + +namespace { + QStringList split( const QString &str ) + { + QStringList lst; + int j = 0; + int i = str.indexOf(QLatin1Char('*'), j ); + + if (str.startsWith(QLatin1String("*"))) + lst << QLatin1String("*"); + + while ( i != -1 ) { + if ( i > j && i <= (int)str.length() ) { + lst << str.mid( j, i - j ); + lst << QLatin1String("*"); + } + j = i + 1; + i = str.indexOf(QLatin1Char('*'), j ); + } + + int l = str.length() - 1; + if ( str.mid( j, l - j + 1 ).length() > 0 ) + lst << str.mid( j, l - j + 1 ); + + return lst; + } +} + + +Reader::Reader() + : indexPath(QString()) + , indexFile(QString()) + , documentFile(QString()) +{ + termList.clear(); + indexTable.clear(); + searchIndexTable.clear(); +} + +Reader::~Reader() +{ + reset(); + searchIndexTable.clear(); +} + +bool Reader::readIndex() +{ + if (indexTable.contains(indexFile)) + return true; + + QFile idxFile(indexFile); + if (!idxFile.open(QFile::ReadOnly)) + return false; + + QString key; + int numOfDocs; + EntryTable entryTable; + QVector docs; + QDataStream dictStream(&idxFile); + while (!dictStream.atEnd()) { + dictStream >> key; + dictStream >> numOfDocs; + docs.resize(numOfDocs); + dictStream >> docs; + entryTable.insert(key, new Entry(docs)); + } + idxFile.close(); + + if (entryTable.isEmpty()) + return false; + + QFile docFile(documentFile); + if (!docFile.open(QFile::ReadOnly)) + return false; + + QString title, url; + DocumentList documentList; + QDataStream docStream(&docFile); + while (!docStream.atEnd()) { + docStream >> title; + docStream >> url; + documentList.append(QStringList(title) << url); + } + docFile.close(); + + if (documentList.isEmpty()) { + cleanupIndex(entryTable); + return false; + } + + indexTable.insert(indexFile, Index(entryTable, documentList)); + return true; +} + +bool Reader::initCheck() const +{ + return !searchIndexTable.isEmpty(); +} + +void Reader::setIndexPath(const QString &path) +{ + indexPath = path; +} + +void Reader::filterFilesForAttributes(const QStringList &attributes) +{ + searchIndexTable.clear(); + for(IndexTable::ConstIterator it = indexTable.begin(); it != indexTable.end(); ++it) { + const QString fileName = it.key(); + bool containsAll = true; + QStringList split = fileName.split(QLatin1String("@")); + foreach (const QString &attribute, attributes) { + if (!split.contains(attribute, Qt::CaseInsensitive)) { + containsAll = false; + break; + } + } + + if (containsAll) + searchIndexTable.insert(fileName, it.value()); + } +} + +void Reader::setIndexFile(const QString &namespaceName, const QString &attributes) +{ + QString extension = namespaceName + QLatin1String("@") + attributes; + indexFile = indexPath + QLatin1String("/indexdb40.") + extension; + documentFile = indexPath + QLatin1String("/indexdoc40.") + extension; +} + +bool Reader::splitSearchTerm(const QString &searchTerm, QStringList *terms, + QStringList *termSeq, QStringList *seqWords) +{ + QString term = searchTerm; + + term = term.simplified(); + term = term.replace(QLatin1String("\'"), QLatin1String("\"")); + term = term.replace(QLatin1String("`"), QLatin1String("\"")); + term = term.replace(QLatin1String("-"), QLatin1String(" ")); + term = term.replace(QRegExp(QLatin1String("\\s[\\S]?\\s")), QLatin1String(" ")); + + *terms = term.split(QLatin1Char(' ')); + QStringList::iterator it = terms->begin(); + for (; it != terms->end(); ++it) { + (*it) = (*it).simplified(); + (*it) = (*it).toLower(); + (*it) = (*it).replace(QLatin1String("\""), QLatin1String("")); + } + + if (term.contains(QLatin1Char('\"'))) { + if ((term.count(QLatin1Char('\"')))%2 == 0) { + int beg = 0; + int end = 0; + QString s; + beg = term.indexOf(QLatin1Char('\"'), beg); + while (beg != -1) { + beg++; + end = term.indexOf(QLatin1Char('\"'), beg); + s = term.mid(beg, end - beg); + s = s.toLower(); + s = s.simplified(); + if (s.contains(QLatin1Char('*'))) { + qWarning("Full Text Search, using a wildcard within phrases is not allowed."); + return false; + } + *seqWords += s.split(QLatin1Char(' ')); + *termSeq << s; + beg = term.indexOf(QLatin1Char('\"'), end + 1); + } + } else { + qWarning("Full Text Search, the closing quotation mark is missing."); + return false; + } + } + + return true; +} + +void Reader::searchInIndex(const QStringList &terms) +{ + foreach (const QString &term, terms) { + QVector documents; + + for(IndexTable::ConstIterator it = searchIndexTable.begin(); + it != searchIndexTable.end(); ++it) { + EntryTable entryTable = it.value().first; + DocumentList documentList = it.value().second; + + if (term.contains(QLatin1Char('*'))) + documents = setupDummyTerm(getWildcardTerms(term, entryTable), entryTable); + else if (entryTable.value(term)) + documents = entryTable.value(term)->documents; + else + continue; + + if (!documents.isEmpty()) { + DocumentInfo info; + QString title, url; + QVector documentsInfo; + foreach(const Document &doc, documents) { + info.docNumber = doc.docNumber; + info.frequency = doc.frequency; + info.documentUrl = documentList.at(doc.docNumber).at(1); + info.documentTitle = documentList.at(doc.docNumber).at(0); + documentsInfo.append(info); + } + + bool found = false; + for(QList::Iterator tit = termList.begin(); + tit != termList.end(); ++tit) { + TermInfo *t = &(*tit); + if(t->term == term) { + t->documents += documentsInfo; + t->frequency += documentsInfo.count(); + found = true; break; + } + } + if (!found) + termList.append(TermInfo(term, documentsInfo.count(), documentsInfo)); + } + } + } + qSort(termList); +} + +QVector Reader::hits() +{ + QVector documents; + if (!termList.count()) + return documents; + + documents = termList.takeFirst().documents; + for(QList::Iterator it = termList.begin(); it != termList.end(); ++it) { + TermInfo *t = &(*it); + QVector docs = t->documents; + for(QVector::Iterator minDoc_it = documents.begin(); + minDoc_it != documents.end(); ) { + bool found = false; + for (QVector::ConstIterator doc_it = docs.constBegin(); + doc_it != docs.constEnd(); ++doc_it ) { + if ( (*minDoc_it).docNumber == (*doc_it).docNumber ) { + (*minDoc_it).frequency += (*doc_it).frequency; + found = true; + break; + } + } + if (!found) + minDoc_it = documents.erase(minDoc_it); + else + ++minDoc_it; + } + } + + qSort(documents); + return documents; +} + +bool Reader::searchForPattern(const QStringList &patterns, const QStringList &words, + const QByteArray &data) +{ + if (data.isEmpty()) + return false; + + for(QHash::ConstIterator mit = + miniIndex.begin(); mit != miniIndex.end(); ++mit) { + delete mit.value(); + } + miniIndex.clear(); + + wordNum = 3; + QStringList::ConstIterator cIt = words.begin(); + for ( ; cIt != words.end(); ++cIt ) + miniIndex.insert(*cIt, new PosEntry(0)); + + QTextStream s(data); + QString text = s.readAll(); + bool valid = true; + const QChar *buf = text.unicode(); + QChar str[64]; + QChar c = buf[0]; + int j = 0; + int i = 0; + while ( j < text.length() ) { + if ( c == QLatin1Char('<') || c == QLatin1Char('&') ) { + valid = false; + if ( i > 1 ) + buildMiniIndex( QString(str,i) ); + i = 0; + c = buf[++j]; + continue; + } + if ( ( c == QLatin1Char('>') || c == QLatin1Char(';') ) && !valid ) { + valid = true; + c = buf[++j]; + continue; + } + if ( !valid ) { + c = buf[++j]; + continue; + } + if ( ( c.isLetterOrNumber() || c == QLatin1Char('_') ) && i < 63 ) { + str[i] = c.toLower(); + ++i; + } else { + if ( i > 1 ) + buildMiniIndex( QString(str,i) ); + i = 0; + } + c = buf[++j]; + } + if ( i > 1 ) + buildMiniIndex( QString(str,i) ); + + QStringList::ConstIterator patIt = patterns.begin(); + QStringList wordLst; + QList a, b; + QList::iterator aIt; + for ( ; patIt != patterns.end(); ++patIt ) { + wordLst = (*patIt).split(QLatin1Char(' ')); + a = miniIndex[ wordLst[0] ]->positions; + for ( int j = 1; j < (int)wordLst.count(); ++j ) { + b = miniIndex[ wordLst[j] ]->positions; + aIt = a.begin(); + while ( aIt != a.end() ) { + if ( b.contains( *aIt + 1 )) { + (*aIt)++; + ++aIt; + } else { + aIt = a.erase( aIt ); + } + } + } + } + if ( a.count() ) + return true; + return false; +} + +QVector Reader::setupDummyTerm(const QStringList &terms, + const EntryTable &entryTable) +{ + QList termList; + for (QStringList::ConstIterator it = terms.begin(); it != terms.end(); ++it) { + if (entryTable.value(*it)) { + Entry *e = entryTable.value(*it); + termList.append(Term(*it, e->documents.count(), e->documents ) ); + } + } + QVector maxList(0); + if ( !termList.count() ) + return maxList; + qSort(termList); + + maxList = termList.takeLast().documents; + for(QList::Iterator it = termList.begin(); it != termList.end(); ++it) { + Term *t = &(*it); + QVector docs = t->documents; + for (QVector::iterator docIt = docs.begin(); docIt != docs.end(); ++docIt ) { + if ( maxList.indexOf( *docIt ) == -1 ) + maxList.append( *docIt ); + } + } + return maxList; +} + +QStringList Reader::getWildcardTerms(const QString &term, + const EntryTable &entryTable) +{ + QStringList lst; + QStringList terms = split(term); + QStringList::Iterator iter; + + for(EntryTable::ConstIterator it = entryTable.begin(); + it != entryTable.end(); ++it) { + int index = 0; + bool found = false; + QString text( it.key() ); + for ( iter = terms.begin(); iter != terms.end(); ++iter ) { + if ( *iter == QLatin1String("*") ) { + found = true; + continue; + } + if ( iter == terms.begin() && (*iter)[0] != text[0] ) { + found = false; + break; + } + index = text.indexOf( *iter, index ); + if ( *iter == terms.last() && index != (int)text.length()-1 ) { + index = text.lastIndexOf( *iter ); + if ( index != (int)text.length() - (int)(*iter).length() ) { + found = false; + break; + } + } + if ( index != -1 ) { + found = true; + index += (*iter).length(); + continue; + } else { + found = false; + break; + } + } + if (found) + lst << text; + } + + return lst; +} + +void Reader::buildMiniIndex(const QString &string) +{ + if (miniIndex[string]) + miniIndex[string]->positions.append(wordNum); + ++wordNum; +} + +void Reader::reset() +{ + for(IndexTable::Iterator it = indexTable.begin(); + it != indexTable.end(); ++it) { + cleanupIndex(it.value().first); + it.value().second.clear(); + } +} + +void Reader::cleanupIndex(EntryTable &entryTable) +{ + for(EntryTable::ConstIterator it = + entryTable.begin(); it != entryTable.end(); ++it) { + delete it.value(); + } + + entryTable.clear(); +} + + +QHelpSearchIndexReaderDefault::QHelpSearchIndexReaderDefault() + : QHelpSearchIndexReader() +{ + // nothing todo +} + +QHelpSearchIndexReaderDefault::~QHelpSearchIndexReaderDefault() +{ +} + +void QHelpSearchIndexReaderDefault::run() +{ + mutex.lock(); + + if (m_cancel) { + mutex.unlock(); + return; + } + + const QList &queryList = this->m_query; + const QLatin1String key("DefaultSearchNamespaces"); + const QString collectionFile(this->m_collectionFile); + const QString indexPath = m_indexFilesFolder; + + mutex.unlock(); + + QString queryTerm; + foreach (const QHelpSearchQuery &query, queryList) { + if (query.fieldName == QHelpSearchQuery::DEFAULT) { + queryTerm = query.wordList.at(0); + break; + } + } + + if (queryTerm.isEmpty()) + return; + + QHelpEngineCore engine(collectionFile, 0); + if (!engine.setupData()) + return; + + const QStringList registeredDocs = engine.registeredDocumentations(); + const QStringList indexedNamespaces = engine.customValue(key).toString(). + split(QLatin1String("|"), QString::SkipEmptyParts); + + emit searchingStarted(); + + // setup the reader + m_reader.setIndexPath(indexPath); + foreach(const QString &namespaceName, registeredDocs) { + mutex.lock(); + if (m_cancel) { + mutex.unlock(); + searchingFinished(0); // TODO: check this ??? + return; + } + mutex.unlock(); + + const QList attributeSets = + engine.filterAttributeSets(namespaceName); + + foreach (const QStringList &attributes, attributeSets) { + // read all index files + m_reader.setIndexFile(namespaceName, attributes.join(QLatin1String("@"))); + if (!m_reader.readIndex()) { + qWarning("Full Text Search, could not read file for namespace: %s.", + namespaceName.toUtf8().constData()); + } + } + } + + // get the current filter attributes and minimize the index files table + m_reader.filterFilesForAttributes(engine.filterAttributes(engine.currentFilter())); + + hitList.clear(); + QStringList terms, termSeq, seqWords; + if (m_reader.initCheck() && // check if we could read anything + m_reader.splitSearchTerm(queryTerm, &terms, &termSeq, &seqWords) ) { + + // search for term(s) + m_reader.searchInIndex(terms); // TODO: should this be interruptible as well ??? + + QVector hits = m_reader.hits(); + if (!hits.isEmpty()) { + if (termSeq.isEmpty()) { + foreach (const DocumentInfo &docInfo, hits) { + mutex.lock(); + if (m_cancel) { + mutex.unlock(); + searchingFinished(0); // TODO: check this, speed issue while locking??? + return; + } + mutex.unlock(); + hitList.append(qMakePair(docInfo.documentTitle, docInfo.documentUrl)); + } + } else { + foreach (const DocumentInfo &docInfo, hits) { + mutex.lock(); + if (m_cancel) { + mutex.unlock(); + searchingFinished(0); // TODO: check this, speed issue while locking??? + return; + } + mutex.unlock(); + + if (m_reader.searchForPattern(termSeq, seqWords, engine.fileData(docInfo.documentUrl))) // TODO: should this be interruptible as well ??? + hitList.append(qMakePair(docInfo.documentTitle, docInfo.documentUrl)); + } + } + } + } + + emit searchingFinished(hitList.count()); +} + +} // namespace std +} // namespace fulltextsearch + +QT_END_NAMESPACE diff --git a/src/assistant/lib/qhelpsearchindexreader_default_p.h b/src/assistant/lib/qhelpsearchindexreader_default_p.h new file mode 100644 index 000000000..30dfe1ed6 --- /dev/null +++ b/src/assistant/lib/qhelpsearchindexreader_default_p.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHINDEXREADERDEFAULT_H +#define QHELPSEARCHINDEXREADERDEFAULT_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhelpsearchindex_default_p.h" +#include "qhelpsearchindexreader_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace fulltextsearch { +namespace std { + +class Reader +{ + typedef QList DocumentList; + typedef QHash EntryTable; + typedef QPair Index; + typedef QHash IndexTable; + +public: + Reader(); + ~Reader(); + + bool readIndex(); + bool initCheck() const; + void setIndexPath(const QString &path); + void filterFilesForAttributes(const QStringList &attributes); + void setIndexFile(const QString &namespaceName, const QString &attributes); + bool splitSearchTerm(const QString &searchTerm, QStringList *terms, + QStringList *termSeq, QStringList *seqWords); + + void searchInIndex(const QStringList &terms); + QVector hits(); + bool searchForPattern(const QStringList &patterns, + const QStringList &words, const QByteArray &data); + +private: + QVector setupDummyTerm(const QStringList &terms, const EntryTable &entryTable); + QStringList getWildcardTerms(const QString &term, const EntryTable &entryTable); + void buildMiniIndex(const QString &string); + void reset(); + void cleanupIndex(EntryTable &entryTable); + +private: + uint wordNum; + QString indexPath; + QString indexFile; + QString documentFile; + + IndexTable indexTable; + QList termList; + IndexTable searchIndexTable; + QHash miniIndex; +}; + + +class QHelpSearchIndexReaderDefault : public QHelpSearchIndexReader +{ + Q_OBJECT + +public: + QHelpSearchIndexReaderDefault(); + ~QHelpSearchIndexReaderDefault(); + +private: + void run(); + +private: + Reader m_reader; +}; + +} // namespace std +} // namespace fulltextsearch + +QT_END_NAMESPACE + +#endif // QHELPSEARCHINDEXREADERDEFAULT_H diff --git a/src/assistant/lib/qhelpsearchindexreader_p.h b/src/assistant/lib/qhelpsearchindexreader_p.h new file mode 100644 index 000000000..0d7518a6e --- /dev/null +++ b/src/assistant/lib/qhelpsearchindexreader_p.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHINDEXREADER_H +#define QHELPSEARCHINDEXREADER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhelpsearchengine.h" + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QHelpEngineCore; + +namespace fulltextsearch { + +class QHelpSearchIndexReader : public QThread +{ + Q_OBJECT + +public: + QHelpSearchIndexReader(); + ~QHelpSearchIndexReader(); + + void cancelSearching(); + void search(const QString &collectionFile, + const QString &indexFilesFolder, + const QList &queryList); + int hitCount() const; + QList hits(int start, int end) const; + +signals: + void searchingStarted(); + void searchingFinished(int hits); + +protected: + mutable QMutex mutex; + QList hitList; + bool m_cancel; + QString m_collectionFile; + QList m_query; + QString m_indexFilesFolder; + +private: + virtual void run()=0; +}; + +} // namespace fulltextsearch + +QT_END_NAMESPACE + +#endif // QHELPSEARCHINDEXREADER_H diff --git a/src/assistant/lib/qhelpsearchindexwriter_clucene.cpp b/src/assistant/lib/qhelpsearchindexwriter_clucene.cpp new file mode 100644 index 000000000..f3d5e4fc3 --- /dev/null +++ b/src/assistant/lib/qhelpsearchindexwriter_clucene.cpp @@ -0,0 +1,898 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qclucenefieldnames_p.h" +#include "qhelpenginecore.h" +#include "qhelp_global.h" +#include "fulltextsearch/qhits_p.h" +#include "fulltextsearch/qquery_p.h" +#include "fulltextsearch/qanalyzer_p.h" +#include "fulltextsearch/qdocument_p.h" +#include "fulltextsearch/qsearchable_p.h" +#include "fulltextsearch/qindexreader_p.h" +#include "fulltextsearch/qindexwriter_p.h" +#include "qhelpsearchindexwriter_clucene_p.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include "private/qfunctions_p.h" + +QT_BEGIN_NAMESPACE + +namespace fulltextsearch { +namespace clucene { + +// taken from qtexthtmlparser +static const struct QTextHtmlEntity +{ + const char *name; + quint16 code; +} entities[] = { + { "AElig", 0x00c6 }, + { "AMP", 38 }, + { "Aacute", 0x00c1 }, + { "Acirc", 0x00c2 }, + { "Agrave", 0x00c0 }, + { "Alpha", 0x0391 }, + { "Aring", 0x00c5 }, + { "Atilde", 0x00c3 }, + { "Auml", 0x00c4 }, + { "Beta", 0x0392 }, + { "Ccedil", 0x00c7 }, + { "Chi", 0x03a7 }, + { "Dagger", 0x2021 }, + { "Delta", 0x0394 }, + { "ETH", 0x00d0 }, + { "Eacute", 0x00c9 }, + { "Ecirc", 0x00ca }, + { "Egrave", 0x00c8 }, + { "Epsilon", 0x0395 }, + { "Eta", 0x0397 }, + { "Euml", 0x00cb }, + { "GT", 62 }, + { "Gamma", 0x0393 }, + { "Iacute", 0x00cd }, + { "Icirc", 0x00ce }, + { "Igrave", 0x00cc }, + { "Iota", 0x0399 }, + { "Iuml", 0x00cf }, + { "Kappa", 0x039a }, + { "LT", 60 }, + { "Lambda", 0x039b }, + { "Mu", 0x039c }, + { "Ntilde", 0x00d1 }, + { "Nu", 0x039d }, + { "OElig", 0x0152 }, + { "Oacute", 0x00d3 }, + { "Ocirc", 0x00d4 }, + { "Ograve", 0x00d2 }, + { "Omega", 0x03a9 }, + { "Omicron", 0x039f }, + { "Oslash", 0x00d8 }, + { "Otilde", 0x00d5 }, + { "Ouml", 0x00d6 }, + { "Phi", 0x03a6 }, + { "Pi", 0x03a0 }, + { "Prime", 0x2033 }, + { "Psi", 0x03a8 }, + { "QUOT", 34 }, + { "Rho", 0x03a1 }, + { "Scaron", 0x0160 }, + { "Sigma", 0x03a3 }, + { "THORN", 0x00de }, + { "Tau", 0x03a4 }, + { "Theta", 0x0398 }, + { "Uacute", 0x00da }, + { "Ucirc", 0x00db }, + { "Ugrave", 0x00d9 }, + { "Upsilon", 0x03a5 }, + { "Uuml", 0x00dc }, + { "Xi", 0x039e }, + { "Yacute", 0x00dd }, + { "Yuml", 0x0178 }, + { "Zeta", 0x0396 }, + { "aacute", 0x00e1 }, + { "acirc", 0x00e2 }, + { "acute", 0x00b4 }, + { "aelig", 0x00e6 }, + { "agrave", 0x00e0 }, + { "alefsym", 0x2135 }, + { "alpha", 0x03b1 }, + { "amp", 38 }, + { "and", 0x22a5 }, + { "ang", 0x2220 }, + { "apos", 0x0027 }, + { "aring", 0x00e5 }, + { "asymp", 0x2248 }, + { "atilde", 0x00e3 }, + { "auml", 0x00e4 }, + { "bdquo", 0x201e }, + { "beta", 0x03b2 }, + { "brvbar", 0x00a6 }, + { "bull", 0x2022 }, + { "cap", 0x2229 }, + { "ccedil", 0x00e7 }, + { "cedil", 0x00b8 }, + { "cent", 0x00a2 }, + { "chi", 0x03c7 }, + { "circ", 0x02c6 }, + { "clubs", 0x2663 }, + { "cong", 0x2245 }, + { "copy", 0x00a9 }, + { "crarr", 0x21b5 }, + { "cup", 0x222a }, + { "curren", 0x00a4 }, + { "dArr", 0x21d3 }, + { "dagger", 0x2020 }, + { "darr", 0x2193 }, + { "deg", 0x00b0 }, + { "delta", 0x03b4 }, + { "diams", 0x2666 }, + { "divide", 0x00f7 }, + { "eacute", 0x00e9 }, + { "ecirc", 0x00ea }, + { "egrave", 0x00e8 }, + { "empty", 0x2205 }, + { "emsp", 0x2003 }, + { "ensp", 0x2002 }, + { "epsilon", 0x03b5 }, + { "equiv", 0x2261 }, + { "eta", 0x03b7 }, + { "eth", 0x00f0 }, + { "euml", 0x00eb }, + { "euro", 0x20ac }, + { "exist", 0x2203 }, + { "fnof", 0x0192 }, + { "forall", 0x2200 }, + { "frac12", 0x00bd }, + { "frac14", 0x00bc }, + { "frac34", 0x00be }, + { "frasl", 0x2044 }, + { "gamma", 0x03b3 }, + { "ge", 0x2265 }, + { "gt", 62 }, + { "hArr", 0x21d4 }, + { "harr", 0x2194 }, + { "hearts", 0x2665 }, + { "hellip", 0x2026 }, + { "iacute", 0x00ed }, + { "icirc", 0x00ee }, + { "iexcl", 0x00a1 }, + { "igrave", 0x00ec }, + { "image", 0x2111 }, + { "infin", 0x221e }, + { "int", 0x222b }, + { "iota", 0x03b9 }, + { "iquest", 0x00bf }, + { "isin", 0x2208 }, + { "iuml", 0x00ef }, + { "kappa", 0x03ba }, + { "lArr", 0x21d0 }, + { "lambda", 0x03bb }, + { "lang", 0x2329 }, + { "laquo", 0x00ab }, + { "larr", 0x2190 }, + { "lceil", 0x2308 }, + { "ldquo", 0x201c }, + { "le", 0x2264 }, + { "lfloor", 0x230a }, + { "lowast", 0x2217 }, + { "loz", 0x25ca }, + { "lrm", 0x200e }, + { "lsaquo", 0x2039 }, + { "lsquo", 0x2018 }, + { "lt", 60 }, + { "macr", 0x00af }, + { "mdash", 0x2014 }, + { "micro", 0x00b5 }, + { "middot", 0x00b7 }, + { "minus", 0x2212 }, + { "mu", 0x03bc }, + { "nabla", 0x2207 }, + { "nbsp", 0x00a0 }, + { "ndash", 0x2013 }, + { "ne", 0x2260 }, + { "ni", 0x220b }, + { "not", 0x00ac }, + { "notin", 0x2209 }, + { "nsub", 0x2284 }, + { "ntilde", 0x00f1 }, + { "nu", 0x03bd }, + { "oacute", 0x00f3 }, + { "ocirc", 0x00f4 }, + { "oelig", 0x0153 }, + { "ograve", 0x00f2 }, + { "oline", 0x203e }, + { "omega", 0x03c9 }, + { "omicron", 0x03bf }, + { "oplus", 0x2295 }, + { "or", 0x22a6 }, + { "ordf", 0x00aa }, + { "ordm", 0x00ba }, + { "oslash", 0x00f8 }, + { "otilde", 0x00f5 }, + { "otimes", 0x2297 }, + { "ouml", 0x00f6 }, + { "para", 0x00b6 }, + { "part", 0x2202 }, + { "percnt", 0x0025 }, + { "permil", 0x2030 }, + { "perp", 0x22a5 }, + { "phi", 0x03c6 }, + { "pi", 0x03c0 }, + { "piv", 0x03d6 }, + { "plusmn", 0x00b1 }, + { "pound", 0x00a3 }, + { "prime", 0x2032 }, + { "prod", 0x220f }, + { "prop", 0x221d }, + { "psi", 0x03c8 }, + { "quot", 34 }, + { "rArr", 0x21d2 }, + { "radic", 0x221a }, + { "rang", 0x232a }, + { "raquo", 0x00bb }, + { "rarr", 0x2192 }, + { "rceil", 0x2309 }, + { "rdquo", 0x201d }, + { "real", 0x211c }, + { "reg", 0x00ae }, + { "rfloor", 0x230b }, + { "rho", 0x03c1 }, + { "rlm", 0x200f }, + { "rsaquo", 0x203a }, + { "rsquo", 0x2019 }, + { "sbquo", 0x201a }, + { "scaron", 0x0161 }, + { "sdot", 0x22c5 }, + { "sect", 0x00a7 }, + { "shy", 0x00ad }, + { "sigma", 0x03c3 }, + { "sigmaf", 0x03c2 }, + { "sim", 0x223c }, + { "spades", 0x2660 }, + { "sub", 0x2282 }, + { "sube", 0x2286 }, + { "sum", 0x2211 }, + { "sup", 0x2283 }, + { "sup1", 0x00b9 }, + { "sup2", 0x00b2 }, + { "sup3", 0x00b3 }, + { "supe", 0x2287 }, + { "szlig", 0x00df }, + { "tau", 0x03c4 }, + { "there4", 0x2234 }, + { "theta", 0x03b8 }, + { "thetasym", 0x03d1 }, + { "thinsp", 0x2009 }, + { "thorn", 0x00fe }, + { "tilde", 0x02dc }, + { "times", 0x00d7 }, + { "trade", 0x2122 }, + { "uArr", 0x21d1 }, + { "uacute", 0x00fa }, + { "uarr", 0x2191 }, + { "ucirc", 0x00fb }, + { "ugrave", 0x00f9 }, + { "uml", 0x00a8 }, + { "upsih", 0x03d2 }, + { "upsilon", 0x03c5 }, + { "uuml", 0x00fc }, + { "weierp", 0x2118 }, + { "xi", 0x03be }, + { "yacute", 0x00fd }, + { "yen", 0x00a5 }, + { "yuml", 0x00ff }, + { "zeta", 0x03b6 }, + { "zwj", 0x200d }, + { "zwnj", 0x200c } +}; + +Q_STATIC_GLOBAL_OPERATOR bool operator<(const QString &entityStr, const QTextHtmlEntity &entity) +{ + return entityStr < QLatin1String(entity.name); +} + +Q_STATIC_GLOBAL_OPERATOR bool operator<(const QTextHtmlEntity &entity, const QString &entityStr) +{ + return QLatin1String(entity.name) < entityStr; +} + +static QChar resolveEntity(const QString &entity) +{ + const QTextHtmlEntity *start = &entities[0]; + const QTextHtmlEntity *end = &entities[(sizeof(entities) / sizeof(entities[0]))]; + const QTextHtmlEntity *e = qBinaryFind(start, end, entity); + if (e == end) + return QChar(); + return e->code; +} + +static const uint latin1Extended[0xA0 - 0x80] = { + 0x20ac, // 0x80 + 0x0081, // 0x81 direct mapping + 0x201a, // 0x82 + 0x0192, // 0x83 + 0x201e, // 0x84 + 0x2026, // 0x85 + 0x2020, // 0x86 + 0x2021, // 0x87 + 0x02C6, // 0x88 + 0x2030, // 0x89 + 0x0160, // 0x8A + 0x2039, // 0x8B + 0x0152, // 0x8C + 0x008D, // 0x8D direct mapping + 0x017D, // 0x8E + 0x008F, // 0x8F directmapping + 0x0090, // 0x90 directmapping + 0x2018, // 0x91 + 0x2019, // 0x92 + 0x201C, // 0x93 + 0X201D, // 0x94 + 0x2022, // 0x95 + 0x2013, // 0x96 + 0x2014, // 0x97 + 0x02DC, // 0x98 + 0x2122, // 0x99 + 0x0161, // 0x9A + 0x203A, // 0x9B + 0x0153, // 0x9C + 0x009D, // 0x9D direct mapping + 0x017E, // 0x9E + 0x0178 // 0x9F +}; +// end taken from qtexthtmlparser + +class DocumentHelper +{ +public: + DocumentHelper(const QString &fileName, const QByteArray &data) + : fileName(fileName) , data(readData(data)) {} + ~DocumentHelper() {} + + bool addFieldsToDocument(QCLuceneDocument *document, + const QString &namespaceName, const QString &attributes = QString()) + { + if (!document) + return false; + + if(!data.isEmpty()) { + QString parsedData = parseData(); + QString parsedTitle = QHelpGlobal::documentTitle(data); + + if(!parsedData.isEmpty()) { + document->add(new QCLuceneField(ContentField, + parsedData,QCLuceneField::INDEX_TOKENIZED)); + document->add(new QCLuceneField(PathField, fileName, + QCLuceneField::STORE_YES | QCLuceneField::INDEX_UNTOKENIZED)); + document->add(new QCLuceneField(TitleField, parsedTitle, + QCLuceneField::STORE_YES | QCLuceneField::INDEX_UNTOKENIZED)); + document->add(new QCLuceneField(TitleTokenizedField, parsedTitle, + QCLuceneField::STORE_YES | QCLuceneField::INDEX_TOKENIZED)); + document->add(new QCLuceneField(NamespaceField, namespaceName, + QCLuceneField::STORE_YES | QCLuceneField::INDEX_UNTOKENIZED)); + document->add(new QCLuceneField(AttributeField, attributes, + QCLuceneField::STORE_YES | QCLuceneField::INDEX_TOKENIZED)); + return true; + } + } + + return false; + } + +private: + QString readData(const QByteArray &data) + { + QTextStream textStream(data); + const QByteArray &codec = QHelpGlobal::codecFromData(data).toLatin1(); + textStream.setCodec(QTextCodec::codecForName(codec.constData())); + + QString stream = textStream.readAll(); + if (stream.isNull() || stream.isEmpty()) + return QString(); + + return stream; + } + + QString parseData() const + { + const int length = data.length(); + const QChar *buf = data.unicode(); + + QString parsedContent; + parsedContent.reserve(length); + + bool valid = true; + int j = 0, count = 0; + + QChar c; + while (j < length) { + c = buf[j++]; + if (c == QLatin1Char('<') || c == QLatin1Char('&')) { + if (count > 1 && c != QLatin1Char('&')) + parsedContent.append(QLatin1Char(' ')); + else if (c == QLatin1Char('&')) { + // Note: this will modify the counter j, in case we sucessful parsed the entity + // we will have modified the counter to stay 1 before the closing ';', so + // the following if condition will be met with if (c == QLatin1Char(';')) + parsedContent.append(parseEntity(length, buf, j)); + } + + count = 0; + valid = false; + continue; + } + if ((c == QLatin1Char('>') || c == QLatin1Char(';')) && !valid) { + valid = true; + continue; + } + if (!valid) + continue; + + if (c.isLetterOrNumber() || c.isPrint()) { + ++count; + parsedContent.append(c.toLower()); + } else { + if (count > 1) + parsedContent.append(QLatin1Char(' ')); + count = 0; + } + } + + return parsedContent; + } + + // taken from qtexthtmlparser + // parses an entity after "&", and returns it + QString parseEntity(int len, const QChar *buf, int &pos) const + { + int recover = pos; + QString entity; + while (pos < len) { + QChar c = buf[pos++]; + if (c.isSpace() || pos - recover > 9) { + goto error; + } + if (c == QLatin1Char(';')) { + pos--; + break; + } + entity += c; + } + { + QChar resolved = resolveEntity(entity); + if (!resolved.isNull()) + return QString(resolved); + } + if (entity.length() > 1 && entity.at(0) == QLatin1Char('#')) { + entity.remove(0, 1); // removing leading # + + int base = 10; + bool ok = false; + + if (entity.at(0).toLower() == QLatin1Char('x')) { // hex entity? + entity.remove(0, 1); + base = 16; + } + + uint uc = entity.toUInt(&ok, base); + if (ok) { + if (uc >= 0x80 && uc < 0x80 + (sizeof(latin1Extended) / sizeof(latin1Extended[0]))) + uc = latin1Extended[uc - 0x80]; // windows latin 1 extended + QString str; + if (uc > 0xffff) { + // surrogate pair + uc -= 0x10000; + ushort high = uc/0x400 + 0xd800; + ushort low = uc%0x400 + 0xdc00; + str.append(QChar(high)); + str.append(QChar(low)); + } else { + str.append(QChar(uc)); + } + return str; + } + } + error: + pos = recover; + return QLatin1String(" "); + } + // end taken from qtexthtmlparser + +private: + QString fileName; + QString data; +}; + + +QHelpSearchIndexWriter::QHelpSearchIndexWriter() + : QThread(0) + , m_cancel(false) +{ + // nothing todo +} + +QHelpSearchIndexWriter::~QHelpSearchIndexWriter() +{ + mutex.lock(); + this->m_cancel = true; + waitCondition.wakeOne(); + mutex.unlock(); + + wait(); +} + +void QHelpSearchIndexWriter::cancelIndexing() +{ + mutex.lock(); + this->m_cancel = true; + mutex.unlock(); +} + +void QHelpSearchIndexWriter::updateIndex(const QString &collectionFile, + const QString &indexFilesFolder, bool reindex) +{ + wait(); + mutex.lock(); + this->m_cancel = false; + this->m_reindex = reindex; + this->m_collectionFile = collectionFile; + this->m_indexFilesFolder = indexFilesFolder; + mutex.unlock(); + + start(QThread::LowestPriority); +} + +void QHelpSearchIndexWriter::optimizeIndex() +{ +#if !defined(QT_NO_EXCEPTIONS) + try { +#endif + if (QCLuceneIndexReader::indexExists(m_indexFilesFolder)) { + if (QCLuceneIndexReader::isLocked(m_indexFilesFolder)) + return; + + QCLuceneStandardAnalyzer analyzer; + QCLuceneIndexWriter writer(m_indexFilesFolder, analyzer, false); + writer.optimize(); + writer.close(); + } +#if !defined(QT_NO_EXCEPTIONS) + } catch (...) { + qWarning("Full Text Search, could not optimize index."); + return; + } +#endif +} + +void QHelpSearchIndexWriter::run() +{ +#if !defined(QT_NO_EXCEPTIONS) + try { +#endif + QMutexLocker mutexLocker(&mutex); + + if (m_cancel) + return; + + const bool reindex = this->m_reindex; + const QString collectionFile(this->m_collectionFile); + + mutexLocker.unlock(); + + QHelpEngineCore engine(collectionFile, 0); + if (!engine.setupData()) + return; + + const QLatin1String key("CluceneIndexedNamespaces"); + if (reindex) + engine.setCustomValue(key, QLatin1String("")); + + QMap indexMap; + const QLatin1String oldKey("CluceneSearchNamespaces"); + if (!engine.customValue(oldKey, QString()).isNull()) { + // old style qhc file < 4.4.2, need to convert... + const QStringList indexedNamespaces + = engine.customValue(oldKey).toString() + .split(QLatin1String("|"), QString::SkipEmptyParts); + foreach (const QString &nameSpace, indexedNamespaces) + indexMap.insert(nameSpace, QDateTime()); + engine.removeCustomValue(oldKey); + } else { + QDataStream dataStream(engine.customValue(key).toByteArray()); + dataStream >> indexMap; + } + + QString indexPath = m_indexFilesFolder; + + QFileInfo fInfo(indexPath); + if (fInfo.exists() && !fInfo.isWritable()) { + qWarning("Full Text Search, could not create index (missing permissions for '%s').", + qPrintable(indexPath)); + return; + } + + emit indexingStarted(); + + QCLuceneIndexWriter *writer = 0; + QCLuceneStandardAnalyzer analyzer; + const QStringList registeredDocs = engine.registeredDocumentations(); + + QLocalSocket localSocket; + localSocket.connectToServer(QString(QLatin1String("QtAssistant%1")) + .arg(QLatin1String(QT_VERSION_STR))); + + QLocalServer localServer; + bool otherInstancesRunning = true; + if (!localSocket.waitForConnected()) { + otherInstancesRunning = false; + localServer.listen(QString(QLatin1String("QtAssistant%1")) + .arg(QLatin1String(QT_VERSION_STR))); + } + + // check if it's locked, and if the other instance is running + if (!otherInstancesRunning && QCLuceneIndexReader::isLocked(indexPath)) + QCLuceneIndexReader::unlock(indexPath); + + if (QCLuceneIndexReader::isLocked(indexPath)) { + // poll unless indexing finished to fake progress + while (QCLuceneIndexReader::isLocked(indexPath)) { + mutexLocker.relock(); + if (m_cancel) + break; + mutexLocker.unlock(); + this->sleep(1); + } + emit indexingFinished(); + return; + } + + if (QCLuceneIndexReader::indexExists(indexPath) && !reindex) { + foreach(const QString &namespaceName, registeredDocs) { + mutexLocker.relock(); + if (m_cancel) { + emit indexingFinished(); + return; + } + mutexLocker.unlock(); + + if (!indexMap.contains(namespaceName)) { + // make sure we remove some partly indexed stuff + removeDocuments(indexPath, namespaceName); + } else { + QString path = engine.documentationFileName(namespaceName); + if (indexMap.value(namespaceName) + < QFileInfo(path).lastModified()) { + // make sure we remove some outdated indexed stuff + indexMap.remove(namespaceName); + removeDocuments(indexPath, namespaceName); + } + + if (indexMap.contains(namespaceName)) { + // make sure we really have content indexed for namespace + QCLuceneTermQuery query(QCLuceneTerm(NamespaceField, namespaceName)); + QCLuceneIndexSearcher indexSearcher(indexPath); + QCLuceneHits hits = indexSearcher.search(query); + if (hits.length() <= 0) + indexMap.remove(namespaceName); + } + } + } + writer = new QCLuceneIndexWriter(indexPath, analyzer, false); + } else { + indexMap.clear(); + writer = new QCLuceneIndexWriter(indexPath, analyzer, true); + } + + writer->setMergeFactor(100); + writer->setMinMergeDocs(1000); + writer->setMaxFieldLength(QCLuceneIndexWriter::DEFAULT_MAX_FIELD_LENGTH); + + QStringList namespaces; + foreach(const QString &namespaceName, registeredDocs) { + mutexLocker.relock(); + if (m_cancel) { + closeIndexWriter(writer); + emit indexingFinished(); + return; + } + mutexLocker.unlock(); + + namespaces.append(namespaceName); + if (indexMap.contains(namespaceName)) + continue; + + const QList attributeSets = + engine.filterAttributeSets(namespaceName); + + if (attributeSets.isEmpty()) { + const QList docFiles = indexableFiles(&engine, namespaceName, + QStringList()); + if (!addDocuments(docFiles, engine, QStringList(), namespaceName, + writer, analyzer)) + break; + } else { + bool bail = false; + foreach (const QStringList &attributes, attributeSets) { + const QList docFiles = indexableFiles(&engine, + namespaceName, attributes); + if (!addDocuments(docFiles, engine, attributes, namespaceName, + writer, analyzer)) { + bail = true; + break; + } + } + if (bail) + break; + } + + mutexLocker.relock(); + if (!m_cancel) { + QString path(engine.documentationFileName(namespaceName)); + indexMap.insert(namespaceName, QFileInfo(path).lastModified()); + writeIndexMap(engine, indexMap); + } + mutexLocker.unlock(); + } + + closeIndexWriter(writer); + + mutexLocker.relock(); + if (!m_cancel) { + mutexLocker.unlock(); + + QStringList indexedNamespaces = indexMap.keys(); + foreach(const QString &namespaceName, indexedNamespaces) { + mutexLocker.relock(); + if (m_cancel) + break; + mutexLocker.unlock(); + + if (!namespaces.contains(namespaceName)) { + indexMap.remove(namespaceName); + writeIndexMap(engine, indexMap); + removeDocuments(indexPath, namespaceName); + } + } + } + +#if !defined(QT_NO_EXCEPTIONS) + } catch (...) { + qWarning("%s: Failed because of CLucene exception.", Q_FUNC_INFO); + } +#endif + + emit indexingFinished(); +} + +bool QHelpSearchIndexWriter::addDocuments(const QList docFiles, + const QHelpEngineCore &engine, const QStringList &attributes, + const QString &namespaceName, QCLuceneIndexWriter *writer, + QCLuceneAnalyzer &analyzer) +{ + QMutexLocker locker(&mutex); + const QString attrList = attributes.join(QLatin1String(" ")); + + locker.unlock(); + foreach(const QUrl &url, docFiles) { + QCLuceneDocument document; + DocumentHelper helper(url.toString(), engine.fileData(url)); + if (helper.addFieldsToDocument(&document, namespaceName, attrList)) { +#if !defined(QT_NO_EXCEPTIONS) + try { +#endif + writer->addDocument(document, analyzer); +#if !defined(QT_NO_EXCEPTIONS) + } catch (...) { + qWarning("Full Text Search, could not properly add documents."); + return false; + } +#endif + } + locker.relock(); + if (m_cancel) + return false; + locker.unlock(); + } + return true; +} + +void QHelpSearchIndexWriter::removeDocuments(const QString &indexPath, + const QString &namespaceName) +{ + if (namespaceName.isEmpty() || QCLuceneIndexReader::isLocked(indexPath)) + return; + + QCLuceneIndexReader reader = QCLuceneIndexReader::open(indexPath); + reader.deleteDocuments(QCLuceneTerm(NamespaceField, namespaceName)); + + reader.close(); +} + +bool QHelpSearchIndexWriter::writeIndexMap(QHelpEngineCore &engine, + const QMap &indexMap) +{ + QByteArray bArray; + + QDataStream data(&bArray, QIODevice::ReadWrite); + data << indexMap; + + return engine.setCustomValue(QLatin1String("CluceneIndexedNamespaces"), + bArray); +} + +QList QHelpSearchIndexWriter::indexableFiles(QHelpEngineCore *helpEngine, + const QString &namespaceName, const QStringList &attributes) const +{ + QList docFiles = helpEngine->files(namespaceName, attributes, + QLatin1String("html")); + docFiles += helpEngine->files(namespaceName, attributes, QLatin1String("htm")); + docFiles += helpEngine->files(namespaceName, attributes, QLatin1String("txt")); + + return docFiles; +} + +void QHelpSearchIndexWriter::closeIndexWriter(QCLuceneIndexWriter *writer) +{ +#if !defined(QT_NO_EXCEPTIONS) + try { +#endif + writer->close(); + delete writer; +#if !defined(QT_NO_EXCEPTIONS) + } catch (...) { + qWarning("Full Text Search, could not properly close index writer."); + } +#endif +} + +} // namespace clucene +} // namespace fulltextsearch + +QT_END_NAMESPACE diff --git a/src/assistant/lib/qhelpsearchindexwriter_clucene_p.h b/src/assistant/lib/qhelpsearchindexwriter_clucene_p.h new file mode 100644 index 000000000..89146f5a7 --- /dev/null +++ b/src/assistant/lib/qhelpsearchindexwriter_clucene_p.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHINDEXWRITERCLUCENE_H +#define QHELPSEARCHINDEXWRITERCLUCENE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhelpenginecore.h" +#include "fulltextsearch/qanalyzer_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QCLuceneIndexWriter; + +namespace fulltextsearch { +namespace clucene { + +class QHelpSearchIndexWriter : public QThread +{ + Q_OBJECT + +public: + QHelpSearchIndexWriter(); + ~QHelpSearchIndexWriter(); + + void cancelIndexing(); + void updateIndex(const QString &collectionFile, + const QString &indexFilesFolder, bool reindex); + void optimizeIndex(); + +signals: + void indexingStarted(); + void indexingFinished(); + +private: + void run(); + + bool addDocuments(const QList docFiles, const QHelpEngineCore &engine, + const QStringList &attributes, const QString &namespaceName, + QCLuceneIndexWriter *writer, QCLuceneAnalyzer &analyzer); + void removeDocuments(const QString &indexPath, const QString &namespaceName); + + bool writeIndexMap(QHelpEngineCore& engine, + const QMap& indexMap); + + QList indexableFiles(QHelpEngineCore *helpEngine, + const QString &namespaceName, const QStringList &attributes) const; + + void closeIndexWriter(QCLuceneIndexWriter *writer); + +private: + QMutex mutex; + QWaitCondition waitCondition; + + bool m_cancel; + bool m_reindex; + QString m_collectionFile; + QString m_indexFilesFolder; +}; + +} // namespace clucene +} // namespace fulltextsearch + + +QT_END_NAMESPACE + +#endif // QHELPSEARCHINDEXWRITERCLUCENE_H diff --git a/src/assistant/lib/qhelpsearchindexwriter_default.cpp b/src/assistant/lib/qhelpsearchindexwriter_default.cpp new file mode 100644 index 000000000..db7f6ba0d --- /dev/null +++ b/src/assistant/lib/qhelpsearchindexwriter_default.cpp @@ -0,0 +1,384 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpsearchindexwriter_default_p.h" +#include "qhelp_global.h" +#include "qhelpenginecore.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace fulltextsearch { +namespace std { + +Writer::Writer(const QString &path) + : indexPath(path) + , indexFile(QString()) + , documentFile(QString()) +{ + // nothing todo +} + +Writer::~Writer() +{ + reset(); +} + +void Writer::reset() +{ + for(QHash::ConstIterator it = + index.begin(); it != index.end(); ++it) { + delete it.value(); + } + + index.clear(); + documentList.clear(); +} + +bool Writer::writeIndex() const +{ + bool status; + QFile idxFile(indexFile); + if (!(status = idxFile.open(QFile::WriteOnly))) + return status; + + QDataStream indexStream(&idxFile); + for(QHash::ConstIterator it = + index.begin(); it != index.end(); ++it) { + indexStream << it.key(); + indexStream << it.value()->documents.count(); + indexStream << it.value()->documents; + } + idxFile.close(); + + QFile docFile(documentFile); + if (!(status = docFile.open(QFile::WriteOnly))) + return status; + + QDataStream docStream(&docFile); + foreach(const QStringList &list, documentList) { + docStream << list.at(0); + docStream << list.at(1); + } + docFile.close(); + + return status; +} + +void Writer::removeIndex() const +{ + QFile idxFile(indexFile); + if (idxFile.exists()) + idxFile.remove(); + + QFile docFile(documentFile); + if (docFile.exists()) + docFile.remove(); +} + +void Writer::setIndexFile(const QString &namespaceName, const QString &attributes) +{ + QString extension = namespaceName + QLatin1String("@") + attributes; + indexFile = indexPath + QLatin1String("/indexdb40.") + extension; + documentFile = indexPath + QLatin1String("/indexdoc40.") + extension; +} + +void Writer::insertInIndex(const QString &string, int docNum) +{ + if (string == QLatin1String("amp") || string == QLatin1String("nbsp")) + return; + + Entry *entry = 0; + if (index.count()) + entry = index[string]; + + if (entry) { + if (entry->documents.last().docNumber != docNum) + entry->documents.append(Document(docNum, 1)); + else + entry->documents.last().frequency++; + } else { + index.insert(string, new Entry(docNum)); + } +} + +void Writer::insertInDocumentList(const QString &title, const QString &url) +{ + documentList.append(QStringList(title) << url); +} + + +QHelpSearchIndexWriter::QHelpSearchIndexWriter() + : QThread() + , m_cancel(false) +{ + // nothing todo +} + +QHelpSearchIndexWriter::~QHelpSearchIndexWriter() +{ + mutex.lock(); + this->m_cancel = true; + waitCondition.wakeOne(); + mutex.unlock(); + + wait(); +} + +void QHelpSearchIndexWriter::cancelIndexing() +{ + mutex.lock(); + this->m_cancel = true; + mutex.unlock(); +} + +void QHelpSearchIndexWriter::updateIndex(const QString &collectionFile, + const QString &indexFilesFolder, + bool reindex) +{ + wait(); + QMutexLocker lock(&mutex); + + this->m_cancel = false; + this->m_reindex = reindex; + this->m_collectionFile = collectionFile; + this->m_indexFilesFolder = indexFilesFolder; + + start(QThread::LowestPriority); +} + +void QHelpSearchIndexWriter::run() +{ + mutex.lock(); + + if (m_cancel) { + mutex.unlock(); + return; + } + + const bool reindex(this->m_reindex); + const QLatin1String key("DefaultSearchNamespaces"); + const QString collectionFile(this->m_collectionFile); + const QString indexPath = m_indexFilesFolder; + + mutex.unlock(); + + QHelpEngineCore engine(collectionFile, 0); + if (!engine.setupData()) + return; + + if (reindex) + engine.setCustomValue(key, QLatin1String("")); + + const QStringList registeredDocs = engine.registeredDocumentations(); + const QStringList indexedNamespaces = engine.customValue(key).toString(). + split(QLatin1String("|"), QString::SkipEmptyParts); + + emit indexingStarted(); + + QStringList namespaces; + Writer writer(indexPath); + foreach(const QString &namespaceName, registeredDocs) { + mutex.lock(); + if (m_cancel) { + mutex.unlock(); + return; + } + mutex.unlock(); + + // if indexed, continue + namespaces.append(namespaceName); + if (indexedNamespaces.contains(namespaceName)) + continue; + + const QList attributeSets = + engine.filterAttributeSets(namespaceName); + + foreach (const QStringList &attributes, attributeSets) { + // cleanup maybe old or unfinished files + writer.setIndexFile(namespaceName, attributes.join(QLatin1String("@"))); + writer.removeIndex(); + + QSet documentsSet; + const QList docFiles = engine.files(namespaceName, attributes); + foreach(QUrl url, docFiles) { + if (m_cancel) + return; + + // get rid of duplicated files + if (url.hasFragment()) + url.setFragment(QString()); + + QString s = url.toString(); + if (s.endsWith(QLatin1String(".html")) + || s.endsWith(QLatin1String(".htm")) + || s.endsWith(QLatin1String(".txt"))) + documentsSet.insert(s); + } + + int docNum = 0; + const QStringList documentsList(documentsSet.toList()); + foreach(const QString &url, documentsList) { + if (m_cancel) + return; + + QByteArray data(engine.fileData(url)); + if (data.isEmpty()) + continue; + + QTextStream s(data); + QString en = QHelpGlobal::codecFromData(data); + s.setCodec(QTextCodec::codecForName(en.toLatin1().constData())); + + QString text = s.readAll(); + if (text.isNull()) + continue; + + QString title = QHelpGlobal::documentTitle(text); + + int j = 0; + int i = 0; + bool valid = true; + const QChar *buf = text.unicode(); + QChar str[64]; + QChar c = buf[0]; + + while ( j < text.length() ) { + if (m_cancel) + return; + + if ( c == QLatin1Char('<') || c == QLatin1Char('&') ) { + valid = false; + if ( i > 1 ) + writer.insertInIndex(QString(str,i), docNum); + i = 0; + c = buf[++j]; + continue; + } + if ( ( c == QLatin1Char('>') || c == QLatin1Char(';') ) && !valid ) { + valid = true; + c = buf[++j]; + continue; + } + if ( !valid ) { + c = buf[++j]; + continue; + } + if ( ( c.isLetterOrNumber() || c == QLatin1Char('_') ) && i < 63 ) { + str[i] = c.toLower(); + ++i; + } else { + if ( i > 1 ) + writer.insertInIndex(QString(str,i), docNum); + i = 0; + } + c = buf[++j]; + } + if ( i > 1 ) + writer.insertInIndex(QString(str,i), docNum); + + docNum++; + writer.insertInDocumentList(title, url); + } + + if (writer.writeIndex()) { + engine.setCustomValue(key, addNamespace( + engine.customValue(key).toString(), namespaceName)); + } + + writer.reset(); + } + } + + QStringListIterator qsli(indexedNamespaces); + while (qsli.hasNext()) { + const QString namespaceName = qsli.next(); + if (namespaces.contains(namespaceName)) + continue; + + const QList attributeSets = + engine.filterAttributeSets(namespaceName); + + foreach (const QStringList &attributes, attributeSets) { + writer.setIndexFile(namespaceName, attributes.join(QLatin1String("@"))); + writer.removeIndex(); + } + + engine.setCustomValue(key, removeNamespace( + engine.customValue(key).toString(), namespaceName)); + } + + emit indexingFinished(); +} + +QString QHelpSearchIndexWriter::addNamespace(const QString namespaces, + const QString &namespaceName) +{ + QString value = namespaces; + if (!value.contains(namespaceName)) + value.append(namespaceName).append(QLatin1String("|")); + + return value; +} + +QString QHelpSearchIndexWriter::removeNamespace(const QString namespaces, + const QString &namespaceName) +{ + QString value = namespaces; + if (value.contains(namespaceName)) + value.remove(namespaceName + QLatin1String("|")); + + return value; +} + +} // namespace std +} // namespace fulltextsearch + +QT_END_NAMESPACE diff --git a/src/assistant/lib/qhelpsearchindexwriter_default_p.h b/src/assistant/lib/qhelpsearchindexwriter_default_p.h new file mode 100644 index 000000000..d510fbc9d --- /dev/null +++ b/src/assistant/lib/qhelpsearchindexwriter_default_p.h @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHINDEXWRITERDEFAULT_H +#define QHELPSEARCHINDEXWRITERDEFAULT_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the help generator tools. This header file may change from version +// to version without notice, or even be removed. +// +// We mean it. +// + +#include "qhelpsearchindex_default_p.h" + +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace fulltextsearch { +namespace std { + +class Writer +{ +public: + Writer(const QString &path); + ~Writer(); + + void reset(); + bool writeIndex() const; + void removeIndex() const; + void setIndexFile(const QString &namespaceName, const QString &attributes); + void insertInIndex(const QString &string, int docNum); + void insertInDocumentList(const QString &title, const QString &url); + +private: + QString indexPath; + QString indexFile; + QString documentFile; + + QHash index; + QList documentList; +}; + + +class QHelpSearchIndexWriter : public QThread +{ + Q_OBJECT + +public: + QHelpSearchIndexWriter(); + ~QHelpSearchIndexWriter(); + + void cancelIndexing(); + void updateIndex(const QString &collectionFile, + const QString &indexFilesFolder, bool reindex); + +signals: + void indexingStarted(); + void indexingFinished(); + +private: + void run(); + QString addNamespace(const QString namespaces, const QString &namespaceName); + QString removeNamespace(const QString namespaces, const QString &namespaceName); + +private: + QMutex mutex; + QWaitCondition waitCondition; + + bool m_cancel; + bool m_reindex; + QString m_collectionFile; + QString m_indexFilesFolder; +}; + +} // namespace std +} // namespace fulltextsearch + +QT_END_NAMESPACE + +#endif // QHELPSEARCHINDEXWRITERDEFAULT_H diff --git a/src/assistant/lib/qhelpsearchquerywidget.cpp b/src/assistant/lib/qhelpsearchquerywidget.cpp new file mode 100644 index 000000000..e6a789a40 --- /dev/null +++ b/src/assistant/lib/qhelpsearchquerywidget.cpp @@ -0,0 +1,587 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpsearchquerywidget.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QHelpSearchQueryWidgetPrivate : public QObject +{ + Q_OBJECT + +private: + struct QueryHistory { + explicit QueryHistory() : curQuery(-1) {} + QList > queries; + int curQuery; + }; + + class CompleterModel : public QAbstractListModel + { + public: + explicit CompleterModel(QObject *parent) + : QAbstractListModel(parent) {} + + int rowCount(const QModelIndex &parent = QModelIndex()) const + { + return parent.isValid() ? 0 : termList.size(); + } + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const + { + if (!index.isValid() || index.row() >= termList.count()|| + (role != Qt::EditRole && role != Qt::DisplayRole)) + return QVariant(); + return termList.at(index.row()); + } + + void addTerm(const QString &term) + { + if (!termList.contains(term)) { + termList.append(term); + reset(); + } + } + + private: + QStringList termList; + }; + + QHelpSearchQueryWidgetPrivate() + : QObject() + , simpleSearch(true) + , searchCompleter(new CompleterModel(this), this) + { + searchButton = 0; + advancedSearchWidget = 0; + showHideAdvancedSearchButton = 0; + defaultQuery = 0; + exactQuery = 0; + similarQuery = 0; + withoutQuery = 0; + allQuery = 0; + atLeastQuery = 0; + } + + ~QHelpSearchQueryWidgetPrivate() + { + // nothing todo + } + + void retranslate() + { + simpleSearchLabel->setText(QHelpSearchQueryWidget::tr("Search for:")); + prevQueryButton->setToolTip(QHelpSearchQueryWidget::tr("Previous search")); + nextQueryButton->setToolTip(QHelpSearchQueryWidget::tr("Next search")); + searchButton->setText(QHelpSearchQueryWidget::tr("Search")); +#ifdef QT_CLUCENE_SUPPORT + advancedSearchLabel->setText(QHelpSearchQueryWidget::tr("Advanced search")); + similarLabel->setText(QHelpSearchQueryWidget::tr("words similar to:")); + withoutLabel->setText(QHelpSearchQueryWidget::tr("without the words:")); + exactLabel->setText(QHelpSearchQueryWidget::tr("with exact phrase:")); + allLabel->setText(QHelpSearchQueryWidget::tr("with all of the words:")); + atLeastLabel->setText(QHelpSearchQueryWidget::tr("with at least one of the words:")); +#endif + } + + QStringList buildTermList(const QString query) + { + bool s = false; + QString phrase; + QStringList wordList; + QString searchTerm = query; + + for (int i = 0; i < searchTerm.length(); ++i) { + if (searchTerm[i] == QLatin1Char('\"') && !s) { + s = true; + phrase = searchTerm[i]; + continue; + } + if (searchTerm[i] != QLatin1Char('\"') && s) + phrase += searchTerm[i]; + if (searchTerm[i] == QLatin1Char('\"') && s) { + s = false; + phrase += searchTerm[i]; + wordList.append(phrase); + searchTerm.remove(phrase); + } + } + if (s) + searchTerm.replace(phrase, phrase.mid(1)); + + const QRegExp exp(QLatin1String("\\s+")); + wordList += searchTerm.split(exp, QString::SkipEmptyParts); + return wordList; + } + + void saveQuery(const QList &query, QueryHistory &queryHist) + { + // We only add the query to the list if it is different from the last one. + bool insert = false; + if (queryHist.queries.empty()) + insert = true; + else { + const QList &lastQuery = queryHist.queries.last(); + if (lastQuery.size() != query.size()) { + insert = true; + } else { + for (int i = 0; i < query.size(); ++i) { + if (query.at(i).fieldName != lastQuery.at(i).fieldName + || query.at(i).wordList != lastQuery.at(i).wordList) { + insert = true; + break; + } + } + } + } + if (insert) { + queryHist.queries.append(query); + foreach (const QHelpSearchQuery &queryPart, query) { + static_cast(searchCompleter.model())-> + addTerm(queryPart.wordList.join(" ")); + } + } + } + + void nextOrPrevQuery(int maxOrMinIndex, int addend, QToolButton *thisButton, + QToolButton *otherButton) + { + QueryHistory *queryHist; + QList lineEdits; + if (simpleSearch) { + queryHist = &simpleQueries; + lineEdits << defaultQuery; + } else { + queryHist = &complexQueries; + lineEdits << allQuery << atLeastQuery << similarQuery + << withoutQuery << exactQuery; + } + foreach (QLineEdit *lineEdit, lineEdits) + lineEdit->clear(); + + // Otherwise, the respective button would be disabled. + Q_ASSERT(queryHist->curQuery != maxOrMinIndex); + + queryHist->curQuery += addend; + const QList &query = + queryHist->queries.at(queryHist->curQuery); + foreach (const QHelpSearchQuery &queryPart, query) { + if (QLineEdit *lineEdit = lineEditFor(queryPart.fieldName)) + lineEdit->setText(queryPart.wordList.join(" ")); + } + + if (queryHist->curQuery == maxOrMinIndex) + thisButton->setEnabled(false); + otherButton->setEnabled(true); + } + + QLineEdit* lineEditFor(const QHelpSearchQuery::FieldName &fieldName) const + { + switch (fieldName) { + case QHelpSearchQuery::DEFAULT: + return defaultQuery; + case QHelpSearchQuery::ALL: + return allQuery; + case QHelpSearchQuery::ATLEAST: + return atLeastQuery; + case QHelpSearchQuery::FUZZY: + return similarQuery; + case QHelpSearchQuery::WITHOUT: + return withoutQuery; + case QHelpSearchQuery::PHRASE: + return exactQuery; + default: + Q_ASSERT(0); + } + return 0; + } + + void enableOrDisableToolButtons() + { + const QueryHistory &queryHist = simpleSearch ? simpleQueries + : complexQueries; + prevQueryButton->setEnabled(queryHist.curQuery > 0); + nextQueryButton->setEnabled(queryHist.curQuery + < queryHist.queries.size() - 1); + } + +private slots: + void showHideAdvancedSearch() + { + if (simpleSearch) { + advancedSearchWidget->show(); + showHideAdvancedSearchButton->setText((QLatin1String("-"))); + } else { + advancedSearchWidget->hide(); + showHideAdvancedSearchButton->setText((QLatin1String("+"))); + } + + simpleSearch = !simpleSearch; + defaultQuery->setEnabled(simpleSearch); + enableOrDisableToolButtons(); + } + + void searchRequested() + { + QList queryList; +#if !defined(QT_CLUCENE_SUPPORT) + queryList.append(QHelpSearchQuery(QHelpSearchQuery::DEFAULT, + QStringList(defaultQuery->text()))); + +#else + if (defaultQuery->isEnabled()) { + queryList.append(QHelpSearchQuery(QHelpSearchQuery::DEFAULT, + buildTermList(defaultQuery->text()))); + } else { + const QRegExp exp(QLatin1String("\\s+")); + QStringList lst = similarQuery->text().split(exp, + QString::SkipEmptyParts); + if (!lst.isEmpty()) { + QStringList fuzzy; + foreach (const QString &term, lst) + fuzzy += buildTermList(term); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::FUZZY, + fuzzy)); + } + + lst = withoutQuery->text().split(exp, QString::SkipEmptyParts); + if (!lst.isEmpty()) { + QStringList without; + foreach (const QString &term, lst) + without.append(term); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::WITHOUT, + without)); + } + + if (!exactQuery->text().isEmpty()) { + QString phrase = exactQuery->text().remove(QLatin1Char('\"')); + phrase = phrase.simplified(); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::PHRASE, + QStringList(phrase))); + } + + lst = allQuery->text().split(exp, QString::SkipEmptyParts); + if (!lst.isEmpty()) { + QStringList all; + foreach (const QString &term, lst) + all.append(term); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::ALL, all)); + } + + lst = atLeastQuery->text().split(exp, QString::SkipEmptyParts); + if (!lst.isEmpty()) { + QStringList atLeast; + foreach (const QString &term, lst) + atLeast += buildTermList(term); + queryList.append(QHelpSearchQuery(QHelpSearchQuery::ATLEAST, + atLeast)); + } + } +#endif + QueryHistory &queryHist = simpleSearch ? simpleQueries : complexQueries; + saveQuery(queryList, queryHist); + queryHist.curQuery = queryHist.queries.size() - 1; + if (queryHist.curQuery > 0) + prevQueryButton->setEnabled(true); + nextQueryButton->setEnabled(false); + } + + void nextQuery() + { + nextOrPrevQuery((simpleSearch ? simpleQueries + : complexQueries).queries.size() - 1, 1, nextQueryButton, + prevQueryButton); + } + + void prevQuery() + { + nextOrPrevQuery(0, -1, prevQueryButton, nextQueryButton); + } + +private: + friend class QHelpSearchQueryWidget; + + bool simpleSearch; + QLabel *simpleSearchLabel; + QLabel *advancedSearchLabel; + QLabel *similarLabel; + QLabel *withoutLabel; + QLabel *exactLabel; + QLabel *allLabel; + QLabel *atLeastLabel; + QPushButton *searchButton; + QWidget* advancedSearchWidget; + QToolButton *showHideAdvancedSearchButton; + QLineEdit *defaultQuery; + QLineEdit *exactQuery; + QLineEdit *similarQuery; + QLineEdit *withoutQuery; + QLineEdit *allQuery; + QLineEdit *atLeastQuery; + QToolButton *nextQueryButton; + QToolButton *prevQueryButton; + QueryHistory simpleQueries; + QueryHistory complexQueries; + QCompleter searchCompleter; +}; + +#include "qhelpsearchquerywidget.moc" + + +/*! + \class QHelpSearchQueryWidget + \since 4.4 + \inmodule QtHelp + \brief The QHelpSearchQueryWidget class provides a simple line edit or + an advanced widget to enable the user to input a search term in a + standardized input mask. +*/ + +/*! + \fn void QHelpSearchQueryWidget::search() + + This signal is emitted when a the user has the search button invoked. + After reciving the signal you can ask the QHelpSearchQueryWidget for the + build list of QHelpSearchQuery's that you may pass to the QHelpSearchEngine's + search() function. +*/ + +/*! + Constructs a new search query widget with the given \a parent. +*/ +QHelpSearchQueryWidget::QHelpSearchQueryWidget(QWidget *parent) + : QWidget(parent) +{ + d = new QHelpSearchQueryWidgetPrivate(); + + QVBoxLayout *vLayout = new QVBoxLayout(this); + vLayout->setMargin(0); + + QHBoxLayout* hBoxLayout = new QHBoxLayout(); + d->simpleSearchLabel = new QLabel(this); + d->defaultQuery = new QLineEdit(this); + d->defaultQuery->setCompleter(&d->searchCompleter); + d->prevQueryButton = new QToolButton(this); + d->prevQueryButton->setArrowType(Qt::LeftArrow); + d->prevQueryButton->setEnabled(false); + d->nextQueryButton = new QToolButton(this); + d->nextQueryButton->setArrowType(Qt::RightArrow); + d->nextQueryButton->setEnabled(false); + d->searchButton = new QPushButton(this); + hBoxLayout->addWidget(d->simpleSearchLabel); + hBoxLayout->addWidget(d->defaultQuery); + hBoxLayout->addWidget(d->prevQueryButton); + hBoxLayout->addWidget(d->nextQueryButton); + hBoxLayout->addWidget(d->searchButton); + + vLayout->addLayout(hBoxLayout); + + connect(d->prevQueryButton, SIGNAL(clicked()), d, SLOT(prevQuery())); + connect(d->nextQueryButton, SIGNAL(clicked()), d, SLOT(nextQuery())); + connect(d->searchButton, SIGNAL(clicked()), this, SIGNAL(search())); + connect(d->defaultQuery, SIGNAL(returnPressed()), this, SIGNAL(search())); + +#if defined(QT_CLUCENE_SUPPORT) + hBoxLayout = new QHBoxLayout(); + d->showHideAdvancedSearchButton = new QToolButton(this); + d->showHideAdvancedSearchButton->setText(QLatin1String("+")); + d->showHideAdvancedSearchButton->setMinimumSize(25, 20); + + d->advancedSearchLabel = new QLabel(this); + QSizePolicy sizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); + sizePolicy.setHeightForWidth(d->advancedSearchLabel->sizePolicy().hasHeightForWidth()); + d->advancedSearchLabel->setSizePolicy(sizePolicy); + + QFrame* hLine = new QFrame(this); + hLine->setFrameStyle(QFrame::HLine); + hBoxLayout->addWidget(d->showHideAdvancedSearchButton); + hBoxLayout->addWidget(d->advancedSearchLabel); + hBoxLayout->addWidget(hLine); + + vLayout->addLayout(hBoxLayout); + + // setup advanced search layout + d->advancedSearchWidget = new QWidget(this); + QGridLayout *gLayout = new QGridLayout(d->advancedSearchWidget); + gLayout->setMargin(0); + + d->similarLabel = new QLabel(this); + gLayout->addWidget(d->similarLabel, 0, 0); + d->similarQuery = new QLineEdit(this); + d->similarQuery->setCompleter(&d->searchCompleter); + gLayout->addWidget(d->similarQuery, 0, 1); + + d->withoutLabel = new QLabel(this); + gLayout->addWidget(d->withoutLabel, 1, 0); + d->withoutQuery = new QLineEdit(this); + d->withoutQuery->setCompleter(&d->searchCompleter); + gLayout->addWidget(d->withoutQuery, 1, 1); + + d->exactLabel = new QLabel(this); + gLayout->addWidget(d->exactLabel, 2, 0); + d->exactQuery = new QLineEdit(this); + d->exactQuery->setCompleter(&d->searchCompleter); + gLayout->addWidget(d->exactQuery, 2, 1); + + d->allLabel = new QLabel(this); + gLayout->addWidget(d->allLabel, 3, 0); + d->allQuery = new QLineEdit(this); + d->allQuery->setCompleter(&d->searchCompleter); + gLayout->addWidget(d->allQuery, 3, 1); + + d->atLeastLabel = new QLabel(this); + gLayout->addWidget(d->atLeastLabel, 4, 0); + d->atLeastQuery = new QLineEdit(this); + d->atLeastQuery->setCompleter(&d->searchCompleter); + gLayout->addWidget(d->atLeastQuery, 4, 1); + + vLayout->addWidget(d->advancedSearchWidget); + d->advancedSearchWidget->hide(); + + d->retranslate(); + + connect(d->exactQuery, SIGNAL(returnPressed()), this, SIGNAL(search())); + connect(d->similarQuery, SIGNAL(returnPressed()), this, SIGNAL(search())); + connect(d->withoutQuery, SIGNAL(returnPressed()), this, SIGNAL(search())); + connect(d->allQuery, SIGNAL(returnPressed()), this, SIGNAL(search())); + connect(d->atLeastQuery, SIGNAL(returnPressed()), this, SIGNAL(search())); + connect(d->showHideAdvancedSearchButton, SIGNAL(clicked()), + d, SLOT(showHideAdvancedSearch())); +#endif + connect(this, SIGNAL(search()), d, SLOT(searchRequested())); +} + +/*! + Destroys the search query widget. +*/ +QHelpSearchQueryWidget::~QHelpSearchQueryWidget() +{ + delete d; +} + +/*! + Expands the search query widget so that the extended search fields are shown. +*/ +void QHelpSearchQueryWidget::expandExtendedSearch() +{ + if (d->simpleSearch) + d->showHideAdvancedSearch(); +} + +/*! + Collapses the search query widget so that only the default search field is + shown. +*/ +void QHelpSearchQueryWidget::collapseExtendedSearch() +{ + if (!d->simpleSearch) + d->showHideAdvancedSearch(); +} + +/*! + Returns a list of queries to use in combination with the search engines + search(QList &queryList) function. +*/ +QList QHelpSearchQueryWidget::query() const +{ + const QHelpSearchQueryWidgetPrivate::QueryHistory &queryHist = + d->simpleSearch ? d->simpleQueries : d->complexQueries; + return queryHist.queries.isEmpty() ? + QList() : queryHist.queries.last(); +} + +/*! + Sets the QHelpSearchQueryWidget input fields to the values specified by + \a queryList search field name. Please note that one has to call the search + engine's search(QList &queryList) function to perform the + actual search. +*/ +void QHelpSearchQueryWidget::setQuery(const QList &queryList) +{ + QList lineEdits; + lineEdits << d->defaultQuery << d->allQuery << d->atLeastQuery + << d->similarQuery << d->withoutQuery << d->exactQuery; + foreach (QLineEdit *lineEdit, lineEdits) + lineEdit->clear(); + + const QLatin1String space(" "); + foreach (const QHelpSearchQuery &q, queryList) { + if (QLineEdit *lineEdit = d->lineEditFor(q.fieldName)) + lineEdit->setText(lineEdit->text() + q.wordList.join(space) + space); + } + d->searchRequested(); +} + +/*! + \reimp +*/ +void QHelpSearchQueryWidget::focusInEvent(QFocusEvent *focusEvent) +{ + if (focusEvent->reason() != Qt::MouseFocusReason) { + d->defaultQuery->selectAll(); + d->defaultQuery->setFocus(); + } +} + +/*! \reimp +*/ +void QHelpSearchQueryWidget::changeEvent(QEvent *event) +{ + if (event->type() == QEvent::LanguageChange) + d->retranslate(); + else + QWidget::changeEvent(event); +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/qhelpsearchquerywidget.h b/src/assistant/lib/qhelpsearchquerywidget.h new file mode 100644 index 000000000..e9fb61ceb --- /dev/null +++ b/src/assistant/lib/qhelpsearchquerywidget.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHQUERYWIDGET_H +#define QHELPSEARCHQUERYWIDGET_H + +#include +#include + +#include +#include +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +class QFocusEvent; +class QHelpSearchQueryWidgetPrivate; + +class QHELP_EXPORT QHelpSearchQueryWidget : public QWidget +{ + Q_OBJECT + +public: + QHelpSearchQueryWidget(QWidget *parent = 0); + ~QHelpSearchQueryWidget(); + + void expandExtendedSearch(); + void collapseExtendedSearch(); + + QList query() const; + void setQuery(const QList &queryList); + +Q_SIGNALS: + void search(); + +private: + virtual void focusInEvent(QFocusEvent *focusEvent); + virtual void changeEvent(QEvent *event); + +private: + QHelpSearchQueryWidgetPrivate *d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QHELPSEARCHQUERYWIDGET_H diff --git a/src/assistant/lib/qhelpsearchresultwidget.cpp b/src/assistant/lib/qhelpsearchresultwidget.cpp new file mode 100644 index 000000000..2b5845062 --- /dev/null +++ b/src/assistant/lib/qhelpsearchresultwidget.cpp @@ -0,0 +1,447 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qhelpsearchresultwidget.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDefaultResultWidget : public QTreeWidget +{ + Q_OBJECT + +public: + QDefaultResultWidget(QWidget *parent = 0) + : QTreeWidget(parent) + { + header()->hide(); + connect(this, SIGNAL(itemActivated(QTreeWidgetItem*,int)), + this, SLOT(itemActivated(QTreeWidgetItem*,int))); + } + + void showResultPage(const QList hits) + { + foreach (const QHelpSearchEngine::SearchHit &hit, hits) + new QTreeWidgetItem(this, QStringList(hit.first) << hit.second); + } + +signals: + void requestShowLink(const QUrl &url); + +private slots: + void itemActivated(QTreeWidgetItem *item, int /* column */) + { + if (item) { + QString data = item->data(1, Qt::DisplayRole).toString(); + emit requestShowLink(data); + } + } +}; + + +class QCLuceneResultWidget : public QTextBrowser +{ + Q_OBJECT + +public: + QCLuceneResultWidget(QWidget *parent = 0) + : QTextBrowser(parent) + { + connect(this, SIGNAL(anchorClicked(QUrl)), + this, SIGNAL(requestShowLink(QUrl))); + setContextMenuPolicy(Qt::NoContextMenu); + } + + void showResultPage(const QList hits, bool isIndexing) + { + QString htmlFile = QString(QLatin1String("%1")) + .arg(tr("Search Results")); + + int count = hits.count(); + if (count != 0) { + if (isIndexing) + htmlFile += QString(QLatin1String("
" + "%1 " + "%2

")).arg(tr("Note:")) + .arg(tr("The search results may not be complete since the " + "documentation is still being indexed!")); + + foreach (const QHelpSearchEngine::SearchHit &hit, hits) { + htmlFile += QString(QLatin1String("
%2
%1

")) + .arg(hit.first).arg(hit.second); + } + } else { + htmlFile += QLatin1String("


") + + tr("Your search did not match any documents.") + + QLatin1String("

"); + if (isIndexing) + htmlFile += QLatin1String("

") + + tr("(The reason for this might be that the documentation " + "is still being indexed.)") + + QLatin1String("

"); + } + + htmlFile += QLatin1String(""); + + setHtml(htmlFile); + } + +signals: + void requestShowLink(const QUrl &url); + +private slots: + void setSource(const QUrl & /* name */) {} +}; + + +class QHelpSearchResultWidgetPrivate : public QObject +{ + Q_OBJECT + +private slots: + void setResults(int hitsCount) + { + if (!searchEngine.isNull()) { +#if defined(QT_CLUCENE_SUPPORT) + showFirstResultPage(); + updateNextButtonState(((hitsCount > 20) ? true : false)); +#else + resultTreeWidget->clear(); + resultTreeWidget->showResultPage(searchEngine->hits(0, hitsCount)); +#endif + } + } + + void showNextResultPage() + { + if (!searchEngine.isNull() + && resultLastToShow < searchEngine->hitCount()) { + resultLastToShow += 20; + resultFirstToShow += 20; + + resultTextBrowser->showResultPage(searchEngine->hits(resultFirstToShow, + resultLastToShow), isIndexing); + if (resultLastToShow >= searchEngine->hitCount()) + updateNextButtonState(false); + } + updateHitRange(); + } + + void showLastResultPage() + { + if (!searchEngine.isNull()) { + resultLastToShow = searchEngine->hitCount(); + resultFirstToShow = resultLastToShow - (resultLastToShow % 20); + + if (resultFirstToShow == resultLastToShow) + resultFirstToShow -= 20; + + resultTextBrowser->showResultPage(searchEngine->hits(resultFirstToShow, + resultLastToShow), isIndexing); + updateNextButtonState(false); + } + updateHitRange(); + } + + void showFirstResultPage() + { + if (!searchEngine.isNull()) { + resultLastToShow = 20; + resultFirstToShow = 0; + + resultTextBrowser->showResultPage(searchEngine->hits(resultFirstToShow, + resultLastToShow), isIndexing); + updatePrevButtonState(false); + } + updateHitRange(); + } + + void showPreviousResultPage() + { + if (!searchEngine.isNull()) { + int count = resultLastToShow % 20; + if (count == 0 || resultLastToShow != searchEngine->hitCount()) + count = 20; + + resultLastToShow -= count; + resultFirstToShow = resultLastToShow -20; + + resultTextBrowser->showResultPage(searchEngine->hits(resultFirstToShow, + resultLastToShow), isIndexing); + if (resultFirstToShow == 0) + updatePrevButtonState(false); + } + updateHitRange(); + } + + void updatePrevButtonState(bool state = true) + { + firstResultPage->setEnabled(state); + previousResultPage->setEnabled(state); + } + + void updateNextButtonState(bool state = true) + { + nextResultPage->setEnabled(state); + lastResultPage->setEnabled(state); + } + + void indexingStarted() + { + isIndexing = true; + } + + void indexingFinished() + { + isIndexing = false; + } + +private: + QHelpSearchResultWidgetPrivate(QHelpSearchEngine *engine) + : QObject() + , searchEngine(engine) + , isIndexing(false) + { + resultTreeWidget = 0; + resultTextBrowser = 0; + + resultLastToShow = 20; + resultFirstToShow = 0; + + firstResultPage = 0; + previousResultPage = 0; + hitsLabel = 0; + nextResultPage = 0; + lastResultPage = 0; + + connect(searchEngine, SIGNAL(indexingStarted()), + this, SLOT(indexingStarted())); + connect(searchEngine, SIGNAL(indexingFinished()), + this, SLOT(indexingFinished())); + } + + ~QHelpSearchResultWidgetPrivate() + { + delete searchEngine; + } + + QToolButton* setupToolButton(const QString &iconPath) + { + QToolButton *button = new QToolButton(); + button->setEnabled(false); + button->setAutoRaise(true); + button->setIcon(QIcon(iconPath)); + button->setIconSize(QSize(12, 12)); + button->setMaximumSize(QSize(16, 16)); + + return button; + } + + void updateHitRange() + { + int last = 0; + int first = 0; + int count = 0; + + if (!searchEngine.isNull()) { + count = searchEngine->hitCount(); + if (count > 0) { + first = resultFirstToShow +1; + last = resultLastToShow > count ? count : resultLastToShow; + } + } + hitsLabel->setText(QHelpSearchResultWidget::tr("%1 - %2 of %n Hits", 0, count).arg(first).arg(last)); + } + +private: + friend class QHelpSearchResultWidget; + + QPointer searchEngine; + + QDefaultResultWidget *resultTreeWidget; + QCLuceneResultWidget *resultTextBrowser; + + int resultLastToShow; + int resultFirstToShow; + bool isIndexing; + + QToolButton *firstResultPage; + QToolButton *previousResultPage; + QLabel *hitsLabel; + QToolButton *nextResultPage; + QToolButton *lastResultPage; +}; + +#include "qhelpsearchresultwidget.moc" + + +/*! + \class QHelpSearchResultWidget + \since 4.4 + \inmodule QtHelp + \brief The QHelpSearchResultWidget class provides either a tree + widget or a text browser depending on the used search engine to display + the hits found by the search. +*/ + +/*! + \fn void QHelpSearchResultWidget::requestShowLink(const QUrl &link) + + This signal is emitted when a item is activated and its associated + \a link should be shown. +*/ + +QHelpSearchResultWidget::QHelpSearchResultWidget(QHelpSearchEngine *engine) + : QWidget(0) + , d(new QHelpSearchResultWidgetPrivate(engine)) +{ + QVBoxLayout *vLayout = new QVBoxLayout(this); + vLayout->setMargin(0); + vLayout->setSpacing(0); + +#if defined(QT_CLUCENE_SUPPORT) + QHBoxLayout *hBoxLayout = new QHBoxLayout(); +#ifndef Q_OS_MAC + hBoxLayout->setMargin(0); + hBoxLayout->setSpacing(0); +#endif + hBoxLayout->addWidget(d->firstResultPage = d->setupToolButton( + QString::fromUtf8(":/trolltech/assistant/images/3leftarrow.png"))); + + hBoxLayout->addWidget(d->previousResultPage = d->setupToolButton( + QString::fromUtf8(":/trolltech/assistant/images/1leftarrow.png"))); + + d->hitsLabel = new QLabel(tr("0 - 0 of 0 Hits"), this); + d->hitsLabel->setEnabled(false); + hBoxLayout->addWidget(d->hitsLabel); + d->hitsLabel->setAlignment(Qt::AlignCenter); + d->hitsLabel->setMinimumSize(QSize(150, d->hitsLabel->height())); + + hBoxLayout->addWidget(d->nextResultPage = d->setupToolButton( + QString::fromUtf8(":/trolltech/assistant/images/1rightarrow.png"))); + + hBoxLayout->addWidget(d->lastResultPage = d->setupToolButton( + QString::fromUtf8(":/trolltech/assistant/images/3rightarrow.png"))); + + QSpacerItem *spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + hBoxLayout->addItem(spacer); + + vLayout->addLayout(hBoxLayout); + + d->resultTextBrowser = new QCLuceneResultWidget(this); + vLayout->addWidget(d->resultTextBrowser); + + connect(d->resultTextBrowser, SIGNAL(requestShowLink(QUrl)), this, + SIGNAL(requestShowLink(QUrl))); + + connect(d->nextResultPage, SIGNAL(clicked()), d, SLOT(showNextResultPage())); + connect(d->lastResultPage, SIGNAL(clicked()), d, SLOT(showLastResultPage())); + connect(d->firstResultPage, SIGNAL(clicked()), d, SLOT(showFirstResultPage())); + connect(d->previousResultPage, SIGNAL(clicked()), d, SLOT(showPreviousResultPage())); + + connect(d->firstResultPage, SIGNAL(clicked()), d, SLOT(updateNextButtonState())); + connect(d->previousResultPage, SIGNAL(clicked()), d, SLOT(updateNextButtonState())); + connect(d->nextResultPage, SIGNAL(clicked()), d, SLOT(updatePrevButtonState())); + connect(d->lastResultPage, SIGNAL(clicked()), d, SLOT(updatePrevButtonState())); + +#else + d->resultTreeWidget = new QDefaultResultWidget(this); + vLayout->addWidget(d->resultTreeWidget); + connect(d->resultTreeWidget, SIGNAL(requestShowLink(QUrl)), this, + SIGNAL(requestShowLink(QUrl))); +#endif + + connect(engine, SIGNAL(searchingFinished(int)), d, SLOT(setResults(int))); +} + +/*! \reimp +*/ +void QHelpSearchResultWidget::changeEvent(QEvent *event) +{ + if (event->type() == QEvent::LanguageChange) + d->setResults(d->searchEngine->hitCount()); +} + +/*! + Destroys the search result widget. +*/ +QHelpSearchResultWidget::~QHelpSearchResultWidget() +{ + delete d; +} + +/*! + Returns a reference of the URL that the item at \a point owns, or an + empty URL if no item exists at that point. +*/ +QUrl QHelpSearchResultWidget::linkAt(const QPoint &point) +{ + QUrl url; +#if defined(QT_CLUCENE_SUPPORT) + if (d->resultTextBrowser) + url = d->resultTextBrowser->anchorAt(point); +#else + if (d->resultTreeWidget) { + QTreeWidgetItem *item = d->resultTreeWidget->itemAt(point); + if (item) + url = item->data(1, Qt::DisplayRole).toString(); + } +#endif + return url; +} + +QT_END_NAMESPACE diff --git a/src/assistant/lib/qhelpsearchresultwidget.h b/src/assistant/lib/qhelpsearchresultwidget.h new file mode 100644 index 000000000..cd6ac1051 --- /dev/null +++ b/src/assistant/lib/qhelpsearchresultwidget.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHELPSEARCHRESULTWIDGET_H +#define QHELPSEARCHRESULTWIDGET_H + +#include +#include + +#include +#include +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Help) + +class QHelpSearchResultWidgetPrivate; + +class QHELP_EXPORT QHelpSearchResultWidget : public QWidget +{ + Q_OBJECT + +public: + ~QHelpSearchResultWidget(); + QUrl linkAt(const QPoint &point); + +Q_SIGNALS: + void requestShowLink(const QUrl &url); + +private: + friend class QHelpSearchEngine; + + QHelpSearchResultWidgetPrivate *d; + QHelpSearchResultWidget(QHelpSearchEngine *engine); + virtual void changeEvent(QEvent *event); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QHELPSEARCHRESULTWIDGET_H diff --git a/src/assistant/tools/assistant/Info_mac.plist b/src/assistant/tools/assistant/Info_mac.plist new file mode 100644 index 000000000..76369a1c5 --- /dev/null +++ b/src/assistant/tools/assistant/Info_mac.plist @@ -0,0 +1,18 @@ + + + + + CFBundleIconFile + @ICON@ + CFBundlePackageType + APPL + CFBundleGetInfoString + Created by Qt/QMake + CFBundleSignature + ???? + CFBundleIdentifier + com.trolltech.assistant + CFBundleExecutable + @EXECUTABLE@ + + diff --git a/src/assistant/tools/assistant/aboutdialog.cpp b/src/assistant/tools/assistant/aboutdialog.cpp new file mode 100644 index 000000000..b4c390e90 --- /dev/null +++ b/src/assistant/tools/assistant/aboutdialog.cpp @@ -0,0 +1,184 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "aboutdialog.h" + +#include "helpviewer.h" +#include "tracer.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +AboutLabel::AboutLabel(QWidget *parent) + : QTextBrowser(parent) +{ + TRACE_OBJ + setFrameStyle(QFrame::NoFrame); + QPalette p; + p.setColor(QPalette::Base, p.color(QPalette::Background)); + setPalette(p); +} + +void AboutLabel::setText(const QString &text, const QByteArray &resources) +{ + TRACE_OBJ + QDataStream in(resources); + in >> m_resourceMap; + + QTextBrowser::setText(text); +} + +QSize AboutLabel::minimumSizeHint() const +{ + TRACE_OBJ + QTextDocument *doc = document(); + doc->adjustSize(); + return QSize(int(doc->size().width()), int(doc->size().height())); +} + +QVariant AboutLabel::loadResource(int type, const QUrl &name) +{ + TRACE_OBJ + if (type == 2 || type == 3) { + if (m_resourceMap.contains(name.toString())) { + return m_resourceMap.value(name.toString()); + } + } + return QVariant(); +} + +void AboutLabel::setSource(const QUrl &url) +{ + TRACE_OBJ + if (url.isValid() && (!HelpViewer::isLocalUrl(url) + || !HelpViewer::canOpenPage(url.path()))) { + if (!QDesktopServices::openUrl(url)) { + QMessageBox::warning(this, tr("Warning"), + tr("Unable to launch external application.\n"), tr("OK")); + } + } +} + +AboutDialog::AboutDialog(QWidget *parent) + : QDialog(parent, Qt::MSWindowsFixedSizeDialogHint | + Qt::WindowTitleHint|Qt::WindowSystemMenuHint) +{ + TRACE_OBJ + m_pixmapLabel = 0; + m_aboutLabel = new AboutLabel(); + + m_closeButton = new QPushButton(); + m_closeButton->setText(tr("&Close")); + connect(m_closeButton, SIGNAL(clicked()), this, SLOT(close())); + + m_layout = new QGridLayout(this); + m_layout->addWidget(m_aboutLabel, 1, 0, 1, -1); + m_layout->addItem(new QSpacerItem(20, 10, QSizePolicy::Minimum, + QSizePolicy::Fixed), 2, 1, 1, 1); + m_layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Expanding), 3, 0, 1, 1); + m_layout->addWidget(m_closeButton, 3, 1, 1, 1); + m_layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Expanding), 3, 2, 1, 1); +} + +void AboutDialog::setText(const QString &text, const QByteArray &resources) +{ + TRACE_OBJ + m_aboutLabel->setText(text, resources); + updateSize(); +} + +void AboutDialog::setPixmap(const QPixmap &pixmap) +{ + TRACE_OBJ + if (!m_pixmapLabel) { + m_pixmapLabel = new QLabel(); + m_layout->addWidget(m_pixmapLabel, 0, 0, 1, -1, Qt::AlignCenter); + } + m_pixmapLabel->setPixmap(pixmap); + updateSize(); +} + +QString AboutDialog::documentTitle() const +{ + TRACE_OBJ + return m_aboutLabel->documentTitle(); +} + +void AboutDialog::updateSize() +{ + TRACE_OBJ + QSize screenSize = QApplication::desktop()->availableGeometry(QCursor::pos()) + .size(); + int limit = qMin(screenSize.width()/2, 500); + +#ifdef Q_WS_MAC + limit = qMin(screenSize.width()/2, 420); +#endif + + layout()->activate(); + int width = layout()->totalMinimumSize().width(); + + if (width > limit) + width = limit; + + QFontMetrics fm(qApp->font("QWorkspaceTitleBar")); + int windowTitleWidth = qMin(fm.width(windowTitle()) + 50, limit); + if (windowTitleWidth > width) + width = windowTitleWidth; + + layout()->activate(); + int height = (layout()->hasHeightForWidth()) + ? layout()->totalHeightForWidth(width) + : layout()->totalMinimumSize().height(); + setFixedSize(width, height); + QCoreApplication::removePostedEvents(this, QEvent::LayoutRequest); +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/aboutdialog.h b/src/assistant/tools/assistant/aboutdialog.h new file mode 100644 index 000000000..292312d05 --- /dev/null +++ b/src/assistant/tools/assistant/aboutdialog.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABOUTDIALOG_H +#define ABOUTDIALOG_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class QLabel; +class QPushButton; +class QGridLayout; + +class AboutLabel : public QTextBrowser +{ + Q_OBJECT + +public: + AboutLabel(QWidget *parent = 0); + void setText(const QString &text, const QByteArray &resources); + QSize minimumSizeHint() const; + +private: + QVariant loadResource(int type, const QUrl &name); + void setSource(const QUrl &url); + + QMap m_resourceMap; +}; + +class AboutDialog : public QDialog +{ + Q_OBJECT + +public: + AboutDialog(QWidget *parent = 0); + void setText(const QString &text, const QByteArray &resources); + void setPixmap(const QPixmap &pixmap); + QString documentTitle() const; + +private: + void updateSize(); + + QLabel *m_pixmapLabel; + AboutLabel *m_aboutLabel; + QPushButton *m_closeButton; + QGridLayout *m_layout; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/assistant/tools/assistant/assistant.icns b/src/assistant/tools/assistant/assistant.icns new file mode 100644 index 000000000..6291dd397 Binary files /dev/null and b/src/assistant/tools/assistant/assistant.icns differ diff --git a/src/assistant/tools/assistant/assistant.ico b/src/assistant/tools/assistant/assistant.ico new file mode 100644 index 000000000..9e1b83f1b Binary files /dev/null and b/src/assistant/tools/assistant/assistant.ico differ diff --git a/src/assistant/tools/assistant/assistant.pro b/src/assistant/tools/assistant/assistant.pro new file mode 100644 index 000000000..7f0fdd158 --- /dev/null +++ b/src/assistant/tools/assistant/assistant.pro @@ -0,0 +1,118 @@ +include(../../../shared/fontpanel/fontpanel.pri) +TEMPLATE = app +LANGUAGE = C++ +TARGET = assistant +contains(QT_CONFIG, webkit):QT += webkit +CONFIG += qt \ + warn_on \ + help +QT += network +PROJECTNAME = Assistant +DESTDIR = ../../../../bin +target.path = $$[QT_INSTALL_BINS] +INSTALLS += target +DEPENDPATH += ../shared +DEPENDPATH += . +INCLUDEPATH += . + +# ## Work around a qmake issue when statically linking to +# ## not-yet-installed plugins +QMAKE_LIBDIR += $$QT_BUILD_TREE/plugins/sqldrivers +HEADERS += aboutdialog.h \ + bookmarkdialog.h \ + bookmarkfiltermodel.h \ + bookmarkitem.h \ + bookmarkmanager.h \ + bookmarkmanagerwidget.h \ + bookmarkmodel.h \ + centralwidget.h \ + cmdlineparser.h \ + contentwindow.h \ + findwidget.h \ + filternamedialog.h \ + helpenginewrapper.h \ + helpviewer.h \ + helpviewer_p.h \ + indexwindow.h \ + installdialog.h \ + mainwindow.h \ + preferencesdialog.h \ + qtdocinstaller.h \ + remotecontrol.h \ + searchwidget.h \ + topicchooser.h \ + tracer.h \ + xbelsupport.h \ + ../shared/collectionconfiguration.h \ + openpagesmodel.h \ + globalactions.h \ + openpageswidget.h \ + openpagesmanager.h \ + openpagesswitcher.h +win32:HEADERS += remotecontrol_win.h + +SOURCES += aboutdialog.cpp \ + bookmarkdialog.cpp \ + bookmarkfiltermodel.cpp \ + bookmarkitem.cpp \ + bookmarkmanager.cpp \ + bookmarkmanagerwidget.cpp \ + bookmarkmodel.cpp \ + centralwidget.cpp \ + cmdlineparser.cpp \ + contentwindow.cpp \ + findwidget.cpp \ + filternamedialog.cpp \ + helpenginewrapper.cpp \ + helpviewer.cpp \ + indexwindow.cpp \ + installdialog.cpp \ + main.cpp \ + mainwindow.cpp \ + preferencesdialog.cpp \ + qtdocinstaller.cpp \ + remotecontrol.cpp \ + searchwidget.cpp \ + topicchooser.cpp \ + xbelsupport.cpp \ + ../shared/collectionconfiguration.cpp \ + openpagesmodel.cpp \ + globalactions.cpp \ + openpageswidget.cpp \ + openpagesmanager.cpp \ + openpagesswitcher.cpp +contains(QT_CONFIG, webkit) { + SOURCES += helpviewer_qwv.cpp +} else { + SOURCES += helpviewer_qtb.cpp +} + +FORMS += bookmarkdialog.ui \ + bookmarkmanagerwidget.ui \ + bookmarkwidget.ui \ + filternamedialog.ui \ + installdialog.ui \ + preferencesdialog.ui \ + topicchooser.ui + +RESOURCES += assistant.qrc \ + assistant_images.qrc + +win32 { + !wince*:LIBS += -lshell32 + RC_FILE = assistant.rc +} + +mac { + ICON = assistant.icns + TARGET = Assistant + QMAKE_INFO_PLIST = Info_mac.plist +} + +contains(CONFIG, static): { + SQLPLUGINS = $$unique(sql-plugins) + contains(SQLPLUGINS, sqlite): { + QTPLUGIN += qsqlite + DEFINES += USE_STATIC_SQLITE_PLUGIN + } +} diff --git a/src/assistant/tools/assistant/assistant.qch b/src/assistant/tools/assistant/assistant.qch new file mode 100644 index 000000000..e6d52997b Binary files /dev/null and b/src/assistant/tools/assistant/assistant.qch differ diff --git a/src/assistant/tools/assistant/assistant.qrc b/src/assistant/tools/assistant/assistant.qrc new file mode 100644 index 000000000..dddf1be75 --- /dev/null +++ b/src/assistant/tools/assistant/assistant.qrc @@ -0,0 +1,5 @@ + + + assistant.qch + + diff --git a/src/assistant/tools/assistant/assistant.rc b/src/assistant/tools/assistant/assistant.rc new file mode 100644 index 000000000..b1bf97b5c --- /dev/null +++ b/src/assistant/tools/assistant/assistant.rc @@ -0,0 +1,32 @@ +#include "winver.h" + +IDI_ICON1 ICON DISCARDABLE "assistant.ico" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGS 0x0L + FILEFLAGSMASK 0x3fL + FILEOS 0x00040004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "CompanyName", "Nokia Corporation and/or its subsidiary(-ies)" + VALUE "FileDescription", "Qt Assistant" + VALUE "FileVersion", "1.0.0.0" + VALUE "LegalCopyright", "Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)." + VALUE "InternalName", "assistant.exe" + VALUE "OriginalFilename", "assistant.exe" + VALUE "ProductName", "Qt Assistant" + VALUE "ProductVersion", "1.0.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END diff --git a/src/assistant/tools/assistant/assistant_images.qrc b/src/assistant/tools/assistant/assistant_images.qrc new file mode 100644 index 000000000..b4f25236d --- /dev/null +++ b/src/assistant/tools/assistant/assistant_images.qrc @@ -0,0 +1,37 @@ + + + images/trolltech-logo.png + images/assistant-128.png + images/assistant.png + images/wrap.png + images/bookmark.png + images/mac/addtab.png + images/mac/book.png + images/mac/closetab.png + images/mac/editcopy.png + images/mac/find.png + images/mac/home.png + images/mac/next.png + images/mac/previous.png + images/mac/print.png + images/mac/synctoc.png + images/mac/zoomin.png + images/mac/zoomout.png + images/mac/resetzoom.png + images/win/addtab.png + images/win/book.png + images/win/closetab.png + images/win/editcopy.png + images/win/find.png + images/win/home.png + images/win/next.png + images/win/previous.png + images/win/print.png + images/win/synctoc.png + images/win/zoomin.png + images/win/zoomout.png + images/win/resetzoom.png + images/closebutton.png + images/darkclosebutton.png + + diff --git a/src/assistant/tools/assistant/bookmarkdialog.cpp b/src/assistant/tools/assistant/bookmarkdialog.cpp new file mode 100644 index 000000000..d2f88f968 --- /dev/null +++ b/src/assistant/tools/assistant/bookmarkdialog.cpp @@ -0,0 +1,237 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "bookmarkdialog.h" +#include "bookmarkfiltermodel.h" +#include "bookmarkitem.h" +#include "bookmarkmodel.h" +#include "helpenginewrapper.h" +#include "tracer.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +BookmarkDialog::BookmarkDialog(BookmarkModel *sourceModel, const QString &title, + const QString &url, QWidget *parent) + : QDialog(parent) + , m_url(url) + , m_title(title) + , bookmarkModel(sourceModel) +{ + TRACE_OBJ + ui.setupUi(this); + + ui.bookmarkEdit->setText(m_title); + ui.newFolderButton->setVisible(false); + ui.buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); + + connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(accepted())); + connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(rejected())); + connect(ui.newFolderButton, SIGNAL(clicked()), this, SLOT(addFolder())); + connect(ui.toolButton, SIGNAL(clicked()), this, SLOT(toolButtonClicked())); + connect(ui.bookmarkEdit, SIGNAL(textChanged(QString)), this, + SLOT(textChanged(QString))); + + bookmarkProxyModel = new BookmarkFilterModel(this); + bookmarkProxyModel->setSourceModel(bookmarkModel); + ui.bookmarkFolders->setModel(bookmarkProxyModel); + connect(ui.bookmarkFolders, SIGNAL(currentIndexChanged(int)), this, + SLOT(currentIndexChanged(int))); + + bookmarkTreeModel = new BookmarkTreeModel(this); + bookmarkTreeModel->setSourceModel(bookmarkModel); + ui.treeView->setModel(bookmarkTreeModel); + + ui.treeView->expandAll(); + ui.treeView->setVisible(false); + ui.treeView->installEventFilter(this); + ui.treeView->viewport()->installEventFilter(this); + ui.treeView->setContextMenuPolicy(Qt::CustomContextMenu); + + connect(ui.treeView, SIGNAL(customContextMenuRequested(QPoint)), this, + SLOT(customContextMenuRequested(QPoint))); + connect(ui.treeView->selectionModel(), SIGNAL(currentChanged(QModelIndex, + QModelIndex)), this, SLOT(currentIndexChanged(QModelIndex))); + + ui.bookmarkFolders->setCurrentIndex(0); + ui.treeView->setCurrentIndex(ui.treeView->indexAt(QPoint(2, 2))); + + const HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + if (helpEngine.usesAppFont()) + setFont(helpEngine.appFont()); +} + +BookmarkDialog::~BookmarkDialog() +{ + TRACE_OBJ +} + +bool BookmarkDialog::isRootItem(const QModelIndex &index) const +{ + return !bookmarkTreeModel->parent(index).isValid(); +} + +bool BookmarkDialog::eventFilter(QObject *object, QEvent *event) +{ + TRACE_OBJ + if (object != ui.treeView && object != ui.treeView->viewport()) + return QWidget::eventFilter(object, event); + + if (event->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast(event); + switch (ke->key()) { + case Qt::Key_F2: { + const QModelIndex &index = ui.treeView->currentIndex(); + if (!isRootItem(index)) { + bookmarkModel->setItemsEditable(true); + ui.treeView->edit(index); + bookmarkModel->setItemsEditable(false); + } + } break; + default: break; + } + } + + return QObject::eventFilter(object, event); +} + +void BookmarkDialog::currentIndexChanged(int row) +{ + TRACE_OBJ + QModelIndex next = bookmarkProxyModel->index(row, 0, QModelIndex()); + if (next.isValid()) { + next = bookmarkProxyModel->mapToSource(next); + ui.treeView->setCurrentIndex(bookmarkTreeModel->mapFromSource(next)); + } +} + +void BookmarkDialog::currentIndexChanged(const QModelIndex &index) +{ + TRACE_OBJ + const QModelIndex current = bookmarkTreeModel->mapToSource(index); + if (current.isValid()) { + const int row = bookmarkProxyModel->mapFromSource(current).row(); + ui.bookmarkFolders->setCurrentIndex(row); + } +} + +void BookmarkDialog::accepted() +{ + TRACE_OBJ + QModelIndex index = ui.treeView->currentIndex(); + if (index.isValid()) { + index = bookmarkModel->addItem(bookmarkTreeModel->mapToSource(index)); + bookmarkModel->setData(index, DataVector() << m_title << m_url << false); + } else + rejected(); + + accept(); +} + +void BookmarkDialog::rejected() +{ + TRACE_OBJ + foreach (const QPersistentModelIndex &index, cache) + bookmarkModel->removeItem(index); + reject(); +} + +void BookmarkDialog::addFolder() +{ + TRACE_OBJ + QModelIndex index = ui.treeView->currentIndex(); + if (index.isValid()) { + index = bookmarkModel->addItem(bookmarkTreeModel->mapToSource(index), + true); + cache.append(index); + + index = bookmarkTreeModel->mapFromSource(index); + if (index.isValid()) { + bookmarkModel->setItemsEditable(true); + ui.treeView->edit(index); + ui.treeView->expand(index); + ui.treeView->setCurrentIndex(index); + bookmarkModel->setItemsEditable(false); + } + } +} + +void BookmarkDialog::toolButtonClicked() +{ + TRACE_OBJ + const bool visible = !ui.treeView->isVisible(); + ui.treeView->setVisible(visible); + ui.newFolderButton->setVisible(visible); + + if (visible) { + resize(QSize(width(), 400)); + ui.toolButton->setText(QLatin1String("-")); + } else { + resize(width(), minimumHeight()); + ui.toolButton->setText(QLatin1String("+")); + } +} + +void BookmarkDialog::textChanged(const QString& text) +{ + m_title = text; +} + +void BookmarkDialog::customContextMenuRequested(const QPoint &point) +{ + TRACE_OBJ + const QModelIndex &index = ui.treeView->currentIndex(); + if (isRootItem(index)) + return; // check if we go to rename the "Bookmarks Menu", bail + + QMenu menu(QLatin1String(""), this); + QAction *renameItem = menu.addAction(tr("Rename Folder")); + + QAction *picked = menu.exec(ui.treeView->mapToGlobal(point)); + if (picked == renameItem) { + bookmarkModel->setItemsEditable(true); + ui.treeView->edit(index); + bookmarkModel->setItemsEditable(false); + } +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/bookmarkdialog.h b/src/assistant/tools/assistant/bookmarkdialog.h new file mode 100644 index 000000000..dfa65bbf8 --- /dev/null +++ b/src/assistant/tools/assistant/bookmarkdialog.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef BOOKMARKDIALOG_H +#define BOOKMARKDIALOG_H + +#include "ui_bookmarkdialog.h" + +QT_BEGIN_NAMESPACE + +class BookmarkModel; +class BookmarkFilterModel; +class BookmarkTreeModel; + +class BookmarkDialog : public QDialog +{ + Q_OBJECT +public: + BookmarkDialog(BookmarkModel *bookmarkModel, const QString &title, + const QString &url, QWidget *parent = 0); + ~BookmarkDialog(); + +private: + bool isRootItem(const QModelIndex &index) const; + bool eventFilter(QObject *object, QEvent *event); + +private slots: + void currentIndexChanged(int index); + void currentIndexChanged(const QModelIndex &index); + + void accepted(); + void rejected(); + + void addFolder(); + void toolButtonClicked(); + void textChanged(const QString& text); + void customContextMenuRequested(const QPoint &point); + +private: + QString m_url; + QString m_title; + Ui::BookmarkDialog ui; + QList cache; + + BookmarkModel *bookmarkModel; + BookmarkTreeModel *bookmarkTreeModel; + BookmarkFilterModel *bookmarkProxyModel; +}; + +QT_END_NAMESPACE + +#endif // BOOKMARKDIALOG_H diff --git a/src/assistant/tools/assistant/bookmarkdialog.ui b/src/assistant/tools/assistant/bookmarkdialog.ui new file mode 100644 index 000000000..51315317b --- /dev/null +++ b/src/assistant/tools/assistant/bookmarkdialog.ui @@ -0,0 +1,156 @@ + + + BookmarkDialog + + + + 0 + 0 + 450 + 133 + + + + + 0 + 0 + + + + Add Bookmark + + + + + + + + + + Bookmark: + + + + + + + Add in Folder: + + + + + + + + + + + + + + + + + + + + + + + + 25 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + + + + + + + 0 + 0 + + + + true + + + true + + + true + + + + + + + + + New Folder + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + BookmarkDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + BookmarkDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/assistant/tools/assistant/bookmarkfiltermodel.cpp b/src/assistant/tools/assistant/bookmarkfiltermodel.cpp new file mode 100644 index 000000000..412e08e5d --- /dev/null +++ b/src/assistant/tools/assistant/bookmarkfiltermodel.cpp @@ -0,0 +1,321 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "bookmarkfiltermodel.h" + +#include "bookmarkitem.h" +#include "bookmarkmodel.h" + +BookmarkFilterModel::BookmarkFilterModel(QObject *parent) + : QAbstractProxyModel(parent) + , hideBookmarks(true) + , sourceModel(0) +{ +} + +void BookmarkFilterModel::setSourceModel(QAbstractItemModel *_sourceModel) +{ + beginResetModel(); + + if (sourceModel) { + disconnect(sourceModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), + this, SLOT(changed(QModelIndex, QModelIndex))); + disconnect(sourceModel, SIGNAL(rowsInserted(QModelIndex, int, int)), + this, SLOT(rowsInserted(QModelIndex, int, int))); + disconnect(sourceModel, + SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)), this, + SLOT(rowsAboutToBeRemoved(QModelIndex, int, int))); + disconnect(sourceModel, SIGNAL(rowsRemoved(QModelIndex, int, int)), + this, SLOT(rowsRemoved(QModelIndex, int, int))); + disconnect(sourceModel, SIGNAL(layoutAboutToBeChanged()), this, + SLOT(layoutAboutToBeChanged())); + disconnect(sourceModel, SIGNAL(layoutChanged()), this, + SLOT(layoutChanged())); + disconnect(sourceModel, SIGNAL(modelAboutToBeReset()), this, + SLOT(modelAboutToBeReset())); + disconnect(sourceModel, SIGNAL(modelReset()), this, SLOT(modelReset())); + } + + QAbstractProxyModel::setSourceModel(sourceModel); + sourceModel = qobject_cast (_sourceModel); + + connect(sourceModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, + SLOT(changed(QModelIndex, QModelIndex))); + + connect(sourceModel, SIGNAL(rowsInserted(QModelIndex, int, int)), + this, SLOT(rowsInserted(QModelIndex, int, int))); + + connect(sourceModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex, int, int)), + this, SLOT(rowsAboutToBeRemoved(QModelIndex, int, int))); + connect(sourceModel, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, + SLOT(rowsRemoved(QModelIndex, int, int))); + + connect(sourceModel, SIGNAL(layoutAboutToBeChanged()), this, + SLOT(layoutAboutToBeChanged())); + connect(sourceModel, SIGNAL(layoutChanged()), this, + SLOT(layoutChanged())); + + connect(sourceModel, SIGNAL(modelAboutToBeReset()), this, + SLOT(modelAboutToBeReset())); + connect(sourceModel, SIGNAL(modelReset()), this, SLOT(modelReset())); + + if (sourceModel) + setupCache(sourceModel->index(0, 0, QModelIndex()).parent()); + + endResetModel(); +} + +int BookmarkFilterModel::rowCount(const QModelIndex &index) const +{ + Q_UNUSED(index) + return cache.count(); +} + +int BookmarkFilterModel::columnCount(const QModelIndex &index) const +{ + Q_UNUSED(index) + if (sourceModel) + return sourceModel->columnCount(); + return 0; +} + +QModelIndex BookmarkFilterModel::mapToSource(const QModelIndex &proxyIndex) const +{ + const int row = proxyIndex.row(); + if (proxyIndex.isValid() && row >= 0 && row < cache.count()) + return cache[row]; + return QModelIndex(); +} + +QModelIndex BookmarkFilterModel::mapFromSource(const QModelIndex &sourceIndex) const +{ + return index(cache.indexOf(sourceIndex), 0, QModelIndex()); +} + +QModelIndex BookmarkFilterModel::parent(const QModelIndex &child) const +{ + Q_UNUSED(child) + return QModelIndex(); +} + +QModelIndex BookmarkFilterModel::index(int row, int column, + const QModelIndex &index) const +{ + Q_UNUSED(index) + if (row < 0 || column < 0 || cache.count() <= row + || !sourceModel || sourceModel->columnCount() <= column) { + return QModelIndex(); + } + return createIndex(row, 0); +} + +Qt::DropActions BookmarkFilterModel::supportedDropActions () const +{ + if (sourceModel) + return sourceModel->supportedDropActions(); + return Qt::IgnoreAction; +} + +Qt::ItemFlags BookmarkFilterModel::flags(const QModelIndex &index) const +{ + if (sourceModel) + return sourceModel->flags(index); + return Qt::NoItemFlags; +} + +QVariant BookmarkFilterModel::data(const QModelIndex &index, int role) const +{ + if (sourceModel) + return sourceModel->data(mapToSource(index), role); + return QVariant(); +} + +bool BookmarkFilterModel::setData(const QModelIndex &index, const QVariant &value, + int role) +{ + if (sourceModel) + return sourceModel->setData(mapToSource(index), value, role); + return false; +} + +void BookmarkFilterModel::filterBookmarks() +{ + if (sourceModel) { + beginResetModel(); + hideBookmarks = true; + setupCache(sourceModel->index(0, 0, QModelIndex()).parent()); + endResetModel(); + } +} + +void BookmarkFilterModel::filterBookmarkFolders() +{ + if (sourceModel) { + beginResetModel(); + hideBookmarks = false; + setupCache(sourceModel->index(0, 0, QModelIndex()).parent()); + endResetModel(); + } +} + +void BookmarkFilterModel::changed(const QModelIndex &topLeft, + const QModelIndex &bottomRight) +{ + emit dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight)); +} + +void BookmarkFilterModel::rowsInserted(const QModelIndex &parent, int start, + int end) +{ + if (!sourceModel) + return; + + QModelIndex cachePrevious = parent; + if (BookmarkItem *parentItem = sourceModel->itemFromIndex(parent)) { + BookmarkItem *newItem = parentItem->child(start); + + // iterate over tree hirarchie to find the previous folder + for (int i = 0; i < parentItem->childCount(); ++i) { + if (BookmarkItem *child = parentItem->child(i)) { + const QModelIndex &tmp = sourceModel->indexFromItem(child); + if (tmp.data(UserRoleFolder).toBool() && child != newItem) + cachePrevious = tmp; + } + } + + const QModelIndex &newIndex = sourceModel->indexFromItem(newItem); + const bool isFolder = newIndex.data(UserRoleFolder).toBool(); + if ((isFolder && hideBookmarks) || (!isFolder && !hideBookmarks)) { + beginInsertRows(mapFromSource(parent), start, end); + const int index = cache.indexOf(cachePrevious) + 1; + if (cache.value(index, QPersistentModelIndex()) != newIndex) + cache.insert(index, newIndex); + endInsertRows(); + } + } +} + +void BookmarkFilterModel::rowsAboutToBeRemoved(const QModelIndex &parent, + int start, int end) +{ + if (!sourceModel) + return; + + if (BookmarkItem *parentItem = sourceModel->itemFromIndex(parent)) { + if (BookmarkItem *child = parentItem->child(start)) { + indexToRemove = sourceModel->indexFromItem(child); + if (cache.contains(indexToRemove)) + beginRemoveRows(mapFromSource(parent), start, end); + } + } +} + +void BookmarkFilterModel::rowsRemoved(const QModelIndex &/*parent*/, int, int) +{ + if (cache.contains(indexToRemove)) { + cache.removeAll(indexToRemove); + endRemoveRows(); + } +} + +void BookmarkFilterModel::layoutAboutToBeChanged() +{ + // TODO: ??? +} + +void BookmarkFilterModel::layoutChanged() +{ + // TODO: ??? +} + +void BookmarkFilterModel::modelAboutToBeReset() +{ + beginResetModel(); +} + +void BookmarkFilterModel::modelReset() +{ + if (sourceModel) + setupCache(sourceModel->index(0, 0, QModelIndex()).parent()); + endResetModel(); +} + +void BookmarkFilterModel::setupCache(const QModelIndex &parent) +{ + cache.clear(); + for (int i = 0; i < sourceModel->rowCount(parent); ++i) + collectItems(sourceModel->index(i, 0, parent)); +} + +void BookmarkFilterModel::collectItems(const QModelIndex &parent) +{ + if (parent.isValid()) { + bool isFolder = sourceModel->data(parent, UserRoleFolder).toBool(); + if ((isFolder && hideBookmarks) || (!isFolder && !hideBookmarks)) + cache.append(parent); + + if (sourceModel->hasChildren(parent)) { + for (int i = 0; i < sourceModel->rowCount(parent); ++i) + collectItems(sourceModel->index(i, 0, parent)); + } + } +} + +// -- BookmarkTreeModel + +BookmarkTreeModel::BookmarkTreeModel(QObject *parent) + : QSortFilterProxyModel(parent) +{ +} + +int BookmarkTreeModel::columnCount(const QModelIndex &parent) const +{ + return qMin(1, QSortFilterProxyModel::columnCount(parent)); +} + +bool BookmarkTreeModel::filterAcceptsRow(int row, const QModelIndex &parent) const +{ + Q_UNUSED(row) + BookmarkModel *model = qobject_cast (sourceModel()); + if (model->rowCount(parent) > 0 + && model->data(model->index(row, 0, parent), UserRoleFolder).toBool()) + return true; + return false; +} diff --git a/src/assistant/tools/assistant/bookmarkfiltermodel.h b/src/assistant/tools/assistant/bookmarkfiltermodel.h new file mode 100644 index 000000000..65ed12f20 --- /dev/null +++ b/src/assistant/tools/assistant/bookmarkfiltermodel.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef BOOKMARKFILTERMODEL_H +#define BOOKMARKFILTERMODEL_H + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class BookmarkItem; +class BookmarkModel; + +typedef QList PersistentModelIndexCache; + +class BookmarkFilterModel : public QAbstractProxyModel +{ + Q_OBJECT +public: + explicit BookmarkFilterModel(QObject *parent = 0); + + void setSourceModel(QAbstractItemModel *sourceModel); + + int rowCount(const QModelIndex &index) const; + int columnCount(const QModelIndex &index) const; + + QModelIndex mapToSource(const QModelIndex &proxyIndex) const; + QModelIndex mapFromSource(const QModelIndex &sourceIndex) const; + + QModelIndex parent(const QModelIndex &child) const; + QModelIndex index(int row, int column, const QModelIndex &parent) const; + + Qt::DropActions supportedDropActions () const; + Qt::ItemFlags flags(const QModelIndex &index) const; + + QVariant data(const QModelIndex &index, int role) const; + bool setData(const QModelIndex &index, const QVariant &value, int role); + + void filterBookmarks(); + void filterBookmarkFolders(); + +private slots: + void changed(const QModelIndex &topLeft, const QModelIndex &bottomRight); + void rowsInserted(const QModelIndex &parent, int start, int end); + void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); + void rowsRemoved(const QModelIndex &parent, int start, int end); + void layoutAboutToBeChanged(); + void layoutChanged(); + void modelAboutToBeReset(); + void modelReset(); + +private: + void setupCache(const QModelIndex &parent); + void collectItems(const QModelIndex &parent); + +private: + bool hideBookmarks; + BookmarkModel *sourceModel; + PersistentModelIndexCache cache; + QPersistentModelIndex indexToRemove; +}; + +// -- BookmarkTreeModel + +class BookmarkTreeModel : public QSortFilterProxyModel +{ + Q_OBJECT +public: + BookmarkTreeModel(QObject *parent = 0); + int columnCount(const QModelIndex &parent = QModelIndex()) const; + +protected: + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; +}; + +QT_END_NAMESPACE + +#endif // BOOKMARKFILTERMODEL_H diff --git a/src/assistant/tools/assistant/bookmarkitem.cpp b/src/assistant/tools/assistant/bookmarkitem.cpp new file mode 100644 index 000000000..8bcf451c1 --- /dev/null +++ b/src/assistant/tools/assistant/bookmarkitem.cpp @@ -0,0 +1,184 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "bookmarkitem.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +BookmarkItem::BookmarkItem(const DataVector &data, BookmarkItem *parent) + : m_data(data) + , m_parent(parent) +{ +} + +BookmarkItem::~BookmarkItem() +{ + qDeleteAll(m_children); +} + +BookmarkItem* +BookmarkItem::parent() const +{ + return m_parent; +} + +void +BookmarkItem::setParent(BookmarkItem *parent) +{ + m_parent = parent; +} + +void +BookmarkItem::addChild(BookmarkItem *child) +{ + child->setParent(this); + m_children.append(child); +} + +BookmarkItem* +BookmarkItem::child(int number) const +{ + if (number >= 0 && number < m_children.count()) + return m_children[number]; + return 0; +} + +int BookmarkItem::childCount() const +{ + return m_children.count(); +} + +int BookmarkItem::childNumber() const +{ + if (m_parent) + return m_parent->m_children.indexOf(const_cast(this)); + return 0; +} + +QVariant +BookmarkItem::data(int column) const +{ + if (column == 0) + return m_data[0]; + + if (column == 1 || column == UserRoleUrl) + return m_data[1]; + + if (column == UserRoleFolder) + return m_data[1].toString() == QLatin1String("Folder"); + + if (column == UserRoleExpanded) + return m_data[2]; + + return QVariant(); +} + +void +BookmarkItem::setData(const DataVector &data) +{ + m_data = data; +} + +bool +BookmarkItem::setData(int column, const QVariant &newValue) +{ + int index = -1; + if (column == 0 || column == 1) + index = column; + + if (column == UserRoleUrl || column == UserRoleFolder) + index = 1; + + if (column == UserRoleExpanded) + index = 2; + + if (index < 0) + return false; + + m_data[index] = newValue; + return true; +} + +bool +BookmarkItem::insertChildren(bool isFolder, int position, int count) +{ + if (position < 0 || position > m_children.size()) + return false; + + for (int row = 0; row < count; ++row) { + m_children.insert(position, new BookmarkItem(DataVector() + << (isFolder + ? QCoreApplication::translate("BookmarkItem", "New Folder") + : QCoreApplication::translate("BookmarkItem", "Untitled")) + << (isFolder ? "Folder" : "about:blank") << false, this)); + } + + return true; +} + +bool +BookmarkItem::removeChildren(int position, int count) +{ + if (position < 0 || position > m_children.size()) + return false; + + for (int row = 0; row < count; ++row) + delete m_children.takeAt(position); + + return true; +} + +void +BookmarkItem::dumpTree(int indent) const +{ + const QString tree(indent, ' '); + qDebug() << tree + (data(UserRoleFolder).toBool() ? "Folder" : "Bookmark") + << "Label:" << data(0).toString() << "parent:" << m_parent << "this:" + << this; + + foreach (BookmarkItem *item, m_children) + item->dumpTree(indent + 4); +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/bookmarkitem.h b/src/assistant/tools/assistant/bookmarkitem.h new file mode 100644 index 000000000..96ce786be --- /dev/null +++ b/src/assistant/tools/assistant/bookmarkitem.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BOOKMARKITEM_H +#define BOOKMARKITEM_H + +#include +#include + +QT_BEGIN_NAMESPACE + +enum { + UserRoleUrl = Qt::UserRole + 50, + UserRoleFolder = Qt::UserRole + 100, + UserRoleExpanded = Qt::UserRole + 150 +}; + +typedef QVector DataVector; + +class BookmarkItem +{ +public: + explicit BookmarkItem(const DataVector &data, BookmarkItem *parent = 0); + ~BookmarkItem(); + + BookmarkItem *parent() const; + void setParent(BookmarkItem *parent); + + void addChild(BookmarkItem *child); + BookmarkItem *child(int number) const; + + int childCount() const; + int childNumber() const; + + QVariant data(int column) const; + void setData(const DataVector &data); + bool setData(int column, const QVariant &value); + + bool insertChildren(bool isFolder, int position, int count); + bool removeChildren(int position, int count); + + void dumpTree(int indent) const; + +private: + DataVector m_data; + + BookmarkItem *m_parent; + QList m_children; +}; + +QT_END_NAMESPACE + +#endif // BOOKMARKITEM_H diff --git a/src/assistant/tools/assistant/bookmarkmanager.cpp b/src/assistant/tools/assistant/bookmarkmanager.cpp new file mode 100644 index 000000000..87331463b --- /dev/null +++ b/src/assistant/tools/assistant/bookmarkmanager.cpp @@ -0,0 +1,559 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "tracer.h" + +#include "bookmarkmanager.h" +#include "bookmarkmanagerwidget.h" +#include "bookmarkdialog.h" +#include "bookmarkfiltermodel.h" +#include "bookmarkitem.h" +#include "bookmarkmodel.h" +#include "centralwidget.h" +#include "helpenginewrapper.h" + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +// -- BookmarkManager::BookmarkWidget + +void BookmarkManager::BookmarkWidget::focusInEvent(QFocusEvent *event) +{ + TRACE_OBJ + if (event->reason() != Qt::MouseFocusReason) { + ui.lineEdit->selectAll(); + ui.lineEdit->setFocus(); + + // force the focus in event on bookmark manager + emit focusInEvent(); + } +} + +// -- BookmarkManager::BookmarkTreeView + +BookmarkManager::BookmarkTreeView::BookmarkTreeView(QWidget *parent) + : QTreeView(parent) +{ + TRACE_OBJ + setAcceptDrops(true); + setDragEnabled(true); + setAutoExpandDelay(1000); + setUniformRowHeights(true); + setDropIndicatorShown(true); + setExpandsOnDoubleClick(true); + + connect(this, SIGNAL(expanded(QModelIndex)), this, + SLOT(setExpandedData(QModelIndex))); + connect(this, SIGNAL(collapsed(QModelIndex)), this, + SLOT(setExpandedData(QModelIndex))); + +} + +void BookmarkManager::BookmarkTreeView::subclassKeyPressEvent(QKeyEvent *event) +{ + TRACE_OBJ + QTreeView::keyPressEvent(event); +} + +void BookmarkManager::BookmarkTreeView::setExpandedData(const QModelIndex &index) +{ + TRACE_OBJ + if (BookmarkModel *treeModel = qobject_cast (model())) + treeModel->setData(index, isExpanded(index), UserRoleExpanded); +} + +// -- BookmarkManager + +QMutex BookmarkManager::mutex; +BookmarkManager* BookmarkManager::bookmarkManager = 0; + +// -- public + +BookmarkManager* BookmarkManager::instance() +{ + TRACE_OBJ + if (!bookmarkManager) { + QMutexLocker _(&mutex); + if (!bookmarkManager) + bookmarkManager = new BookmarkManager(); + } + return bookmarkManager; +} + +void BookmarkManager::destroy() +{ + TRACE_OBJ + delete bookmarkManager; + bookmarkManager = 0; +} + +QWidget* BookmarkManager::bookmarkDockWidget() const +{ + TRACE_OBJ + if (bookmarkWidget) + return bookmarkWidget; + return 0; +} + +void BookmarkManager::setBookmarksMenu(QMenu* menu) +{ + TRACE_OBJ + bookmarkMenu = menu; + refreshBookmarkMenu(); +} + +void BookmarkManager::setBookmarksToolbar(QToolBar *toolBar) +{ + TRACE_OBJ + m_toolBar = toolBar; + refreshBookmarkToolBar(); +} + +// -- public slots + +void BookmarkManager::addBookmark(const QString &title, const QString &url) +{ + TRACE_OBJ + showBookmarkDialog(title.isEmpty() ? tr("Untitled") : title, + url.isEmpty() ? QLatin1String("about:blank") : url); +} + +// -- private + +BookmarkManager::BookmarkManager() + : typeAndSearch(false) + , bookmarkMenu(0) + , m_toolBar(0) + , bookmarkModel(new BookmarkModel) + , bookmarkFilterModel(0) + , typeAndSearchModel(0) + , bookmarkWidget(new BookmarkWidget) + , bookmarkTreeView(new BookmarkTreeView) + , bookmarkManagerWidget(0) +{ + TRACE_OBJ + bookmarkWidget->installEventFilter(this); + connect(bookmarkWidget->ui.add, SIGNAL(clicked()), this, + SLOT(addBookmark())); + connect(bookmarkWidget->ui.remove, SIGNAL(clicked()), this, + SLOT(removeBookmark())); + connect(bookmarkWidget->ui.lineEdit, SIGNAL(textChanged(QString)), this, + SLOT(textChanged(QString))); + connect(bookmarkWidget, SIGNAL(focusInEvent()), this, SLOT(focusInEvent())); + + bookmarkTreeView->setModel(bookmarkModel); + bookmarkTreeView->installEventFilter(this); + bookmarkTreeView->viewport()->installEventFilter(this); + bookmarkTreeView->setContextMenuPolicy(Qt::CustomContextMenu); + bookmarkWidget->ui.stackedWidget->addWidget(bookmarkTreeView); + + connect(bookmarkTreeView, SIGNAL(activated(QModelIndex)), this, + SLOT(setSourceFromIndex(QModelIndex))); + connect(bookmarkTreeView, SIGNAL(customContextMenuRequested(QPoint)), this, + SLOT(customContextMenuRequested(QPoint))); + + connect(&HelpEngineWrapper::instance(), SIGNAL(setupFinished()), this, + SLOT(setupFinished())); + connect(bookmarkModel, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, + SLOT(refreshBookmarkMenu())); + connect(bookmarkModel, SIGNAL(rowsInserted(QModelIndex, int, int)), this, + SLOT(refreshBookmarkMenu())); + connect(bookmarkModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, + SLOT(refreshBookmarkMenu())); + + connect(bookmarkModel, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, + SLOT(refreshBookmarkToolBar())); + connect(bookmarkModel, SIGNAL(rowsInserted(QModelIndex, int, int)), this, + SLOT(refreshBookmarkToolBar())); + connect(bookmarkModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, + SLOT(refreshBookmarkToolBar())); +} + +BookmarkManager::~BookmarkManager() +{ + TRACE_OBJ + delete bookmarkManagerWidget; + HelpEngineWrapper::instance().setBookmarks(bookmarkModel->bookmarks()); + delete bookmarkModel; +} + +void BookmarkManager::removeItem(const QModelIndex &index) +{ + TRACE_OBJ + QModelIndex current = index; + if (typeAndSearch) { // need to map because of proxy + current = typeAndSearchModel->mapToSource(current); + current = bookmarkFilterModel->mapToSource(current); + } else if (!bookmarkModel->parent(index).isValid()) { + return; // check if we should delete the "Bookmarks Menu", bail + } + + if (bookmarkModel->hasChildren(current)) { + int value = QMessageBox::question(bookmarkTreeView, tr("Remove"), + tr("You are going to delete a Folder, this will also
" + "remove it's content. Are you sure to continue?"), + QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel); + if (value == QMessageBox::Cancel) + return; + } + bookmarkModel->removeItem(current); +} + +bool BookmarkManager::eventFilter(QObject *object, QEvent *event) +{ + if (object != bookmarkTreeView && object != bookmarkTreeView->viewport() + && object != bookmarkWidget) + return QObject::eventFilter(object, event); + + TRACE_OBJ + const bool isWidget = object == bookmarkWidget; + if (event->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast(event); + switch (ke->key()) { + case Qt::Key_F2: { + renameBookmark(bookmarkTreeView->currentIndex()); + } break; + + case Qt::Key_Delete: { + removeItem(bookmarkTreeView->currentIndex()); + return true; + } break; + + case Qt::Key_Up: { // needs event filter on widget + case Qt::Key_Down: + if (isWidget) + bookmarkTreeView->subclassKeyPressEvent(ke); + } break; + + case Qt::Key_Escape: { + emit escapePressed(); + } break; + + default: break; + } + } + + if (event->type() == QEvent::MouseButtonRelease && !isWidget) { + QMouseEvent *me = static_cast(event); + switch (me->button()) { + case Qt::LeftButton: { + if (me->modifiers() & Qt::ControlModifier) + setSourceFromIndex(bookmarkTreeView->currentIndex(), true); + } break; + + case Qt::MidButton: { + setSourceFromIndex(bookmarkTreeView->currentIndex(), true); + } break; + + default: break; + } + } + + return QObject::eventFilter(object, event); +} + +void BookmarkManager::buildBookmarksMenu(const QModelIndex &index, QMenu* menu) +{ + TRACE_OBJ + if (!index.isValid()) + return; + + const QString &text = index.data().toString(); + const QIcon &icon = qvariant_cast(index.data(Qt::DecorationRole)); + if (index.data(UserRoleFolder).toBool()) { + if (QMenu* subMenu = menu->addMenu(icon, text)) { + for (int i = 0; i < bookmarkModel->rowCount(index); ++i) + buildBookmarksMenu(bookmarkModel->index(i, 0, index), subMenu); + } + } else { + QAction *action = menu->addAction(icon, text); + action->setData(index.data(UserRoleUrl).toString()); + } +} + +void BookmarkManager::showBookmarkDialog(const QString &name, const QString &url) +{ + TRACE_OBJ + BookmarkDialog dialog(bookmarkModel, name, url, bookmarkTreeView); + dialog.exec(); +} + +// -- private slots + +void BookmarkManager::setupFinished() +{ + TRACE_OBJ + bookmarkModel->setBookmarks(HelpEngineWrapper::instance().bookmarks()); + bookmarkModel->expandFoldersIfNeeeded(bookmarkTreeView); + + refreshBookmarkMenu(); + refreshBookmarkToolBar(); + + bookmarkTreeView->hideColumn(1); + bookmarkTreeView->header()->setVisible(false); + bookmarkTreeView->header()->setStretchLastSection(true); + + if (!bookmarkFilterModel) + bookmarkFilterModel = new BookmarkFilterModel(this); + bookmarkFilterModel->setSourceModel(bookmarkModel); + bookmarkFilterModel->filterBookmarkFolders(); + + if (!typeAndSearchModel) + typeAndSearchModel = new QSortFilterProxyModel(this); + typeAndSearchModel->setDynamicSortFilter(true); + typeAndSearchModel->setSourceModel(bookmarkFilterModel); +} + +void BookmarkManager::addBookmark() +{ + TRACE_OBJ + if (CentralWidget *widget = CentralWidget::instance()) + addBookmark(widget->currentTitle(), widget->currentSource().toString()); +} + +void BookmarkManager::removeBookmark() +{ + TRACE_OBJ + removeItem(bookmarkTreeView->currentIndex()); +} + +void BookmarkManager::manageBookmarks() +{ + TRACE_OBJ + if (bookmarkManagerWidget == 0) { + bookmarkManagerWidget = new BookmarkManagerWidget(bookmarkModel); + connect(bookmarkManagerWidget, SIGNAL(setSource(QUrl)), this, + SIGNAL(setSource(QUrl))); + connect(bookmarkManagerWidget, SIGNAL(setSourceInNewTab(QUrl)) + , this, SIGNAL(setSourceInNewTab(QUrl))); + connect(bookmarkManagerWidget, SIGNAL(managerWidgetAboutToClose()) + , this, SLOT(managerWidgetAboutToClose())); + } + bookmarkManagerWidget->show(); + bookmarkManagerWidget->raise(); +} + +void BookmarkManager::refreshBookmarkMenu() +{ + TRACE_OBJ + if (!bookmarkMenu) + return; + + bookmarkMenu->clear(); + + bookmarkMenu->addAction(tr("Manage Bookmarks..."), this, + SLOT(manageBookmarks())); + bookmarkMenu->addAction(QIcon::fromTheme("bookmark-new"), + tr("Add Bookmark..."), this, SLOT(addBookmark()), QKeySequence(tr("Ctrl+D"))); + + bookmarkMenu->addSeparator(); + + QModelIndex root = bookmarkModel->index(0, 0, QModelIndex()).parent(); + buildBookmarksMenu(bookmarkModel->index(0, 0, root), bookmarkMenu); + + bookmarkMenu->addSeparator(); + + root = bookmarkModel->index(1, 0, QModelIndex()); + for (int i = 0; i < bookmarkModel->rowCount(root); ++i) + buildBookmarksMenu(bookmarkModel->index(i, 0, root), bookmarkMenu); + + connect(bookmarkMenu, SIGNAL(triggered(QAction*)), this, + SLOT(setSourceFromAction(QAction*))); +} + +void BookmarkManager::refreshBookmarkToolBar() +{ + TRACE_OBJ + if (!m_toolBar) + return; + + m_toolBar->clear(); + m_toolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + + const QModelIndex &root = bookmarkModel->index(0, 0, QModelIndex()); + for (int i = 0; i < bookmarkModel->rowCount(root); ++i) { + const QModelIndex &index = bookmarkModel->index(i, 0, root); + if (index.data(UserRoleFolder).toBool()) { + QToolButton *button = new QToolButton(m_toolBar); + button->setPopupMode(QToolButton::InstantPopup); + button->setText(index.data().toString()); + QMenu *menu = new QMenu(button); + for (int j = 0; j < bookmarkModel->rowCount(index); ++j) + buildBookmarksMenu(bookmarkModel->index(j, 0, index), menu); + connect(menu, SIGNAL(triggered(QAction*)), this, + SLOT(setSourceFromAction(QAction*))); + button->setMenu(menu); + button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + button->setIcon(qvariant_cast(index.data(Qt::DecorationRole))); + QAction *a = m_toolBar->addWidget(button); + a->setText(index.data().toString()); + } else { + QAction *action = m_toolBar->addAction( + qvariant_cast(index.data(Qt::DecorationRole)), + index.data().toString(), this, SLOT(setSourceFromAction())); + action->setData(index.data(UserRoleUrl).toString()); + } + } +} + +void BookmarkManager::renameBookmark(const QModelIndex &index) +{ + // check if we should rename the "Bookmarks Menu", bail + if (!typeAndSearch && !bookmarkModel->parent(index).isValid()) + return; + + bookmarkModel->setItemsEditable(true); + bookmarkTreeView->edit(index); + bookmarkModel->setItemsEditable(false); +} + + +void BookmarkManager::setSourceFromAction() +{ + TRACE_OBJ + setSourceFromAction(qobject_cast (sender())); +} + +void BookmarkManager::setSourceFromAction(QAction *action) +{ + TRACE_OBJ + if (action) { + const QVariant &data = action->data(); + if (data.canConvert()) + emit setSource(data.toUrl()); + } +} + +void BookmarkManager::setSourceFromIndex(const QModelIndex &index, bool newTab) +{ + TRACE_OBJ + QAbstractItemModel *base = bookmarkModel; + if (typeAndSearch) + base = typeAndSearchModel; + + if (base->data(index, UserRoleFolder).toBool()) + return; + + const QVariant &data = base->data(index, UserRoleUrl); + if (data.canConvert()) { + if (newTab) + emit setSourceInNewTab(data.toUrl()); + else + emit setSource(data.toUrl()); + } +} + +void BookmarkManager::customContextMenuRequested(const QPoint &point) +{ + TRACE_OBJ + QModelIndex index = bookmarkTreeView->indexAt(point); + if (!index.isValid()) + return; + + // check if we should open the menu on "Bookmarks Menu", bail + if (!typeAndSearch && !bookmarkModel->parent(index).isValid()) + return; + + QAction *remove = 0; + QAction *rename = 0; + QAction *showItem = 0; + QAction *showItemInNewTab = 0; + + QMenu menu(QLatin1String("")); + if (!typeAndSearch && bookmarkModel->data(index, UserRoleFolder).toBool()) { + remove = menu.addAction(tr("Delete Folder")); + rename = menu.addAction(tr("Rename Folder")); + } else { + showItem = menu.addAction(tr("Show Bookmark")); + showItemInNewTab = menu.addAction(tr("Show Bookmark in New Tab")); + menu.addSeparator(); + remove = menu.addAction(tr("Delete Bookmark")); + rename = menu.addAction(tr("Rename Bookmark")); + } + + QAction *pickedAction = menu.exec(bookmarkTreeView->mapToGlobal(point)); + if (pickedAction == rename) + renameBookmark(index); + else if (pickedAction == remove) + removeItem(index); + else if (pickedAction == showItem || pickedAction == showItemInNewTab) + setSourceFromIndex(index, pickedAction == showItemInNewTab); +} + +void BookmarkManager::focusInEvent() +{ + TRACE_OBJ + const QModelIndex &index = bookmarkTreeView->indexAt(QPoint(2, 2)); + if (index.isValid()) + bookmarkTreeView->setCurrentIndex(index); +} + +void BookmarkManager::managerWidgetAboutToClose() +{ + delete bookmarkManagerWidget; + bookmarkManagerWidget = 0; +} + +void BookmarkManager::textChanged(const QString &text) +{ + TRACE_OBJ + if (!bookmarkWidget->ui.lineEdit->text().isEmpty()) { + if (!typeAndSearch) { + typeAndSearch = true; + bookmarkTreeView->setItemsExpandable(false); + bookmarkTreeView->setRootIsDecorated(false); + bookmarkTreeView->setModel(typeAndSearchModel); + } + typeAndSearchModel->setFilterRegExp(QRegExp(text)); + } else { + typeAndSearch = false; + bookmarkTreeView->setModel(bookmarkModel); + bookmarkTreeView->setItemsExpandable(true); + bookmarkTreeView->setRootIsDecorated(true); + bookmarkModel->expandFoldersIfNeeeded(bookmarkTreeView); + } +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/bookmarkmanager.h b/src/assistant/tools/assistant/bookmarkmanager.h new file mode 100644 index 000000000..f5823a7fa --- /dev/null +++ b/src/assistant/tools/assistant/bookmarkmanager.h @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef BOOKMARKMANAGER_H +#define BOOKMARKMANAGER_H + +#include +#include + +#include "ui_bookmarkwidget.h" + +QT_BEGIN_NAMESPACE + +class BookmarkManagerWidget; +class BookmarkModel; +class BookmarkFilterModel; +class QKeyEvent; +class QSortFilterProxyModel; +class QToolBar; + +class BookmarkManager : public QObject +{ + Q_OBJECT + class BookmarkWidget; + class BookmarkTreeView; + class BookmarkListView; + Q_DISABLE_COPY(BookmarkManager); + +public: + static BookmarkManager* instance(); + static void destroy(); + + QWidget* bookmarkDockWidget() const; + void setBookmarksMenu(QMenu* menu); + void setBookmarksToolbar(QToolBar *toolBar); + +public slots: + void addBookmark(const QString &title, const QString &url); + +signals: + void escapePressed(); + void setSource(const QUrl &url); + void setSourceInNewTab(const QUrl &url); + +private: + BookmarkManager(); + ~BookmarkManager(); + + void removeItem(const QModelIndex &index); + bool eventFilter(QObject *object, QEvent *event); + void buildBookmarksMenu(const QModelIndex &index, QMenu *menu); + void showBookmarkDialog(const QString &name, const QString &url); + +private slots: + void setupFinished(); + + void addBookmark(); + void removeBookmark(); + void manageBookmarks(); + void refreshBookmarkMenu(); + void refreshBookmarkToolBar(); + void renameBookmark(const QModelIndex &index); + + void setSourceFromAction(); + void setSourceFromAction(QAction *action); + void setSourceFromIndex(const QModelIndex &index, bool newTab = false); + + void focusInEvent(); + void managerWidgetAboutToClose(); + void textChanged(const QString &text); + void customContextMenuRequested(const QPoint &point); + +private: + bool typeAndSearch; + + static QMutex mutex; + static BookmarkManager *bookmarkManager; + + QMenu *bookmarkMenu; + QToolBar *m_toolBar; + + BookmarkModel *bookmarkModel; + BookmarkFilterModel *bookmarkFilterModel; + QSortFilterProxyModel *typeAndSearchModel; + + BookmarkWidget *bookmarkWidget; + BookmarkTreeView *bookmarkTreeView; + BookmarkManagerWidget *bookmarkManagerWidget; +}; + +class BookmarkManager::BookmarkWidget : public QWidget +{ + Q_OBJECT +public: + BookmarkWidget(QWidget *parent = 0) + : QWidget(parent) { ui.setupUi(this); } + virtual ~BookmarkWidget() {} + + Ui::BookmarkWidget ui; + +signals: + void focusInEvent(); + +private: + void focusInEvent(QFocusEvent *event); +}; + +class BookmarkManager::BookmarkTreeView : public QTreeView +{ + Q_OBJECT +public: + BookmarkTreeView(QWidget *parent = 0); + ~BookmarkTreeView() {} + + void subclassKeyPressEvent(QKeyEvent *event); + +private slots: + void setExpandedData(const QModelIndex &index); +}; + +QT_END_NAMESPACE + +#endif // BOOKMARKMANAGER_H diff --git a/src/assistant/tools/assistant/bookmarkmanagerwidget.cpp b/src/assistant/tools/assistant/bookmarkmanagerwidget.cpp new file mode 100644 index 000000000..dd410d3a2 --- /dev/null +++ b/src/assistant/tools/assistant/bookmarkmanagerwidget.cpp @@ -0,0 +1,321 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "bookmarkmanagerwidget.h" +#include "bookmarkitem.h" +#include "bookmarkmodel.h" +#include "tracer.h" +#include "xbelsupport.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace { + #define TR(x) QCoreApplication::translate("BookmarkManager", x) +} + +BookmarkManagerWidget::BookmarkManagerWidget(BookmarkModel *sourceModel, + QWidget *parent) + : QWidget(parent) + , bookmarkModel(sourceModel) +{ + TRACE_OBJ + ui.setupUi(this); + + ui.treeView->setModel(bookmarkModel); + + ui.treeView->expandAll(); + ui.treeView->installEventFilter(this); + ui.treeView->viewport()->installEventFilter(this); + ui.treeView->setContextMenuPolicy(Qt::CustomContextMenu); + + connect(ui.treeView, SIGNAL(customContextMenuRequested(QPoint)), this, + SLOT(customContextMenuRequested(QPoint))); + + connect(ui.remove, SIGNAL(clicked()), this, SLOT(removeItem())); + connect(ui.lineEdit, SIGNAL(textChanged(QString)), this, + SLOT(textChanged(QString))); + new QShortcut(QKeySequence::Find, ui.lineEdit, SLOT(setFocus())); + + importExportMenu.addAction(tr("Import..."), this, SLOT(importBookmarks())); + importExportMenu.addAction(tr("Export..."), this, SLOT(exportBookmarks())); + ui.importExport->setMenu(&importExportMenu); + + new QShortcut(QKeySequence::FindNext, this, SLOT(findNext())); + new QShortcut(QKeySequence::FindPrevious, this, SLOT(findPrevious())); + + connect(bookmarkModel, SIGNAL(rowsRemoved(QModelIndex, int, int)), this, + SLOT(refeshBookmarkCache())); + connect(bookmarkModel, SIGNAL(rowsInserted(QModelIndex, int, int)), this, + SLOT(refeshBookmarkCache())); + connect(bookmarkModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, + SLOT(refeshBookmarkCache())); + + ui.treeView->setCurrentIndex(ui.treeView->indexAt(QPoint(2, 2))); +} + +BookmarkManagerWidget::~BookmarkManagerWidget() +{ + TRACE_OBJ +} + +void BookmarkManagerWidget::closeEvent(QCloseEvent *event) +{ + TRACE_OBJ + event->accept(); + emit managerWidgetAboutToClose(); +} + +void BookmarkManagerWidget::renameItem(const QModelIndex &index) +{ + TRACE_OBJ + // check if we should rename the "Bookmarks Menu", bail + if (!bookmarkModel->parent(index).isValid()) + return; + + bookmarkModel->setItemsEditable(true); + ui.treeView->edit(index); + bookmarkModel->setItemsEditable(false); +} + +static int nextIndex(int current, int count, bool forward) +{ + TRACE_OBJ + if (current >= 0) + return (forward ? (current + 1) : ((current - 1) + count)) % count; + return 0; +} + +void BookmarkManagerWidget::selectNextIndex(bool direction) const +{ + QModelIndex current = ui.treeView->currentIndex(); + if (current.isValid() && !cache.isEmpty()) { + current = cache.at(nextIndex(cache.indexOf(current), cache.count(), + direction)); + } + ui.treeView->setCurrentIndex(current); +} + +bool BookmarkManagerWidget::eventFilter(QObject *object, QEvent *event) +{ + TRACE_OBJ + if (object != ui.treeView && object != ui.treeView->viewport()) + return QWidget::eventFilter(object, event); + + if (event->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast(event); + switch (ke->key()) { + case Qt::Key_F2: { + renameItem(ui.treeView->currentIndex()); + } break; + + case Qt::Key_Delete: { + removeItem(ui.treeView->currentIndex()); + } break; + + default: break; + } + } + + if (event->type() == QEvent::MouseButtonRelease) { + QMouseEvent *me = static_cast(event); + switch (me->button()) { + case Qt::LeftButton: { + if (me->modifiers() & Qt::ControlModifier) + setSourceFromIndex(ui.treeView->currentIndex(), true); + } break; + + case Qt::MidButton: { + setSourceFromIndex(ui.treeView->currentIndex(), true); + } break; + + default: break; + } + } + return QObject::eventFilter(object, event); +} + +void BookmarkManagerWidget::findNext() +{ + TRACE_OBJ + selectNextIndex(true); +} + +void BookmarkManagerWidget::findPrevious() +{ + TRACE_OBJ + selectNextIndex(false); +} + +void BookmarkManagerWidget::importBookmarks() +{ + TRACE_OBJ + const QString &fileName = QFileDialog::getOpenFileName(0, TR("Open File"), + QDir::currentPath(), TR("Files (*.xbel)")); + + if (fileName.isEmpty()) + return; + + QFile file(fileName); + if (file.open(QIODevice::ReadOnly)) { + XbelReader reader(bookmarkModel); + reader.readFromFile(&file); + } +} + +void BookmarkManagerWidget::exportBookmarks() +{ + TRACE_OBJ + QString fileName = QFileDialog::getSaveFileName(0, TR("Save File"), + QLatin1String("untitled.xbel"), TR("Files (*.xbel)")); + + const QLatin1String suffix(".xbel"); + if (!fileName.endsWith(suffix)) + fileName.append(suffix); + + QFile file(fileName); + if (file.open(QIODevice::WriteOnly)) { + XbelWriter writer(bookmarkModel); + writer.writeToFile(&file); + } else { + QMessageBox::information(this, TR("Qt Assistant"), + TR("Unable to save bookmarks."), TR("OK")); + } +} + +void BookmarkManagerWidget::refeshBookmarkCache() +{ + TRACE_OBJ + cache.clear(); + + const QString &text = ui.lineEdit->text(); + if (!text.isEmpty()) + cache = bookmarkModel->indexListFor(text); +} + +void BookmarkManagerWidget::textChanged(const QString &/*text*/) +{ + TRACE_OBJ + refeshBookmarkCache(); + if (!cache.isEmpty()) + ui.treeView->setCurrentIndex(cache.at(0)); +} + +void BookmarkManagerWidget::removeItem(const QModelIndex &index) +{ + TRACE_OBJ + QModelIndex current = index.isValid() ? index : ui.treeView->currentIndex(); + if (!bookmarkModel->parent(current).isValid()) + return; // check if we should delete the "Bookmarks Menu", bail + + if (bookmarkModel->hasChildren(current)) { + int value = QMessageBox::question(this, TR("Remove"), TR("You are going" + "to delete a Folder, this will also
remove it's content. Are " + "you sure to continue?"), + QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel); + if (value == QMessageBox::Cancel) + return; + } + bookmarkModel->removeItem(current); +} + +void BookmarkManagerWidget::customContextMenuRequested(const QPoint &point) +{ + TRACE_OBJ + const QModelIndex &index = ui.treeView->indexAt(point); + if (!index.isValid()) + return; + + // check if we should open the menu on "Bookmarks Menu", bail + if (!bookmarkModel->parent(index).isValid()) + return; + + QAction *remove = 0; + QAction *rename = 0; + QAction *showItem = 0; + QAction *showItemInNewTab = 0; + + QMenu menu(QLatin1String("")); + if (bookmarkModel->data(index, UserRoleFolder).toBool()) { + remove = menu.addAction(TR("Delete Folder")); + rename = menu.addAction(TR("Rename Folder")); + } else { + showItem = menu.addAction(TR("Show Bookmark")); + showItemInNewTab = menu.addAction(TR("Show Bookmark in New Tab")); + menu.addSeparator(); + remove = menu.addAction(TR("Delete Bookmark")); + rename = menu.addAction(TR("Rename Bookmark")); + } + + QAction *pickedAction = menu.exec(ui.treeView->mapToGlobal(point)); + if (pickedAction == rename) + renameItem(index); + else if (pickedAction == remove) + removeItem(index); + else if (pickedAction == showItem || pickedAction == showItemInNewTab) + setSourceFromIndex(index, pickedAction == showItemInNewTab); +} + +void +BookmarkManagerWidget::setSourceFromIndex(const QModelIndex &index, bool newTab) +{ + TRACE_OBJ + if (bookmarkModel->data(index, UserRoleFolder).toBool()) + return; + + const QVariant &data = bookmarkModel->data(index, UserRoleUrl); + if (data.canConvert()) { + if (newTab) + emit setSourceInNewTab(data.toUrl()); + else + emit setSource(data.toUrl()); + } +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/bookmarkmanagerwidget.h b/src/assistant/tools/assistant/bookmarkmanagerwidget.h new file mode 100644 index 000000000..a0dec72a6 --- /dev/null +++ b/src/assistant/tools/assistant/bookmarkmanagerwidget.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef BOOKMARKMANAGERWIDGET_H +#define BOOKMARKMANAGERWIDGET_H + +#include "ui_bookmarkmanagerwidget.h" + +#include + +#include + +QT_BEGIN_NAMESPACE + +class BookmarkModel; +class QCloseEvent; +class QString; + +class BookmarkManagerWidget : public QWidget +{ + Q_OBJECT +public: + explicit BookmarkManagerWidget(BookmarkModel *bookmarkModel, + QWidget *parent = 0); + ~BookmarkManagerWidget(); + +protected: + void closeEvent(QCloseEvent *event); + +signals: + void setSource(const QUrl &url); + void setSourceInNewTab(const QUrl &url); + + void managerWidgetAboutToClose(); + +private: + void renameItem(const QModelIndex &index); + void selectNextIndex(bool direction) const; + bool eventFilter(QObject *object, QEvent *event); + +private slots: + void findNext(); + void findPrevious(); + + void importBookmarks(); + void exportBookmarks(); + + void refeshBookmarkCache(); + void textChanged(const QString &text); + + void removeItem(const QModelIndex &index = QModelIndex()); + + void customContextMenuRequested(const QPoint &point); + void setSourceFromIndex(const QModelIndex &index, bool newTab = false); + +private: + QMenu importExportMenu; + Ui::BookmarkManagerWidget ui; + QList cache; + + BookmarkModel *bookmarkModel; +}; + +QT_END_NAMESPACE + +#endif // BOOKMARKMANAGERWIDGET_H diff --git a/src/assistant/tools/assistant/bookmarkmanagerwidget.ui b/src/assistant/tools/assistant/bookmarkmanagerwidget.ui new file mode 100644 index 000000000..dc965d94e --- /dev/null +++ b/src/assistant/tools/assistant/bookmarkmanagerwidget.ui @@ -0,0 +1,137 @@ + + + BookmarkManagerWidget + + + + 0 + 0 + 517 + 348 + + + + Manage Bookmarks + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Search: + + + + + + + + + + + + true + + + true + + + true + + + 1000 + + + true + + + true + + + 225 + + + 50 + + + 225 + + + 50 + + + + + + + + + Remove + + + + + + + Import and Backup + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + OK + + + + + + + + + + + pushButton_5 + clicked() + BookmarkManagerWidget + close() + + + 445 + 328 + + + 340 + 313 + + + + + diff --git a/src/assistant/tools/assistant/bookmarkmodel.cpp b/src/assistant/tools/assistant/bookmarkmodel.cpp new file mode 100644 index 000000000..49b89c38f --- /dev/null +++ b/src/assistant/tools/assistant/bookmarkmodel.cpp @@ -0,0 +1,461 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "bookmarkmodel.h" +#include "bookmarkitem.h" + +#include +#include + +#include +#include +#include + +const quint32 VERSION = 0xe53798; +const QLatin1String MIMETYPE("application/bookmarks.assistant"); + +BookmarkModel::BookmarkModel() + : QAbstractItemModel() + , m_folder(false) + , m_editable(false) + , rootItem(0) +{ +} + +BookmarkModel::~BookmarkModel() +{ + delete rootItem; +} + +QByteArray +BookmarkModel::bookmarks() const +{ + QByteArray ba; + QDataStream stream(&ba, QIODevice::WriteOnly); + stream << qint32(VERSION); + + const QModelIndex &root = index(0,0, QModelIndex()).parent(); + for (int i = 0; i < rowCount(root); ++i) + collectItems(index(i, 0, root), 0, &stream); + + return ba; +} + +void +BookmarkModel::setBookmarks(const QByteArray &bookmarks) +{ + beginResetModel(); + + delete rootItem; + folderIcon = QApplication::style()->standardIcon(QStyle::SP_DirClosedIcon); + bookmarkIcon = QIcon(QLatin1String(":/trolltech/assistant/images/bookmark.png")); + + rootItem = new BookmarkItem(DataVector() << tr("Name") << tr("Address") + << true); + + QStack parents; + QDataStream stream(bookmarks); + + qint32 version; + stream >> version; + if (version < VERSION) { + stream.device()->seek(0); + BookmarkItem* toolbar = new BookmarkItem(DataVector() << tr("Toolbar Menu") + << QLatin1String("Folder") << true); + rootItem->addChild(toolbar); + + BookmarkItem* menu = new BookmarkItem(DataVector() << tr("Bookmarks Menu") + << QLatin1String("Folder") << true); + rootItem->addChild(menu); + parents.push(menu); + } else { + parents.push(rootItem); + } + + qint32 depth; + bool expanded; + QString name, url; + while (!stream.atEnd()) { + stream >> depth >> name >> url >> expanded; + while ((parents.count() - 1) != depth) + parents.pop(); + + BookmarkItem *item = new BookmarkItem(DataVector() << name << url << expanded); + if (url == QLatin1String("Folder")) { + parents.top()->addChild(item); + parents.push(item); + } else { + parents.top()->addChild(item); + } + } + + cache.clear(); + setupCache(index(0,0, QModelIndex().parent())); + endResetModel(); +} + +void +BookmarkModel::setItemsEditable(bool editable) +{ + m_editable = editable; +} + +void +BookmarkModel::expandFoldersIfNeeeded(QTreeView *treeView) +{ + foreach (const QModelIndex &index, cache) + treeView->setExpanded(index, index.data(UserRoleExpanded).toBool()); +} + +QModelIndex +BookmarkModel::addItem(const QModelIndex &parent, bool isFolder) +{ + m_folder = isFolder; + QModelIndex next; + if (insertRow(rowCount(parent), parent)) + next = index(rowCount(parent) - 1, 0, parent); + m_folder = false; + + return next; +} + +bool +BookmarkModel::removeItem(const QModelIndex &index) +{ + if (!index.isValid()) + return false; + + QModelIndexList indexes; + if (rowCount(index) > 0) + indexes = collectItems(index); + indexes.append(index); + + foreach (const QModelIndex &itemToRemove, indexes) { + if (!removeRow(itemToRemove.row(), itemToRemove.parent())) + return false; + cache.remove(itemFromIndex(itemToRemove)); + } + return true; +} + +int +BookmarkModel::rowCount(const QModelIndex &index) const +{ + if (BookmarkItem *item = itemFromIndex(index)) + return item->childCount(); + return 0; +} + +int +BookmarkModel::columnCount(const QModelIndex &/*index*/) const +{ + return 2; +} + +QModelIndex +BookmarkModel::parent(const QModelIndex &index) const +{ + if (!index.isValid()) + return QModelIndex(); + + if (BookmarkItem *childItem = itemFromIndex(index)) { + if (BookmarkItem *parent = childItem->parent()) { + if (parent != rootItem) + return createIndex(parent->childNumber(), 0, parent); + } + } + return QModelIndex(); +} + +QModelIndex +BookmarkModel::index(int row, int column, const QModelIndex &index) const +{ + if (index.isValid() && (index.column() != 0 && index.column() != 1)) + return QModelIndex(); + + if (BookmarkItem *parent = itemFromIndex(index)) { + if (BookmarkItem *childItem = parent->child(row)) + return createIndex(row, column, childItem); + } + return QModelIndex(); +} + +Qt::DropActions +BookmarkModel::supportedDropActions () const +{ + return /* Qt::CopyAction | */Qt::MoveAction; +} + +Qt::ItemFlags +BookmarkModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return Qt::NoItemFlags; + + Qt::ItemFlags defaultFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; + + if (m_editable) + defaultFlags |= Qt::ItemIsEditable; + + if (itemFromIndex(index) && index.data(UserRoleFolder).toBool()) { + if (index.column() > 0) + return defaultFlags &~ Qt::ItemIsEditable; + return defaultFlags | Qt::ItemIsDropEnabled; + } + + return defaultFlags | Qt::ItemIsDragEnabled; +} + +QVariant +BookmarkModel::data(const QModelIndex &index, int role) const +{ + if (index.isValid()) { + if (BookmarkItem *item = itemFromIndex(index)) { + switch (role) { + case Qt::EditRole: { + case Qt::DisplayRole: + if (index.data(UserRoleFolder).toBool() && index.column() == 1) + return QLatin1String(""); + return item->data(index.column()); + } break; + + case Qt::DecorationRole: { + if (index.column() == 0) + return index.data(UserRoleFolder).toBool() + ? folderIcon : bookmarkIcon; + } break; + + default:; + return item->data(role); + } + } + } + return QVariant(); +} + +void BookmarkModel::setData(const QModelIndex &index, const DataVector &data) +{ + if (BookmarkItem *item = itemFromIndex(index)) { + item->setData(data); + emit dataChanged(index, index); + } +} + +bool +BookmarkModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + bool result = false; + if (role != Qt::EditRole && role != UserRoleExpanded) + return result; + + if (BookmarkItem *item = itemFromIndex(index)) { + if (role == Qt::EditRole) { + const bool isFolder = index.data(UserRoleFolder).toBool(); + if (!isFolder || (isFolder && index.column() == 0)) + result = item->setData(index.column(), value); + } else if (role == UserRoleExpanded) { + result = item->setData(UserRoleExpanded, value); + } + } + + if (result) + emit dataChanged(index, index); + return result; +} + +QVariant +BookmarkModel::headerData(int section, Qt::Orientation orientation, + int role) const +{ + if (rootItem && orientation == Qt::Horizontal && role == Qt::DisplayRole) + return rootItem->data(section); + return QVariant(); +} + +QModelIndex +BookmarkModel::indexFromItem(BookmarkItem *item) const +{ + return cache.value(item, QModelIndex()); +} + +BookmarkItem* +BookmarkModel::itemFromIndex(const QModelIndex &index) const +{ + if (index.isValid()) + return static_cast(index.internalPointer()); + return rootItem; +} + +QList +BookmarkModel::indexListFor(const QString &label) const +{ + QList hits; + const QModelIndexList &list = collectItems(QModelIndex()); + foreach(const QModelIndex &index, list) { + if (index.data().toString().contains(label, Qt::CaseInsensitive)) + hits.prepend(index); // list is reverse sorted + } + return hits; +} + +bool +BookmarkModel::insertRows(int position, int rows, const QModelIndex &parent) +{ + if (!parent.data(UserRoleFolder).toBool()) + return false; + + bool success = false; + if (BookmarkItem *parentItem = itemFromIndex(parent)) { + beginInsertRows(parent, position, position + rows - 1); + success = parentItem->insertChildren(m_folder, position, rows); + if (success) { + const QModelIndex ¤t = index(position, 0, parent); + cache.insert(itemFromIndex(current), current); + } + endInsertRows(); + } + return success; +} + +bool +BookmarkModel::removeRows(int position, int rows, const QModelIndex &index) +{ + bool success = false; + if (BookmarkItem *parent = itemFromIndex(index)) { + beginRemoveRows(index, position, position + rows - 1); + success = parent->removeChildren(position, rows); + endRemoveRows(); + } + return success; +} + +QStringList +BookmarkModel::mimeTypes() const +{ + return QStringList() << MIMETYPE; +} + +QMimeData* +BookmarkModel::mimeData(const QModelIndexList &indexes) const +{ + if (indexes.isEmpty()) + return 0; + + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + + foreach (const QModelIndex &index, indexes) { + if (index.column() == 0) + collectItems(index, 0, &stream); + } + + QMimeData *mimeData = new QMimeData(); + mimeData->setData(MIMETYPE, data); + return mimeData; +} + +bool +BookmarkModel::dropMimeData(const QMimeData *data, Qt::DropAction action, + int row, int column, const QModelIndex &parent) +{ + if (action == Qt::IgnoreAction) + return true; + + if (!data->hasFormat(MIMETYPE) || column > 0) + return false; + + QByteArray ba = data->data(MIMETYPE); + QDataStream stream(&ba, QIODevice::ReadOnly); + while (stream.atEnd()) + return false; + + qint32 depth; + bool expanded; + QString name, url; + while (!stream.atEnd()) { + stream >> depth >> name >> url >> expanded; + if (insertRow(qMax(0, row), parent)) { + const QModelIndex ¤t = index(qMax(0, row), 0, parent); + if (current.isValid()) { + BookmarkItem* item = itemFromIndex(current); + item->setData(DataVector() << name << url << expanded); + } + } + } + return true; +} + +void +BookmarkModel::setupCache(const QModelIndex &parent) +{ + const QModelIndexList &list = collectItems(parent); + foreach (const QModelIndex &index, list) + cache.insert(itemFromIndex(index), index); +} + +QModelIndexList +BookmarkModel::collectItems(const QModelIndex &parent) const +{ + QModelIndexList list; + for (int i = rowCount(parent) - 1; i >= 0 ; --i) { + const QModelIndex &next = index(i, 0, parent); + if (data(next, UserRoleFolder).toBool()) + list += collectItems(next); + list.append(next); + } + return list; +} + +void +BookmarkModel::collectItems(const QModelIndex &parent, qint32 depth, + QDataStream *stream) const +{ + if (parent.isValid()) { + *stream << depth; + *stream << parent.data().toString(); + *stream << parent.data(UserRoleUrl).toString(); + *stream << parent.data(UserRoleExpanded).toBool(); + + for (int i = 0; i < rowCount(parent); ++i) { + if (parent.data(UserRoleFolder).toBool()) + collectItems(index(i, 0 , parent), depth + 1, stream); + } + } +} diff --git a/src/assistant/tools/assistant/bookmarkmodel.h b/src/assistant/tools/assistant/bookmarkmodel.h new file mode 100644 index 000000000..33c9e981d --- /dev/null +++ b/src/assistant/tools/assistant/bookmarkmodel.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef BOOKMARKMODEL_H +#define BOOKMARKMODEL_H + +#include + +#include + +QT_BEGIN_NAMESPACE + +class BookmarkItem; +class QMimeData; +class QTreeView; + +typedef QMap ItemModelIndexCache; + +class BookmarkModel : public QAbstractItemModel +{ + Q_OBJECT +public: + BookmarkModel(); + ~BookmarkModel(); + + QByteArray bookmarks() const; + void setBookmarks(const QByteArray &bookmarks); + + void setItemsEditable(bool editable); + void expandFoldersIfNeeeded(QTreeView *treeView); + + QModelIndex addItem(const QModelIndex &parent, bool isFolder = false); + bool removeItem(const QModelIndex &index); + + int rowCount(const QModelIndex &index = QModelIndex()) const; + int columnCount(const QModelIndex &index = QModelIndex()) const; + + QModelIndex parent(const QModelIndex &index) const; + QModelIndex index(int row, int column, const QModelIndex &index) const; + + Qt::DropActions supportedDropActions () const; + Qt::ItemFlags flags(const QModelIndex &index) const; + + QVariant data(const QModelIndex &index, int role) const; + void setData(const QModelIndex &index, const QVector &data); + bool setData(const QModelIndex &index, const QVariant &value, int role); + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + + QModelIndex indexFromItem(BookmarkItem *item) const; + BookmarkItem *itemFromIndex(const QModelIndex &index) const; + QList indexListFor(const QString &label) const; + + bool insertRows(int position, int rows, const QModelIndex &parent); + bool removeRows(int position, int rows, const QModelIndex &parent); + + QStringList mimeTypes() const; + QMimeData* mimeData(const QModelIndexList &indexes) const; + bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, + int column, const QModelIndex &parent); + +private: + void setupCache(const QModelIndex &parent); + QModelIndexList collectItems(const QModelIndex &parent) const; + void collectItems(const QModelIndex &parent, qint32 depth, + QDataStream *stream) const; + +private: + int columns; + bool m_folder; + bool m_editable; + QIcon folderIcon; + QIcon bookmarkIcon; + QTreeView *treeView; + BookmarkItem *rootItem; + ItemModelIndexCache cache; +}; + +QT_END_NAMESPACE + +#endif // BOOKMARKMODEL_H diff --git a/src/assistant/tools/assistant/bookmarkwidget.ui b/src/assistant/tools/assistant/bookmarkwidget.ui new file mode 100644 index 000000000..a31a2779c --- /dev/null +++ b/src/assistant/tools/assistant/bookmarkwidget.ui @@ -0,0 +1,85 @@ + + + BookmarkWidget + + + + 0 + 0 + 235 + 606 + + + + Bookmarks + + + + 4 + + + + + + + Filter: + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Add + + + + + + + Remove + + + + + + + + + + diff --git a/src/assistant/tools/assistant/centralwidget.cpp b/src/assistant/tools/assistant/centralwidget.cpp new file mode 100644 index 000000000..c8c454f60 --- /dev/null +++ b/src/assistant/tools/assistant/centralwidget.cpp @@ -0,0 +1,636 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "centralwidget.h" + +#include "findwidget.h" +#include "helpenginewrapper.h" +#include "helpviewer.h" +#include "openpagesmanager.h" +#include "tracer.h" +#include "../shared/collectionconfiguration.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace { + CentralWidget *staticCentralWidget = 0; +} + +// -- TabBar + +TabBar::TabBar(QWidget *parent) + : QTabBar(parent) +{ + TRACE_OBJ +#ifdef Q_OS_MAC + setDocumentMode(true); +#endif + setMovable(true); + setShape(QTabBar::RoundedNorth); + setContextMenuPolicy(Qt::CustomContextMenu); + setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred, + QSizePolicy::TabWidget)); + connect(this, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentChanged(int))); + connect(this, SIGNAL(tabCloseRequested(int)), this, SLOT(slotTabCloseRequested(int))); + connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, + SLOT(slotCustomContextMenuRequested(QPoint))); +} + +TabBar::~TabBar() +{ + TRACE_OBJ +} + +int TabBar::addNewTab(const QString &title) +{ + TRACE_OBJ + const int index = addTab(title); + setTabsClosable(count() > 1); + return index; +} + +void TabBar::setCurrent(HelpViewer *viewer) +{ + TRACE_OBJ + for (int i = 0; i < count(); ++i) { + HelpViewer *data = tabData(i).value(); + if (data == viewer) { + setCurrentIndex(i); + break; + } + } +} + +void TabBar::removeTabAt(HelpViewer *viewer) +{ + TRACE_OBJ + for (int i = 0; i < count(); ++i) { + HelpViewer *data = tabData(i).value(); + if (data == viewer) { + removeTab(i); + break; + } + } + setTabsClosable(count() > 1); +} + +void TabBar::titleChanged() +{ + TRACE_OBJ + for (int i = 0; i < count(); ++i) { + HelpViewer *data = tabData(i).value(); + QString title = data->title(); + title.replace(QLatin1Char('&'), QLatin1String("&&")); + setTabText(i, title.isEmpty() ? tr("(Untitled)") : title); + } +} + +void TabBar::slotCurrentChanged(int index) +{ + TRACE_OBJ + emit currentTabChanged(tabData(index).value()); +} + +void TabBar::slotTabCloseRequested(int index) +{ + TRACE_OBJ + OpenPagesManager::instance()->closePage(tabData(index).value()); +} + +void TabBar::slotCustomContextMenuRequested(const QPoint &pos) +{ + TRACE_OBJ + const int tab = tabAt(pos); + if (tab < 0) + return; + + QMenu menu(QLatin1String(""), this); + menu.addAction(tr("New &Tab"), OpenPagesManager::instance(), SLOT(createPage())); + + const bool enableAction = count() > 1; + QAction *closePage = menu.addAction(tr("&Close Tab")); + closePage->setEnabled(enableAction); + + QAction *closePages = menu.addAction(tr("Close Other Tabs")); + closePages->setEnabled(enableAction); + + menu.addSeparator(); + + HelpViewer *viewer = tabData(tab).value(); + QAction *newBookmark = menu.addAction(tr("Add Bookmark for this Page...")); + const QString &url = viewer->source().toString(); + if (url.isEmpty() || url == QLatin1String("about:blank")) + newBookmark->setEnabled(false); + + QAction *pickedAction = menu.exec(mapToGlobal(pos)); + if (pickedAction == closePage) + slotTabCloseRequested(tab); + else if (pickedAction == closePages) { + for (int i = count() - 1; i >= 0; --i) { + if (i != tab) + slotTabCloseRequested(i); + } + } else if (pickedAction == newBookmark) + emit addBookmark(viewer->title(), url); +} + +// -- CentralWidget + +CentralWidget::CentralWidget(QWidget *parent) + : QWidget(parent) +#ifndef QT_NO_PRINTER + , m_printer(0) +#endif + , m_findWidget(new FindWidget(this)) + , m_stackedWidget(new QStackedWidget(this)) + , m_tabBar(new TabBar(this)) +{ + TRACE_OBJ + staticCentralWidget = this; + QVBoxLayout *vboxLayout = new QVBoxLayout(this); + + vboxLayout->setMargin(0); + vboxLayout->setSpacing(0); + vboxLayout->addWidget(m_tabBar); + m_tabBar->setVisible(HelpEngineWrapper::instance().showTabs()); + vboxLayout->addWidget(m_stackedWidget); + vboxLayout->addWidget(m_findWidget); + m_findWidget->hide(); + + connect(m_findWidget, SIGNAL(findNext()), this, SLOT(findNext())); + connect(m_findWidget, SIGNAL(findPrevious()), this, SLOT(findPrevious())); + connect(m_findWidget, SIGNAL(find(QString, bool, bool)), this, + SLOT(find(QString, bool, bool))); + connect(m_findWidget, SIGNAL(escapePressed()), this, SLOT(activateTab())); + connect(m_tabBar, SIGNAL(addBookmark(QString, QString)), this, + SIGNAL(addBookmark(QString, QString))); +} + +CentralWidget::~CentralWidget() +{ + TRACE_OBJ + QStringList zoomFactors; + QStringList currentPages; + for (int i = 0; i < m_stackedWidget->count(); ++i) { + const HelpViewer * const viewer = viewerAt(i); + const QUrl &source = viewer->source(); + if (source.isValid()) { + currentPages << source.toString(); + zoomFactors << QString::number(viewer->scale()); + } + } + + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + helpEngine.setLastShownPages(currentPages); + helpEngine.setLastZoomFactors(zoomFactors); + helpEngine.setLastTabPage(m_stackedWidget->currentIndex()); + +#ifndef QT_NO_PRINTER + delete m_printer; +#endif +} + +CentralWidget *CentralWidget::instance() +{ + TRACE_OBJ + return staticCentralWidget; +} + +QUrl CentralWidget::currentSource() const +{ + TRACE_OBJ + return currentHelpViewer()->source(); +} + +QString CentralWidget::currentTitle() const +{ + TRACE_OBJ + return currentHelpViewer()->title(); +} + +bool CentralWidget::hasSelection() const +{ + TRACE_OBJ + return !currentHelpViewer()->selectedText().isEmpty(); +} + +bool CentralWidget::isForwardAvailable() const +{ + TRACE_OBJ + return currentHelpViewer()->isForwardAvailable(); +} + +bool CentralWidget::isBackwardAvailable() const +{ + TRACE_OBJ + return currentHelpViewer()->isBackwardAvailable(); +} + +HelpViewer* CentralWidget::viewerAt(int index) const +{ + TRACE_OBJ + return static_cast(m_stackedWidget->widget(index)); +} + +HelpViewer* CentralWidget::currentHelpViewer() const +{ + TRACE_OBJ + return static_cast(m_stackedWidget->currentWidget()); +} + +void CentralWidget::addPage(HelpViewer *page, bool fromSearch) +{ + TRACE_OBJ + page->installEventFilter(this); + page->setFocus(Qt::OtherFocusReason); + connectSignals(page); + const int index = m_stackedWidget->addWidget(page); + m_tabBar->setTabData(m_tabBar->addNewTab(page->title()), + QVariant::fromValue(viewerAt(index))); + connect (page, SIGNAL(titleChanged()), m_tabBar, SLOT(titleChanged())); + + if (fromSearch) { + connect(currentHelpViewer(), SIGNAL(loadFinished(bool)), this, + SLOT(highlightSearchTerms())); + } +} + +void CentralWidget::removePage(int index) +{ + TRACE_OBJ + const bool currentChanged = index == currentIndex(); + m_tabBar->removeTabAt(viewerAt(index)); + m_stackedWidget->removeWidget(m_stackedWidget->widget(index)); + if (currentChanged) + emit currentViewerChanged(); +} + +int CentralWidget::currentIndex() const +{ + TRACE_OBJ + return m_stackedWidget->currentIndex(); +} + +void CentralWidget::setCurrentPage(HelpViewer *page) +{ + TRACE_OBJ + m_tabBar->setCurrent(page); + m_stackedWidget->setCurrentWidget(page); + emit currentViewerChanged(); +} + +void CentralWidget::connectTabBar() +{ + TRACE_OBJ + connect(m_tabBar, SIGNAL(currentTabChanged(HelpViewer*)), + OpenPagesManager::instance(), SLOT(setCurrentPage(HelpViewer*))); +} + +// -- public slots + +void CentralWidget::copy() +{ + TRACE_OBJ + currentHelpViewer()->copy(); +} + +void CentralWidget::home() +{ + TRACE_OBJ + currentHelpViewer()->home(); +} + +void CentralWidget::zoomIn() +{ + TRACE_OBJ + currentHelpViewer()->scaleUp(); +} + +void CentralWidget::zoomOut() +{ + TRACE_OBJ + currentHelpViewer()->scaleDown(); +} + +void CentralWidget::resetZoom() +{ + TRACE_OBJ + currentHelpViewer()->resetScale(); +} + +void CentralWidget::forward() +{ + TRACE_OBJ + currentHelpViewer()->forward(); +} + +void CentralWidget::nextPage() +{ + TRACE_OBJ + m_stackedWidget->setCurrentIndex((m_stackedWidget->currentIndex() + 1) + % m_stackedWidget->count()); +} + +void CentralWidget::backward() +{ + TRACE_OBJ + currentHelpViewer()->backward(); +} + +void CentralWidget::previousPage() +{ + TRACE_OBJ + m_stackedWidget->setCurrentIndex((m_stackedWidget->currentIndex() - 1) + % m_stackedWidget->count()); +} + +void CentralWidget::print() +{ + TRACE_OBJ +#ifndef QT_NO_PRINTER + initPrinter(); + QPrintDialog dlg(m_printer, this); + + if (!currentHelpViewer()->selectedText().isEmpty()) + dlg.addEnabledOption(QAbstractPrintDialog::PrintSelection); + dlg.addEnabledOption(QAbstractPrintDialog::PrintPageRange); + dlg.addEnabledOption(QAbstractPrintDialog::PrintCollateCopies); + dlg.setWindowTitle(tr("Print Document")); + if (dlg.exec() == QDialog::Accepted) + currentHelpViewer()->print(m_printer); +#endif +} + +void CentralWidget::pageSetup() +{ + TRACE_OBJ +#ifndef QT_NO_PRINTER + initPrinter(); + QPageSetupDialog dlg(m_printer); + dlg.exec(); +#endif +} + +void CentralWidget::printPreview() +{ + TRACE_OBJ +#ifndef QT_NO_PRINTER + initPrinter(); + QPrintPreviewDialog preview(m_printer, this); + connect(&preview, SIGNAL(paintRequested(QPrinter*)), + SLOT(printPreview(QPrinter*))); + preview.exec(); +#endif +} + +void CentralWidget::setSource(const QUrl &url) +{ + TRACE_OBJ + HelpViewer *viewer = currentHelpViewer(); + viewer->setSource(url); + viewer->setFocus(Qt::OtherFocusReason); +} + +void CentralWidget::setSourceFromSearch(const QUrl &url) +{ + TRACE_OBJ + connect(currentHelpViewer(), SIGNAL(loadFinished(bool)), this, + SLOT(highlightSearchTerms())); + currentHelpViewer()->setSource(url); + currentHelpViewer()->setFocus(Qt::OtherFocusReason); +} + +void CentralWidget::findNext() +{ + TRACE_OBJ + find(m_findWidget->text(), true, false); +} + +void CentralWidget::findPrevious() +{ + TRACE_OBJ + find(m_findWidget->text(), false, false); +} + +void CentralWidget::find(const QString &ttf, bool forward, bool incremental) +{ + TRACE_OBJ + bool found = false; + if (HelpViewer *viewer = currentHelpViewer()) { + HelpViewer::FindFlags flags = 0; + if (!forward) + flags |= HelpViewer::FindBackward; + if (m_findWidget->caseSensitive()) + flags |= HelpViewer::FindCaseSensitively; + found = viewer->findText(ttf, flags, incremental, false); + } + + if (!found && ttf.isEmpty()) + found = true; // the line edit is empty, no need to mark it red... + + if (!m_findWidget->isVisible()) + m_findWidget->show(); + m_findWidget->setPalette(found); +} + +void CentralWidget::activateTab() +{ + TRACE_OBJ + currentHelpViewer()->setFocus(); +} + +void CentralWidget::showTextSearch() +{ + TRACE_OBJ + m_findWidget->show(); +} + +void CentralWidget::updateBrowserFont() +{ + TRACE_OBJ + const int count = m_stackedWidget->count(); + const QFont &font = viewerAt(count - 1)->viewerFont(); + for (int i = 0; i < count; ++i) + viewerAt(i)->setViewerFont(font); +} + +void CentralWidget::updateUserInterface() +{ + m_tabBar->setVisible(HelpEngineWrapper::instance().showTabs()); +} + +// -- protected + +void CentralWidget::keyPressEvent(QKeyEvent *e) +{ + TRACE_OBJ + const QString &text = e->text(); + if (text.startsWith(QLatin1Char('/'))) { + if (!m_findWidget->isVisible()) { + m_findWidget->showAndClear(); + } else { + m_findWidget->show(); + } + } else { + QWidget::keyPressEvent(e); + } +} + +void CentralWidget::focusInEvent(QFocusEvent * /* event */) +{ + TRACE_OBJ + // If we have a current help viewer then this is the 'focus proxy', + // otherwise it's the central widget. This is needed, so an embedding + // program can just set the focus to the central widget and it does + // The Right Thing(TM) + QObject *receiver = m_stackedWidget; + if (HelpViewer *viewer = currentHelpViewer()) + receiver = viewer; + QTimer::singleShot(1, receiver, SLOT(setFocus())); +} + +// -- private slots + +void CentralWidget::highlightSearchTerms() +{ + TRACE_OBJ + QHelpSearchEngine *searchEngine = + HelpEngineWrapper::instance().searchEngine(); + QList queryList = searchEngine->query(); + + QStringList terms; + foreach (const QHelpSearchQuery &query, queryList) { + switch (query.fieldName) { + default: break; + case QHelpSearchQuery::ALL: { + case QHelpSearchQuery::PHRASE: + case QHelpSearchQuery::DEFAULT: + case QHelpSearchQuery::ATLEAST: + foreach (QString term, query.wordList) + terms.append(term.remove(QLatin1Char('"'))); + } + } + } + + HelpViewer *viewer = currentHelpViewer(); + foreach (const QString& term, terms) + viewer->findText(term, 0, false, true); + disconnect(viewer, SIGNAL(loadFinished(bool)), this, + SLOT(highlightSearchTerms())); +} + +void CentralWidget::printPreview(QPrinter *p) +{ + TRACE_OBJ +#ifndef QT_NO_PRINTER + currentHelpViewer()->print(p); +#endif +} + +void CentralWidget::handleSourceChanged(const QUrl &url) +{ + TRACE_OBJ + if (sender() == currentHelpViewer()) + emit sourceChanged(url); +} + +// -- private + +void CentralWidget::initPrinter() +{ + TRACE_OBJ +#ifndef QT_NO_PRINTER + if (!m_printer) + m_printer = new QPrinter(QPrinter::HighResolution); +#endif +} + +void CentralWidget::connectSignals(HelpViewer *page) +{ + TRACE_OBJ + connect(page, SIGNAL(copyAvailable(bool)), this, + SIGNAL(copyAvailable(bool))); + connect(page, SIGNAL(forwardAvailable(bool)), this, + SIGNAL(forwardAvailable(bool))); + connect(page, SIGNAL(backwardAvailable(bool)), this, + SIGNAL(backwardAvailable(bool))); + connect(page, SIGNAL(sourceChanged(QUrl)), this, + SLOT(handleSourceChanged(QUrl))); + connect(page, SIGNAL(highlighted(QString)), this, + SIGNAL(highlighted(QString))); + connect(page, SIGNAL(printRequested()), this, SLOT(print())); +} + +bool CentralWidget::eventFilter(QObject *object, QEvent *e) +{ + TRACE_OBJ + if (e->type() != QEvent::KeyPress) + return QWidget::eventFilter(object, e); + + HelpViewer *viewer = currentHelpViewer(); + QKeyEvent *keyEvent = static_cast (e); + if (viewer == object && keyEvent->key() == Qt::Key_Backspace) { + if (viewer->isBackwardAvailable()) { +#if !defined(QT_NO_WEBKIT) + // this helps in case there is an html field + if (!viewer->hasFocus()) +#endif + viewer->backward(); + } + } + return QWidget::eventFilter(object, e); +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/centralwidget.h b/src/assistant/tools/assistant/centralwidget.h new file mode 100644 index 000000000..2645fa8df --- /dev/null +++ b/src/assistant/tools/assistant/centralwidget.h @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CENTRALWIDGET_H +#define CENTRALWIDGET_H + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class FindWidget; +class HelpViewer; +class QStackedWidget; + +class TabBar : public QTabBar +{ + Q_OBJECT +public: + TabBar(QWidget *parent = 0); + ~TabBar(); + + int addNewTab(const QString &title); + void setCurrent(HelpViewer *viewer); + void removeTabAt(HelpViewer *viewer); + +public slots: + void titleChanged(); + +signals: + void currentTabChanged(HelpViewer *viewer); + void addBookmark(const QString &title, const QString &url); + +private slots: + void slotCurrentChanged(int index); + void slotTabCloseRequested(int index); + void slotCustomContextMenuRequested(const QPoint &pos); +}; + +class CentralWidget : public QWidget +{ + Q_OBJECT + +public: + CentralWidget(QWidget *parent = 0); + ~CentralWidget(); + + static CentralWidget *instance(); + + QUrl currentSource() const; + QString currentTitle() const; + + bool hasSelection() const; + bool isForwardAvailable() const; + bool isBackwardAvailable() const; + + HelpViewer *viewerAt(int index) const; + HelpViewer *currentHelpViewer() const; + + void addPage(HelpViewer *page, bool fromSearch = false); + void removePage(int index); + + int currentIndex() const; + void setCurrentPage(HelpViewer *page); + + void connectTabBar(); + +public slots: + void copy(); + void home(); + + void zoomIn(); + void zoomOut(); + void resetZoom(); + + void forward(); + void nextPage(); + + void backward(); + void previousPage(); + + void print(); + void pageSetup(); + void printPreview(); + + void setSource(const QUrl &url); + void setSourceFromSearch(const QUrl &url); + + void findNext(); + void findPrevious(); + void find(const QString &text, bool forward, bool incremental); + + void activateTab(); + void showTextSearch(); + void updateBrowserFont(); + void updateUserInterface(); + +signals: + void currentViewerChanged(); + void copyAvailable(bool yes); + void sourceChanged(const QUrl &url); + void highlighted(const QString &link); + void forwardAvailable(bool available); + void backwardAvailable(bool available); + void addBookmark(const QString &title, const QString &url); + +protected: + void keyPressEvent(QKeyEvent *); + void focusInEvent(QFocusEvent *event); + +private slots: + void highlightSearchTerms(); + void printPreview(QPrinter *printer); + void handleSourceChanged(const QUrl &url); + +private: + void initPrinter(); + void connectSignals(HelpViewer *page); + bool eventFilter(QObject *object, QEvent *e); + +private: +#ifndef QT_NO_PRINTER + QPrinter *m_printer; +#endif + FindWidget *m_findWidget; + QStackedWidget *m_stackedWidget; + TabBar *m_tabBar; +}; + +QT_END_NAMESPACE + +#endif // CENTRALWIDGET_H diff --git a/src/assistant/tools/assistant/cmdlineparser.cpp b/src/assistant/tools/assistant/cmdlineparser.cpp new file mode 100644 index 000000000..6a239d305 --- /dev/null +++ b/src/assistant/tools/assistant/cmdlineparser.cpp @@ -0,0 +1,376 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "tracer.h" + +#include +#include +#include + +#include "cmdlineparser.h" + +QT_BEGIN_NAMESPACE + +static const char helpMessage[] = QT_TRANSLATE_NOOP("CmdLineParser", + "Usage: assistant [Options]\n\n" + "-collectionFile file Uses the specified collection\n" + " file instead of the default one\n" + "-showUrl url Shows the document with the\n" + " url.\n" + "-enableRemoteControl Enables Assistant to be\n" + " remotely controlled.\n" + "-show widget Shows the specified dockwidget\n" + " which can be \"contents\", \"index\",\n" + " \"bookmarks\" or \"search\".\n" + "-activate widget Activates the specified dockwidget\n" + " which can be \"contents\", \"index\",\n" + " \"bookmarks\" or \"search\".\n" + "-hide widget Hides the specified dockwidget\n" + " which can be \"contents\", \"index\"\n" + " \"bookmarks\" or \"search\".\n" + "-register helpFile Registers the specified help file\n" + " (.qch) in the given collection\n" + " file.\n" + "-unregister helpFile Unregisters the specified help file\n" + " (.qch) from the give collection\n" + " file.\n" + "-setCurrentFilter filter Set the filter as the active filter.\n" + "-remove-search-index Removes the full text search index.\n" + "-rebuild-search-index Re-builds the full text search index (potentially slow).\n" + "-quiet Does not display any error or\n" + " status message.\n" + "-help Displays this help.\n" + ); + + +CmdLineParser::CmdLineParser(const QStringList &arguments) + : m_pos(0), + m_enableRemoteControl(false), + m_contents(Untouched), + m_index(Untouched), + m_bookmarks(Untouched), + m_search(Untouched), + m_register(None), + m_removeSearchIndex(false), + m_rebuildSearchIndex(false), + m_quiet(false) +{ + TRACE_OBJ + for (int i = 1; i < arguments.count(); ++i) { + const QString &arg = arguments.at(i); + if (arg.toLower() == "-quiet") + m_quiet = true; + else + m_arguments.append(arg); + } +} + +CmdLineParser::Result CmdLineParser::parse() +{ + TRACE_OBJ + bool showHelp = false; + + while (m_error.isEmpty() && hasMoreArgs()) { + const QString &arg = nextArg().toLower(); + if (arg == QLatin1String("-collectionfile")) + handleCollectionFileOption(); + else if (arg == QLatin1String("-showurl")) + handleShowUrlOption(); + else if (arg == QLatin1String("-enableremotecontrol")) + m_enableRemoteControl = true; + else if (arg == QLatin1String("-show")) + handleShowOption(); + else if (arg == QLatin1String("-hide")) + handleHideOption(); + else if (arg == QLatin1String("-activate")) + handleActivateOption(); + else if (arg == QLatin1String("-register")) + handleRegisterOption(); + else if (arg == QLatin1String("-unregister")) + handleUnregisterOption(); + else if (arg == QLatin1String("-setcurrentfilter")) + handleSetCurrentFilterOption(); + else if (arg == QLatin1String("-remove-search-index")) + m_removeSearchIndex = true; + else if (arg == QLatin1String("-rebuild-search-index")) + m_rebuildSearchIndex = true; + else if (arg == QLatin1String("-help")) + showHelp = true; + else + m_error = tr("Unknown option: %1").arg(arg); + } + + if (!m_error.isEmpty()) { + showMessage(m_error + QLatin1String("\n\n\n") + tr(helpMessage), true); + return Error; + } else if (showHelp) { + showMessage(tr(helpMessage), false); + return Help; + } + return Ok; +} + +bool CmdLineParser::hasMoreArgs() const +{ + TRACE_OBJ + return m_pos < m_arguments.count(); +} + +const QString &CmdLineParser::nextArg() +{ + TRACE_OBJ + Q_ASSERT(hasMoreArgs()); + return m_arguments.at(m_pos++); +} + +void CmdLineParser::handleCollectionFileOption() +{ + TRACE_OBJ + if (hasMoreArgs()) { + const QString &fileName = nextArg(); + m_collectionFile = getFileName(fileName); + if (m_collectionFile.isEmpty()) + m_error = tr("The collection file '%1' does not exist."). + arg(fileName); + } else { + m_error = tr("Missing collection file."); + } +} + +void CmdLineParser::handleShowUrlOption() +{ + TRACE_OBJ + if (hasMoreArgs()) { + const QString &urlString = nextArg(); + QUrl url(urlString); + if (url.isValid()) { + m_url = url; + } else + m_error = tr("Invalid URL '%1'.").arg(urlString); + } else { + m_error = tr("Missing URL."); + } +} + +void CmdLineParser::handleShowOption() +{ + TRACE_OBJ + handleShowOrHideOrActivateOption(Show); +} + +void CmdLineParser::handleHideOption() +{ + TRACE_OBJ + handleShowOrHideOrActivateOption(Hide); +} + +void CmdLineParser::handleActivateOption() +{ + TRACE_OBJ + handleShowOrHideOrActivateOption(Activate); +} + +void CmdLineParser::handleShowOrHideOrActivateOption(ShowState state) +{ + TRACE_OBJ + if (hasMoreArgs()) { + const QString &widget = nextArg().toLower(); + if (widget == QLatin1String("contents")) + m_contents = state; + else if (widget == QLatin1String("index")) + m_index = state; + else if (widget == QLatin1String("bookmarks")) + m_bookmarks = state; + else if (widget == QLatin1String("search")) + m_search = state; + else + m_error = tr("Unknown widget: %1").arg(widget); + } else { + m_error = tr("Missing widget."); + } +} + +void CmdLineParser::handleRegisterOption() +{ + TRACE_OBJ + handleRegisterOrUnregisterOption(Register); +} + +void CmdLineParser::handleUnregisterOption() +{ + TRACE_OBJ + handleRegisterOrUnregisterOption(Unregister); +} + +void CmdLineParser::handleRegisterOrUnregisterOption(RegisterState state) +{ + TRACE_OBJ + if (hasMoreArgs()) { + const QString &fileName = nextArg(); + m_helpFile = getFileName(fileName); + if (m_helpFile.isEmpty()) + m_error = tr("The Qt help file '%1' does not exist.").arg(fileName); + else + m_register = state; + } else { + m_error = tr("Missing help file."); + } +} + +void CmdLineParser::handleSetCurrentFilterOption() +{ + TRACE_OBJ + if (hasMoreArgs()) + m_currentFilter = nextArg(); + else + m_error = tr("Missing filter argument."); +} + +QString CmdLineParser::getFileName(const QString &fileName) +{ + TRACE_OBJ + QFileInfo fi(fileName); + if (!fi.exists()) + return QString(); + return fi.absoluteFilePath(); +} + +void CmdLineParser::showMessage(const QString &msg, bool error) +{ + TRACE_OBJ + if (m_quiet) + return; +#ifdef Q_OS_WIN + QString message = QLatin1String("
") % msg % QLatin1String("
"); + if (error) + QMessageBox::critical(0, tr("Error"), message); + else + QMessageBox::information(0, tr("Notice"), message); +#else + fprintf(error ? stderr : stdout, "%s\n", qPrintable(msg)); +#endif +} + +void CmdLineParser::setCollectionFile(const QString &file) +{ + TRACE_OBJ + m_collectionFile = file; +} + +QString CmdLineParser::collectionFile() const +{ + TRACE_OBJ + return m_collectionFile; +} + +bool CmdLineParser::collectionFileGiven() const +{ + TRACE_OBJ + return m_arguments.contains(QLatin1String("-collectionfile"), + Qt::CaseInsensitive); +} + +QUrl CmdLineParser::url() const +{ + TRACE_OBJ + return m_url; +} + +bool CmdLineParser::enableRemoteControl() const +{ + TRACE_OBJ + return m_enableRemoteControl; +} + +CmdLineParser::ShowState CmdLineParser::contents() const +{ + TRACE_OBJ + return m_contents; +} + +CmdLineParser::ShowState CmdLineParser::index() const +{ + TRACE_OBJ + return m_index; +} + +CmdLineParser::ShowState CmdLineParser::bookmarks() const +{ + TRACE_OBJ + return m_bookmarks; +} + +CmdLineParser::ShowState CmdLineParser::search() const +{ + TRACE_OBJ + return m_search; +} + +QString CmdLineParser::currentFilter() const +{ + TRACE_OBJ + return m_currentFilter; +} + +bool CmdLineParser::removeSearchIndex() const +{ + TRACE_OBJ + return m_removeSearchIndex; +} + +bool CmdLineParser::rebuildSearchIndex() const +{ + TRACE_OBJ + return m_rebuildSearchIndex; +} + +CmdLineParser::RegisterState CmdLineParser::registerRequest() const +{ + TRACE_OBJ + return m_register; +} + +QString CmdLineParser::helpFile() const +{ + TRACE_OBJ + return m_helpFile; +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/cmdlineparser.h b/src/assistant/tools/assistant/cmdlineparser.h new file mode 100644 index 000000000..f45679f66 --- /dev/null +++ b/src/assistant/tools/assistant/cmdlineparser.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CMDLINEPARSER_H +#define CMDLINEPARSER_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class CmdLineParser +{ + Q_DECLARE_TR_FUNCTIONS(CmdLineParser) +public: + enum Result {Ok, Help, Error}; + enum ShowState {Untouched, Show, Hide, Activate}; + enum RegisterState {None, Register, Unregister}; + + CmdLineParser(const QStringList &arguments); + Result parse(); + + void setCollectionFile(const QString &file); + QString collectionFile() const; + bool collectionFileGiven() const; + QString cloneFile() const; + QUrl url() const; + bool enableRemoteControl() const; + ShowState contents() const; + ShowState index() const; + ShowState bookmarks() const; + ShowState search() const; + QString currentFilter() const; + bool removeSearchIndex() const; + bool rebuildSearchIndex() const; + RegisterState registerRequest() const; + QString helpFile() const; + + void showMessage(const QString &msg, bool error); + +private: + QString getFileName(const QString &fileName); + bool hasMoreArgs() const; + const QString &nextArg(); + void handleCollectionFileOption(); + void handleShowUrlOption(); + void handleShowOption(); + void handleHideOption(); + void handleActivateOption(); + void handleShowOrHideOrActivateOption(ShowState state); + void handleRegisterOption(); + void handleUnregisterOption(); + void handleRegisterOrUnregisterOption(RegisterState state); + void handleSetCurrentFilterOption(); + + QStringList m_arguments; + int m_pos; + QString m_collectionFile; + QString m_cloneFile; + QString m_helpFile; + QUrl m_url; + bool m_enableRemoteControl; + + ShowState m_contents; + ShowState m_index; + ShowState m_bookmarks; + ShowState m_search; + RegisterState m_register; + QString m_currentFilter; + bool m_removeSearchIndex; + bool m_rebuildSearchIndex; + bool m_quiet; + QString m_error; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/assistant/tools/assistant/contentwindow.cpp b/src/assistant/tools/assistant/contentwindow.cpp new file mode 100644 index 000000000..fbf70aa1f --- /dev/null +++ b/src/assistant/tools/assistant/contentwindow.cpp @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "contentwindow.h" + +#include "centralwidget.h" +#include "helpenginewrapper.h" +#include "helpviewer.h" +#include "openpagesmanager.h" +#include "tracer.h" + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +ContentWindow::ContentWindow() + : m_contentWidget(HelpEngineWrapper::instance().contentWidget()) + , m_expandDepth(-2) +{ + TRACE_OBJ + m_contentWidget->viewport()->installEventFilter(this); + m_contentWidget->setContextMenuPolicy(Qt::CustomContextMenu); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->setMargin(4); + layout->addWidget(m_contentWidget); + + connect(m_contentWidget, SIGNAL(customContextMenuRequested(QPoint)), this, + SLOT(showContextMenu(QPoint))); + connect(m_contentWidget, SIGNAL(linkActivated(QUrl)), this, + SIGNAL(linkActivated(QUrl))); + + QHelpContentModel *contentModel = + qobject_cast(m_contentWidget->model()); + connect(contentModel, SIGNAL(contentsCreated()), this, SLOT(expandTOC())); +} + +ContentWindow::~ContentWindow() +{ + TRACE_OBJ +} + +bool ContentWindow::syncToContent(const QUrl& url) +{ + TRACE_OBJ + QModelIndex idx = m_contentWidget->indexOf(url); + if (!idx.isValid()) + return false; + m_contentWidget->setCurrentIndex(idx); + return true; +} + +void ContentWindow::expandTOC() +{ + TRACE_OBJ + Q_ASSERT(m_expandDepth >= -2); + if (m_expandDepth > -2) { + expandToDepth(m_expandDepth); + m_expandDepth = -2; + } +} + +void ContentWindow::expandToDepth(int depth) +{ + TRACE_OBJ + Q_ASSERT(depth >= -2); + m_expandDepth = depth; + if (depth == -1) + m_contentWidget->expandAll(); + else if (depth == 0) + m_contentWidget->collapseAll(); + else + m_contentWidget->expandToDepth(depth - 1); +} + +void ContentWindow::focusInEvent(QFocusEvent *e) +{ + TRACE_OBJ + if (e->reason() != Qt::MouseFocusReason) + m_contentWidget->setFocus(); +} + +void ContentWindow::keyPressEvent(QKeyEvent *e) +{ + TRACE_OBJ + if (e->key() == Qt::Key_Escape) + emit escapePressed(); +} + +bool ContentWindow::eventFilter(QObject *o, QEvent *e) +{ + TRACE_OBJ + if (m_contentWidget && o == m_contentWidget->viewport() + && e->type() == QEvent::MouseButtonRelease) { + QMouseEvent *me = static_cast(e); + const QModelIndex &index = m_contentWidget->indexAt(me->pos()); + if (!index.isValid()) + return QWidget::eventFilter(o, e); + + const Qt::MouseButtons button = me->button(); + QItemSelectionModel *sm = m_contentWidget->selectionModel(); + if (sm->isSelected(index)) { + if ((button == Qt::LeftButton && (me->modifiers() & Qt::ControlModifier)) + || (button == Qt::MidButton)) { + QHelpContentModel *contentModel = + qobject_cast(m_contentWidget->model()); + if (contentModel) { + QHelpContentItem *itm = contentModel->contentItemAt(index); + if (itm && HelpViewer::canOpenPage(itm->url().path())) + OpenPagesManager::instance()->createPage(itm->url()); + } + } else if (button == Qt::LeftButton) { + itemClicked(index); + } + } + } + return QWidget::eventFilter(o, e); +} + + +void ContentWindow::showContextMenu(const QPoint &pos) +{ + TRACE_OBJ + if (!m_contentWidget->indexAt(pos).isValid()) + return; + + QHelpContentModel *contentModel = + qobject_cast(m_contentWidget->model()); + QHelpContentItem *itm = + contentModel->contentItemAt(m_contentWidget->currentIndex()); + + QMenu menu; + QAction *curTab = menu.addAction(tr("Open Link")); + QAction *newTab = menu.addAction(tr("Open Link in New Tab")); + if (!HelpViewer::canOpenPage(itm->url().path())) + newTab->setEnabled(false); + + menu.move(m_contentWidget->mapToGlobal(pos)); + + QAction *action = menu.exec(); + if (curTab == action) + emit linkActivated(itm->url()); + else if (newTab == action) + OpenPagesManager::instance()->createPage(itm->url()); +} + +void ContentWindow::itemClicked(const QModelIndex &index) +{ + TRACE_OBJ + QHelpContentModel *contentModel = + qobject_cast(m_contentWidget->model()); + + if (contentModel) { + if (QHelpContentItem *itm = contentModel->contentItemAt(index)) { + const QUrl &url = itm->url(); + if (url != CentralWidget::instance()->currentSource()) + emit linkActivated(url); + } + } +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/contentwindow.h b/src/assistant/tools/assistant/contentwindow.h new file mode 100644 index 000000000..b8bdc8fee --- /dev/null +++ b/src/assistant/tools/assistant/contentwindow.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CONTENTWINDOW_H +#define CONTENTWINDOW_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QHelpEngine; +class QHelpContentItem; +class QHelpContentWidget; + +class ContentWindow : public QWidget +{ + Q_OBJECT + +public: + ContentWindow(); + ~ContentWindow(); + + bool syncToContent(const QUrl &url); + void expandToDepth(int depth); + +signals: + void linkActivated(const QUrl &link); + void escapePressed(); + +private slots: + void showContextMenu(const QPoint &pos); + void expandTOC(); + void itemClicked(const QModelIndex &index); + +private: + void focusInEvent(QFocusEvent *e); + void keyPressEvent(QKeyEvent *e); + bool eventFilter(QObject *o, QEvent *e); + + QHelpContentWidget * const m_contentWidget; + int m_expandDepth; +}; + +QT_END_NAMESPACE + +#endif // CONTENTWINDOW_H diff --git a/src/assistant/tools/assistant/doc/HOWTO b/src/assistant/tools/assistant/doc/HOWTO new file mode 100644 index 000000000..a0143479e --- /dev/null +++ b/src/assistant/tools/assistant/doc/HOWTO @@ -0,0 +1,16 @@ +How to build/ update a new assistant.qch for Assistant internal help + +- update: + - open assistant.qdocconf, update year and qt version + + - ..\..\..\..\qdoc3\debug\qdoc3.exe assistant.qdocconf + will generate an folder html containing all required stuff + + - cp assistant.qhp to generated html folder + - run qhelpgenerator html\assistant.qhp -o ..\assistant.qch + + - rebuild assistant + +- to test your changes: + - remove assistant.qch in your cache directory + - restart assistant diff --git a/src/assistant/tools/assistant/doc/assistant.qdoc b/src/assistant/tools/assistant/doc/assistant.qdoc new file mode 100644 index 000000000..8bd7432ec --- /dev/null +++ b/src/assistant/tools/assistant/doc/assistant.qdoc @@ -0,0 +1,461 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page assistant.html + \title Qt Assistant + + \chapter Introduction + + This document introduces \e{Qt Assistant}, a tool for presenting on-line + documentation. It also introduces the Qt Reference Documentation which + is accessible using \e{Qt Assistant}, or with a web browser. The document is + divided into the following sections: + + Table of contents: + + \list + \o \l{Introduction} + \o \l{The One-Minute Guide to Using Qt Assistant} + \o \l{Introduction to the Qt Reference Documentation} + \o \l{Qt Assistant in More Detail} + \o \l{Full Text Searching} + \endlist + + \chapter The One-Minute Guide to Using Qt Assistant + + Once you have installed Qt, \QA should be ready to run: + + \list + \o On Windows, \QA is available as a menu option on the Qt menu. + \o On Mac OS X, \QA is installed in the /Developer/Applications/Qt directory. + \o On Unix/Linux, open a terminal, type \c{assistant} and press \key{Enter}. + \endlist + + When you start up \QA, you will be presented with a standard main window + application, with a menu bar and toolbar. Below these, on the left hand + side are navigation windows called \e{Contents}, \e{Index} and \e{Bookmarks}. + On the right, taking up most of the space, is the \e{Documentation} window. + By default, \QA loads the Qt reference documentation along with the manuals + of other Qt tools, like \QD or \QL. + + \QA works in a similar way to a Web browser. If you click hyperlinks + (cross-references), the \e{Documentation} window will present the relevant + page. You can bookmark pages of particular interest and you can click the + \gui{Previous} and \gui{Next} toolbar buttons to navigate within the pages + you have visited. + + Although \QA can be used just like a Web browser to navigate through + the documentation, \QA offers a powerful means of navigation that Web + browsers do not provide. \QA uses an advanced full text search engine + to index all the pages in each compressed help file so that you can + search for particular words and phrases. + + To perform an index search, click the \gui{Index} tab on the Sidebar + (or press \key{Alt+I}). In the \gui{'Look For'} line edit enter a word; + e.g., 'homedirpath'. As you type, words are found and highlighted in a list + beneath the line edit. If the highlighted text matches what you're + looking for, double click it, (or press \key{Enter}) and the + \e{Documentation} window will display the relevant page. You rarely have + to type in the whole word before \QA finds a match. Note that for some + words there may be more than one possible page that is relevant. + + \QA also provides full text searching for finding specific words in + the documentation. To activate the full text search, either press \key(Alt+S) + or click on the \gui{Search} tab in the \e{Documentation} window. Then + enter the term you're looking for and hit the \gui{Search} button. All + documents containing the specified term will then be listed in the list box + below. + + \chapter Introduction to the Qt Reference Documentation + + The documentation for the Qt library is written in-line in the \c + .cpp files by the developers themselves. The documentation team + revises the documentation to ensure that it is accurate and usable, + and to provide quality control. The documentation team also writes the + larger texts, such as the class descriptions that introduce a class + along with the concepts the class uses, as well as introducing the + functions and properties that the class provides. + + The documentation focuses on the API rather than the internals, since + we make great efforts to keep our API consistent and compatible with + each new version, but we may change the internals considerably to improve + performance and enhance functionality. + + The Qt Reference Documentation consists of almost 1,500 HTML pages + (over 2,500 printed pages). The overwhelming majority of pages + document Qt classes. Since developers differ in the way they + think and work we provide a variety of approaches to navigating the + documentation set: + + \list + \i The \menu{Qt's Classes} page lists every class + in Qt's public API, and consists of several hundred classes. + \i The \menu{Qt's Main Classes} page lists the + classes you're most likely to use most often, and provides a much + shorter and more managable list than the All Classes list. + \i The \menu{Grouped Classes} page presents a list + of groups, each of which leads to a list of related classes, for + example, the \menu{Advanced Widgets} list. + \i The \menu{Class Inheritance Hierarchy} page + presents a list of classes in terms of the hierarchy of Qt classes. + \i The \menu{Member Function Index} page lists all the + functions provided by Qt classes, each one with links to the class(es) + in which it appears. + \endlist + + No matter where you find yourself in the Qt documentation, you will + find extensive cross-referencing. Even snippets of example code + contain clickable links, so that for example, if you come across a + class declaration in a code example, the class name will be a + clickable link to the class's documentation. + + In addition to the class documentation some of Qt's modules have + extensive descriptions, and there are many overview documents which + describe various aspects of the Qt library; all these are linked from + the reference documentation home page. There are also two tutorials + and numerous example programs in the examples subdirectory of the Qt + distribution. + + \chapter Qt Assistant in More Detail + + \img assistant-assistant.png + + \section1 Command Line Options + + \QA handles the following command line options: + + \table + \header + \o Command Line Option + \o Brief Description + \row + \o -collectionFile + \o Uses the specified collection file instead of the default one. + \row + \o -showUrl URL + \o Shows the document referenced by URL. + \row + \o -enableRemoteControl + \o Enables \QA to be remotly controlled. + \row + \o -show + \o Shows the specified dockwidget which can be "contents", "index", + "bookmarks" or "search". + \row + \o -hide + \o Hides the specified dockwidget which can be "contents", "index", + "bookmarks" or "search. + \row + \o -activate + \o Activates the specified dockwidget which can be "contents", + "index", "bookmarks" or "search. + \row + \o -register + \o Registers the specified compressed help file in the given help + collection. + \row + \o -unregister + \o Unregisters the specified compressed help file from the given + collection file. + \row + \o -quiet + \o Doesn't show any error, warning or success messages. + \endtable + + \section1 Tool Windows + + \img assistant-dockwidgets.png + + The tool windows provide four ways to navigate the documentation: + + \list + \o The \gui{Contents} window presents a table of contents implemented as a + tree view for the documentation that is available. If you click an item, + its documentation will appear in the \e{Documentation} window. If you double + click an item or click on the control to the left of it, the item's sub-items + will appear. Click a sub-item to make its page appear in the \e{Documentation} + window. Click on the control next to an open item to hide its sub-items. + \o The \gui{Index} window is used to look up key words or phrases. + See \l{The One-Minute Guide to Using Qt Assistant} for how to use this + window. + \o The \gui{Bookmarks} window lists any bookmarks you have made. Double + click a bookmark to make its page appear in the \e{Documentation} window. + The \gui{Bookmarks} window provides a context menu with \gui{Show Item}, + \gui{Delete Item} as well as \gui{Rename Item}. Click in the main menu + \menu{Bookmark|Add Bookmark...} (or press \key{Ctrl+B}) to bookmark the + page that is currently showing in the \e{Documentation} window. Right click + a bookmark in the list to rename or delete the highlighted bookmark. + \endlist + + If you want the \gui{Documentation} window to use as much space as possible, + you can easily group, move or hide the tool windows. To group the windows, + drag one on top of the other and release the mouse. If one or all tool + windows are not shown, press \key{Alt+C}, \key{Alt+I} or \key{Alt+O} to show + the required window. + + The tool windows can be docked into the main window, so you can drag them + to the top, left, right or bottom of \e{Qt Assistant's} window, or you can + drag them outside \QA to float them as independent windows. + + \section1 Documentation Window + + \img assistant-docwindow.png + + The \gui{Documentation} window lets you create a tab for each + documentation page that you view. Click the \gui{Add Tab} button and a new + tab will appear with the page name as the tab's caption. This makes it + convenient to switch between pages when you are working with different + documentation. You can delete a tab by clicking the \gui{Close Tab} button + located on the right side of the \gui{Documentation} window. + + \section1 Toolbars + + \img assistant-toolbar.png + + The main toolbar provides fast access to the most common actions. + + \table + \header \o Action \o Description \o Menu Item \o Shortcut + \row \o \gui{Previous} \o Takes you to the previous page in the history. + \o \menu{Go|Previous} \o \key{Alt+Left Arrow} + \row \o \gui{Next} \o Takes you to the next page in the history. + \o \menu{Go|Next} \o \key{Alt+Right Arrow} + \row \o \gui{Home} + \o Takes you to the home page as specified in the Preferences Dialog. + \o \menu{Go|Home} \o \key{Ctrl+Home}. + \row \o \gui{Sync with Table of Contents} + \o Synchronizes the \gui{Contents} tool window with the page currently + shown in the \gui{Documentation} window. + \o \menu{Go|Sync with Table of Contents} \o + \row \o \gui{Copy} \o Copies any selected text to the clipboard. + \o \menu{Edit|Copy} \o \key{Ctrl+C} + \row \o \gui{Print} \o Opens the \gui{Print} dialog. + \o \menu{File|Print} \o \key{Ctrl+P} + \row \o \gui{Find in Text} \o Opens the \gui{Find Text} dialog. + \o \menu{Edit|Find in Text} \o \key{Ctrl+F} + \row \o \gui{Zoom in} + \o Increases the font size used to display text in the current tab. + \o \menu{View|Zoom in} \o \key{Ctrl++} + \row \o \gui{Zoom out} + \o Decreases the font size used to display text in the current tab. + \o \menu{View|Zoom out} \o \key{Ctrl+-} + \row \o \gui{Normal Size} + \o Resets the font size to its normal size in the current tab. + \o \menu{View|Normal Size} \o \key{Ctrl+0} + \endtable + + \img assistant-address-toolbar.png + + The address toolbar provides a fast way to enter a specific URL for a + documentation file. By default, the address toolbar is not shown, so it + has to be activated via \menu{View|Toolbars|Address Toolbar}. + + \img assistant-filter-toolbar.png + + The filter toolbar allows you to apply a filter to the currently installed + documentation. As with the address toolbar, the filter toolbar is not visible + by default and has to be activated via \menu{View|Toolbars|Filter Toolbar}. + + \section1 Menus + + \section2 File Menu + + \list + \o \menu{File|Page Setup...} invokes a dialog allowing you to define + page layout properties, such as margin sizes, page orientation and paper size. + \o \menu{File|Print Preview...} provides a preview of the printed pages. + \o \menu{File|Print...} opens the \l{#Print Dialog}{\gui{Print} dialog}. + \o \menu{File|New Tab} opens a new empty tab in the \gui{Documentation} + window. + \o \menu{File|Close Tab} closes the current tab of the + \gui{Documentation} window. + \o \menu{File|Exit} closes the \QA application. + \endlist + + \section2 Edit Menu + + \list + \o \menu{Edit|Copy} copies any selected text to the clipboard. + \o \menu{Edit|Find in Text} invokes the \l{#Find Text Control}{\gui{Find Text} + control} at the lower end of the \gui{Documentation} window. + \o \menu{Edit|Find Next} looks for the next occurance of the specified + text in the \gui{Find Text} control. + \o \menu{Edit|Find Previous} looks for the previous occurance of + the specified text in the \l{#Find Text Control}{\gui{Find Text} control}. + \o \menu{Edit|Preferences} invokes the \l{#Preferences Dialog}{\gui{Preferences} dialog}. + \endlist + + \section2 View Menu + + \list + \o \menu{View|Zoom in} increases the font size in the current tab. + \o \menu{View|Zoom out} decreases the font size in the current tab. + \o \menu{View|Normal Size} resets the font size in the current tab. + \o \menu{View|Contents} toggles the display of the \gui{Contents} tool window. + \o \menu{View|Index} toggles the display of the \gui{Index} tool window. + \o \menu{View|Bookmarks} toggles the display of the \gui{Bookmarks} tool window. + \o \menu{View|Search} toggles the display of the Search in the \gui{Documentation} window. + \endlist + + \section2 Go Menu + + \list + \o \menu{Go|Home} goes to the home page. + \o \menu{Go|Back} displays the previous page in the history. + \o \menu{Go|Forward} displays the next page in the history. + \o \menu{Go|Sync with Table of Contents} syncs the \gui{Contents} tool window to the currently shown page. + \o \menu{Go|Next Page} selects the next tab in the \gui{Documentation} window. + \o \menu{Go|Previous Page} selects the previous tab in the \gui{Documentation} window. + \endlist + + \section2 Bookmarks Menu + + \list + \o \menu{Bookmarks|Add} adds the current page to the list of bookmarks. + \endlist + + \section1 Dialogs + + \section2 Print Dialog + + This dialog is platform-specific. It gives access to various printer + options and can be used to print the document shown in the current tab. + + \section2 Preferences Dialog + + \img assistant-preferences-fonts.png + + The \menu{Fonts} page allows you to change the font family and font sizes of the + browser window displaying the documentation or the application itself. + + \img assistant-preferences-filters.png + + The \menu{Filters} page lets you create and remove documentation + filters. To add a new filter, click the \gui{Add} button, specify a + filter name in the pop-up dialog and click \gui{OK}, then select + the filter attributes in the list box on the right hand side. + You can delete a filter by selecting it and clicking the \gui{Remove} + button. + + \img assistant-preferences-documentation.png + + The \menu{Documentation} page lets you install and remove compressed help + files. Click the \gui{Install} button and choose the path of the compressed + help file (*.qch) you would like to install. + To delete a help file, select a documentation set in the list and click + \gui{Remove}. + + \img assistant-preferences-options.png + + The \menu{Options} page lets you specify the homepage \QA will display when + you click the \gui{Home} button in \QA's main user interface. You can specify + the hompage by typing it here or clicking on one of the buttons below the + textbox. \gui{Current Page} sets the currently displayed page as your home + page while \gui{Restore to default} will reset your home page to the default + home page. + + \section1 Find Text Control + + This control is used to find text in the current page. Enter the text you want + to find in the line edit. The search is incremental, meaning that the most + relevant result is shown as you enter characters into the line edit. + + If you check the \gui{Whole words only} checkbox, the search will only consider + whole words; for example, if you search for "spin" with this checkbox checked it will + not match "spinbox", but will match "spin". If you check the \gui{Case sensitive} + checkbox then, for example, "spin" will match "spin" but not "Spin". You can + search forwards or backwards from your current position in the page by clicking + the \gui{Previous} or \gui{Next} buttons. To hide the find control, either click the + \gui{Close} button or hit the \key{Esc} key. + + \section1 Filtering Help Contents + + \QA allows you to install any kind of documentation as long as it is organized + in Qt compressed help files (*.qch). For example, it is possible to install the + Qt reference documentation for Qt 4.4.0 and Qt 4.4.1 at the same time. In many + respects, this is very convenient since only one version of \QA is needed. + However, at the same time it becomes more complicated when performing tasks like + searching the index because nearly every keyword is defined in Qt 4.4.0 as well + as in Qt 4.4.1. This means that \QA will always ask the user to choose which one + should be displayed. + + We use documentation filters to solve this issue. A filter is identified by its + name, and contains a list of filter attributes. An attribute is just a string and + can be freely chosen. Attributes are defined by the documentation itself, this + means that every documentation set usually has one or more attributes. + + For example, the Qt 4.4.0 \QA documentation defines the attributes \c {assistant}, + \c{tools} and \c{4.4.0}, \QD defines \c{designer}, \c{tools} and \c{4.4.0}. + The filter to display all tools would then define only the attribute + \c{tools} since this attribute is part of both documentation sets. + Adding the attribute \c{assistant} to the filter would then only show \QA + documentation since the \QD documentation does not contain this + attribute. Having an empty list of attributes in a filter will match all + documentation; i.e., it is equivalent to requesting unfiltered documentation. + + \section1 Full Text Searching + + \img assistant-search.png + + \QA provides a powerful full text search engine. To search + for certain words or text, click the \gui{Search} tab in the \gui{Documentation} + window. Then enter the text you want to look for and press \key{Enter} + or click the \gui{Search} button. The search is not case sensitive, so, + for example, Foo, fOo and FOO are all treated as the same. The following are + examples of common search patterns: + + \list + \o \c deep -- lists all the documents that contain the word 'deep' + \o \c{deep*} -- lists all the documents that contain a word beginning + with 'deep' + \o \c{deep copy} -- lists all documents that contain both 'deep' \e + and 'copy' + \o \c{"deep copy"} -- list all documents that contain the phrase 'deep copy' + \endlist + + It is also possible to use the \gui{Advanced search} to get more flexibility. + You can specify some words so that hits containing these are excluded from the + result, or you can search for an exact phrase. Searching for similar words will + give results like these: + + \list + \o \c{QStin} -- lists all the documents with titles that are similar, such as \c{QString} + \o \c{QSting} -- lists all the documents with titles that are similar, such as \c{QString} + \o \c{QStrin} -- lists all the documents with titles that are similar, such as \c{QString} + \endlist + + Options can be combined to improve the search results. + + The list of documents found is ordered according to the number of + occurrences of the search text which they contain, with those containing + the highest number of occurrences appearing first. Simply click any + document in the list to display it in the \gui{Documentation} window. + + If the documentation has changed \mdash for example, if documents have been added + or removed \mdash \QA will index them again. +*/ diff --git a/src/assistant/tools/assistant/doc/assistant.qdocconf b/src/assistant/tools/assistant/doc/assistant.qdocconf new file mode 100644 index 000000000..4bd3842d6 --- /dev/null +++ b/src/assistant/tools/assistant/doc/assistant.qdocconf @@ -0,0 +1,16 @@ +include(../../../../qdoc3/test/qt.qdocconf) + +version = + +sourcedirs = $QTDIR/tools/assistant/tools/assistant/doc +imagedirs = $QTDIR/tools/assistant/tools/assistant/doc/images +outputdir = $QTDIR/tools/assistant/tools/assistant/doc/html +project = assistant +description = "Qt Assistant" +HTML.{postheader,address} = "" +HTML.footer = "


\n" \ + "\n" \ + "\n" \ + "\n" \ + "\n" \ + "
Copyright © 2011 Nokia Corporation and/or its subsidiary(-ies)Trademarks
Qt 4.8.0
" diff --git a/src/assistant/tools/assistant/doc/assistant.qhp b/src/assistant/tools/assistant/doc/assistant.qhp new file mode 100644 index 000000000..7ea4cdd46 --- /dev/null +++ b/src/assistant/tools/assistant/doc/assistant.qhp @@ -0,0 +1,22 @@ + + + assistant + com.trolltech.com.assistantinternal-1.0.0 + + + assistant.html + classic.css + images/assistant-address-toolbar.png + images/assistant-assistant.png + images/assistant-dockwidgets.png + images/assistant-docwindow.png + images/assistant-filter-toolbar.png + images/assistant-preferences-documentation.png + images/assistant-preferences-filters.png + images/assistant-preferences-fonts.png + images/assistant-preferences-options.png + images/assistant-search.png + images/assistant-toolbar.png + + + diff --git a/src/assistant/tools/assistant/doc/classic.css b/src/assistant/tools/assistant/doc/classic.css new file mode 100644 index 000000000..911354035 --- /dev/null +++ b/src/assistant/tools/assistant/doc/classic.css @@ -0,0 +1,92 @@ +h3.fn,span.fn +{ + margin-left: 1cm; + text-indent: -1cm; +} + +a:link +{ + color: #004faf; + text-decoration: none +} + +a:visited +{ + color: #672967; + text-decoration: none +} + +td.postheader +{ + font-family: sans-serif +} + +tr.address +{ + font-family: sans-serif +} + +body +{ + background: #ffffff; + color: black +} + +table tr.odd { + background: #f0f0f0; + color: black; +} + +table tr.even { + background: #e4e4e4; + color: black; +} + +table.annotated th { + padding: 3px; + text-align: left +} + +table.annotated td { + padding: 3px; +} + +table tr pre +{ + padding-top: none; + padding-bottom: none; + padding-left: none; + padding-right: none; + border: none; + background: none +} + +tr.qt-style +{ + background: #a2c511; + color: black +} + +body pre +{ + padding: 0.2em; + border: #e7e7e7 1px solid; + background: #f1f1f1; + color: black +} + +span.preprocessor, span.preprocessor a +{ + color: darkblue; +} + +span.comment +{ + color: darkred; + font-style: italic +} + +span.string,span.char +{ + color: darkgreen; +} diff --git a/src/assistant/tools/assistant/doc/images/assistant-address-toolbar.png b/src/assistant/tools/assistant/doc/images/assistant-address-toolbar.png new file mode 100644 index 000000000..847b7debb Binary files /dev/null and b/src/assistant/tools/assistant/doc/images/assistant-address-toolbar.png differ diff --git a/src/assistant/tools/assistant/doc/images/assistant-assistant.png b/src/assistant/tools/assistant/doc/images/assistant-assistant.png new file mode 100644 index 000000000..1ff5cc976 Binary files /dev/null and b/src/assistant/tools/assistant/doc/images/assistant-assistant.png differ diff --git a/src/assistant/tools/assistant/doc/images/assistant-dockwidgets.png b/src/assistant/tools/assistant/doc/images/assistant-dockwidgets.png new file mode 100644 index 000000000..17bc064c5 Binary files /dev/null and b/src/assistant/tools/assistant/doc/images/assistant-dockwidgets.png differ diff --git a/src/assistant/tools/assistant/doc/images/assistant-docwindow.png b/src/assistant/tools/assistant/doc/images/assistant-docwindow.png new file mode 100644 index 000000000..c5bac581f Binary files /dev/null and b/src/assistant/tools/assistant/doc/images/assistant-docwindow.png differ diff --git a/src/assistant/tools/assistant/doc/images/assistant-examples.png b/src/assistant/tools/assistant/doc/images/assistant-examples.png new file mode 100644 index 000000000..47c01bcda Binary files /dev/null and b/src/assistant/tools/assistant/doc/images/assistant-examples.png differ diff --git a/src/assistant/tools/assistant/doc/images/assistant-filter-toolbar.png b/src/assistant/tools/assistant/doc/images/assistant-filter-toolbar.png new file mode 100644 index 000000000..4e89a79b9 Binary files /dev/null and b/src/assistant/tools/assistant/doc/images/assistant-filter-toolbar.png differ diff --git a/src/assistant/tools/assistant/doc/images/assistant-preferences-documentation.png b/src/assistant/tools/assistant/doc/images/assistant-preferences-documentation.png new file mode 100644 index 000000000..790fd9a1a Binary files /dev/null and b/src/assistant/tools/assistant/doc/images/assistant-preferences-documentation.png differ diff --git a/src/assistant/tools/assistant/doc/images/assistant-preferences-filters.png b/src/assistant/tools/assistant/doc/images/assistant-preferences-filters.png new file mode 100644 index 000000000..7453dd66d Binary files /dev/null and b/src/assistant/tools/assistant/doc/images/assistant-preferences-filters.png differ diff --git a/src/assistant/tools/assistant/doc/images/assistant-preferences-fonts.png b/src/assistant/tools/assistant/doc/images/assistant-preferences-fonts.png new file mode 100644 index 000000000..d42d190d0 Binary files /dev/null and b/src/assistant/tools/assistant/doc/images/assistant-preferences-fonts.png differ diff --git a/src/assistant/tools/assistant/doc/images/assistant-preferences-options.png b/src/assistant/tools/assistant/doc/images/assistant-preferences-options.png new file mode 100644 index 000000000..d6624151a Binary files /dev/null and b/src/assistant/tools/assistant/doc/images/assistant-preferences-options.png differ diff --git a/src/assistant/tools/assistant/doc/images/assistant-search.png b/src/assistant/tools/assistant/doc/images/assistant-search.png new file mode 100644 index 000000000..ef75c3329 Binary files /dev/null and b/src/assistant/tools/assistant/doc/images/assistant-search.png differ diff --git a/src/assistant/tools/assistant/doc/images/assistant-toolbar.png b/src/assistant/tools/assistant/doc/images/assistant-toolbar.png new file mode 100644 index 000000000..1b41825c6 Binary files /dev/null and b/src/assistant/tools/assistant/doc/images/assistant-toolbar.png differ diff --git a/src/assistant/tools/assistant/filternamedialog.cpp b/src/assistant/tools/assistant/filternamedialog.cpp new file mode 100644 index 000000000..1d9563d2f --- /dev/null +++ b/src/assistant/tools/assistant/filternamedialog.cpp @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "tracer.h" + +#include + +#include "filternamedialog.h" + +QT_BEGIN_NAMESPACE + +FilterNameDialog::FilterNameDialog(QWidget *parent) + : QDialog(parent) +{ + TRACE_OBJ + m_ui.setupUi(this); + connect(m_ui.buttonBox->button(QDialogButtonBox::Ok), + SIGNAL(clicked()), this, SLOT(accept())); + connect(m_ui.buttonBox->button(QDialogButtonBox::Cancel), + SIGNAL(clicked()), this, SLOT(reject())); + connect(m_ui.lineEdit, SIGNAL(textChanged(QString)), + this, SLOT(updateOkButton())); + m_ui.buttonBox->button(QDialogButtonBox::Ok)->setDisabled(true); + +} + +QString FilterNameDialog::filterName() const +{ + TRACE_OBJ + return m_ui.lineEdit->text(); +} + +void FilterNameDialog::updateOkButton() +{ + TRACE_OBJ + m_ui.buttonBox->button(QDialogButtonBox::Ok) + ->setDisabled(m_ui.lineEdit->text().isEmpty()); +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/filternamedialog.h b/src/assistant/tools/assistant/filternamedialog.h new file mode 100644 index 000000000..35575421e --- /dev/null +++ b/src/assistant/tools/assistant/filternamedialog.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FILTERNAMEDIALOG_H +#define FILTERNAMEDIALOG_H + +#include +#include "ui_filternamedialog.h" + +QT_BEGIN_NAMESPACE + +class FilterNameDialog : public QDialog +{ + Q_OBJECT + +public: + FilterNameDialog(QWidget *parent = 0); + QString filterName() const; + +private slots: + void updateOkButton(); + +private: + Ui::FilterNameDialogClass m_ui; +}; + +QT_END_NAMESPACE + +#endif // FILTERNAMEDIALOG_H diff --git a/src/assistant/tools/assistant/filternamedialog.ui b/src/assistant/tools/assistant/filternamedialog.ui new file mode 100644 index 000000000..755a93479 --- /dev/null +++ b/src/assistant/tools/assistant/filternamedialog.ui @@ -0,0 +1,67 @@ + + FilterNameDialogClass + + + + 0 + 0 + 312 + 95 + + + + Add Filter Name + + + + 9 + + + 6 + + + + + Filter Name: + + + + + + + + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok + + + + + + + + + diff --git a/src/assistant/tools/assistant/findwidget.cpp b/src/assistant/tools/assistant/findwidget.cpp new file mode 100644 index 000000000..d45ed30b0 --- /dev/null +++ b/src/assistant/tools/assistant/findwidget.cpp @@ -0,0 +1,234 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "tracer.h" +#include "findwidget.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +FindWidget::FindWidget(QWidget *parent) + : QWidget(parent) + , appPalette(qApp->palette()) +{ + TRACE_OBJ + installEventFilter(this); + QHBoxLayout *hboxLayout = new QHBoxLayout(this); + QString resourcePath = QLatin1String(":/trolltech/assistant/images/"); + +#ifndef Q_OS_MAC + hboxLayout->setMargin(0); + hboxLayout->setSpacing(6); + resourcePath.append(QLatin1String("win")); +#else + resourcePath.append(QLatin1String("mac")); +#endif + + toolClose = setupToolButton(QLatin1String(""), + resourcePath + QLatin1String("/closetab.png")); + hboxLayout->addWidget(toolClose); + connect(toolClose, SIGNAL(clicked()), SLOT(hide())); + + editFind = new QLineEdit(this); + hboxLayout->addWidget(editFind); + editFind->setMinimumSize(QSize(150, 0)); + connect(editFind, SIGNAL(textChanged(QString)), this, + SLOT(textChanged(QString))); + connect(editFind, SIGNAL(returnPressed()), this, SIGNAL(findNext())); + connect(editFind, SIGNAL(textChanged(QString)), this, SLOT(updateButtons())); + + toolPrevious = setupToolButton(tr("Previous"), + resourcePath + QLatin1String("/previous.png")); + connect(toolPrevious, SIGNAL(clicked()), this, SIGNAL(findPrevious())); + + hboxLayout->addWidget(toolPrevious); + + toolNext = setupToolButton(tr("Next"), + resourcePath + QLatin1String("/next.png")); + hboxLayout->addWidget(toolNext); + connect(toolNext, SIGNAL(clicked()), this, SIGNAL(findNext())); + + checkCase = new QCheckBox(tr("Case Sensitive"), this); + hboxLayout->addWidget(checkCase); + + labelWrapped = new QLabel(this); + labelWrapped->setScaledContents(true); + labelWrapped->setTextFormat(Qt::RichText); + labelWrapped->setMinimumSize(QSize(0, 20)); + labelWrapped->setMaximumSize(QSize(105, 20)); + labelWrapped->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter); + labelWrapped->setText(tr(" Search wrapped")); + hboxLayout->addWidget(labelWrapped); + + QSpacerItem *spacerItem = new QSpacerItem(20, 20, QSizePolicy::Expanding, + QSizePolicy::Minimum); + hboxLayout->addItem(spacerItem); + setMinimumWidth(minimumSizeHint().width()); + labelWrapped->hide(); + + updateButtons(); +} + +FindWidget::~FindWidget() +{ + TRACE_OBJ +} + +void FindWidget::show() +{ + TRACE_OBJ + QWidget::show(); + editFind->selectAll(); + editFind->setFocus(Qt::ShortcutFocusReason); +} + +void FindWidget::showAndClear() +{ + TRACE_OBJ + show(); + editFind->clear(); +} + +QString FindWidget::text() const +{ + TRACE_OBJ + return editFind->text(); +} + +bool FindWidget::caseSensitive() const +{ + TRACE_OBJ + return checkCase->isChecked(); +} + +void FindWidget::setPalette(bool found) +{ + TRACE_OBJ + QPalette palette = editFind->palette(); + palette.setColor(QPalette::Active, QPalette::Base, found ? Qt::white + : QColor(255, 102, 102)); + editFind->setPalette(palette); +} + +void FindWidget::setTextWrappedVisible(bool visible) +{ + TRACE_OBJ + labelWrapped->setVisible(visible); +} + +void FindWidget::hideEvent(QHideEvent* event) +{ + TRACE_OBJ +#if !defined(QT_NO_WEBKIT) + // TODO: remove this once webkit supports setting the palette + if (!event->spontaneous()) + qApp->setPalette(appPalette); +#else + Q_UNUSED(event); +#endif +} + +void FindWidget::showEvent(QShowEvent* event) +{ + TRACE_OBJ +#if !defined(QT_NO_WEBKIT) + // TODO: remove this once webkit supports setting the palette + if (!event->spontaneous()) { + QPalette p = appPalette; + p.setColor(QPalette::Inactive, QPalette::Highlight, + p.color(QPalette::Active, QPalette::Highlight)); + p.setColor(QPalette::Inactive, QPalette::HighlightedText, + p.color(QPalette::Active, QPalette::HighlightedText)); + qApp->setPalette(p); + } +#else + Q_UNUSED(event); +#endif +} + +void FindWidget::updateButtons() +{ + TRACE_OBJ + const bool enable = !editFind->text().isEmpty(); + toolNext->setEnabled(enable); + toolPrevious->setEnabled(enable); +} + +void FindWidget::textChanged(const QString &text) +{ + TRACE_OBJ + emit find(text, true, true); +} + +bool FindWidget::eventFilter(QObject *object, QEvent *e) +{ + TRACE_OBJ + if (e->type() == QEvent::KeyPress) { + if ((static_cast(e))->key() == Qt::Key_Escape) { + hide(); + emit escapePressed(); + } + } + return QWidget::eventFilter(object, e); +} + +QToolButton* FindWidget::setupToolButton(const QString &text, const QString &icon) +{ + TRACE_OBJ + QToolButton *toolButton = new QToolButton(this); + + toolButton->setText(text); + toolButton->setAutoRaise(true); + toolButton->setIcon(QIcon(icon)); + toolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + + return toolButton; +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/findwidget.h b/src/assistant/tools/assistant/findwidget.h new file mode 100644 index 000000000..d3be0f587 --- /dev/null +++ b/src/assistant/tools/assistant/findwidget.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef FINDWIDGET_H +#define FINDWIDGET_H + +#include + +QT_BEGIN_NAMESPACE + +class QCheckBox; +class QLabel; +class QLineEdit; +class QToolButton; + +class FindWidget : public QWidget +{ + Q_OBJECT +public: + FindWidget(QWidget *parent = 0); + ~FindWidget(); + + void show(); + void showAndClear(); + + QString text() const; + bool caseSensitive() const; + + void setPalette(bool found); + void setTextWrappedVisible(bool visible); + +signals: + void findNext(); + void findPrevious(); + void escapePressed(); + void find(const QString &text, bool forward, bool incremental); + +protected: + void hideEvent(QHideEvent* event); + void showEvent(QShowEvent * event); + +private slots: + void updateButtons(); + void textChanged(const QString &text); + +private: + bool eventFilter(QObject *object, QEvent *e); + QToolButton* setupToolButton(const QString &text, const QString &icon); + +private: + QPalette appPalette; + + QLineEdit *editFind; + QCheckBox *checkCase; + QLabel *labelWrapped; + QToolButton *toolNext; + QToolButton *toolClose; + QToolButton *toolPrevious; +}; + +QT_END_NAMESPACE + +#endif // FINDWIDGET_H diff --git a/src/assistant/tools/assistant/globalactions.cpp b/src/assistant/tools/assistant/globalactions.cpp new file mode 100644 index 000000000..7fc59ebcd --- /dev/null +++ b/src/assistant/tools/assistant/globalactions.cpp @@ -0,0 +1,246 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Assistant module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "globalactions.h" + +#include "centralwidget.h" +#include "helpviewer.h" +#include "tracer.h" + +#include +#include + +#if !defined(QT_NO_WEBKIT) +#include +#endif + +GlobalActions *GlobalActions::instance(QObject *parent) +{ + Q_ASSERT(!m_instance != !parent); + if (!m_instance) + m_instance = new GlobalActions(parent); + return m_instance; +} + +GlobalActions::GlobalActions(QObject *parent) : QObject(parent) +{ + TRACE_OBJ + + // TODO: Put resource path in misc class + QString resourcePath = QLatin1String(":/trolltech/assistant/images/"); +#ifdef Q_OS_MAC + resourcePath.append(QLatin1String("mac")); +#else + resourcePath.append(QLatin1String("win")); +#endif + CentralWidget *centralWidget = CentralWidget::instance(); + + m_backAction = new QAction(tr("&Back"), parent); + m_backAction->setEnabled(false); + m_backAction->setShortcuts(QKeySequence::Back); + m_backAction->setIcon(QIcon(resourcePath + QLatin1String("/previous.png"))); + connect(m_backAction, SIGNAL(triggered()), centralWidget, SLOT(backward())); + m_actionList << m_backAction; + + m_nextAction = new QAction(tr("&Forward"), parent); + m_nextAction->setPriority(QAction::LowPriority); + m_nextAction->setEnabled(false); + m_nextAction->setShortcuts(QKeySequence::Forward); + m_nextAction->setIcon(QIcon(resourcePath + QLatin1String("/next.png"))); + connect(m_nextAction, SIGNAL(triggered()), centralWidget, SLOT(forward())); + m_actionList << m_nextAction; + + setupNavigationMenus(m_backAction, m_nextAction, centralWidget); + + m_homeAction = new QAction(tr("&Home"), parent); + m_homeAction->setShortcut(tr("ALT+Home")); + m_homeAction->setIcon(QIcon(resourcePath + QLatin1String("/home.png"))); + connect(m_homeAction, SIGNAL(triggered()), centralWidget, SLOT(home())); + m_actionList << m_homeAction; + + QAction *separator = new QAction(parent); + separator->setSeparator(true); + m_actionList << separator; + + m_zoomInAction = new QAction(tr("Zoom &in"), parent); + m_zoomInAction->setPriority(QAction::LowPriority); + m_zoomInAction->setIcon(QIcon(resourcePath + QLatin1String("/zoomin.png"))); + m_zoomInAction->setShortcut(QKeySequence::ZoomIn); + connect(m_zoomInAction, SIGNAL(triggered()), centralWidget, SLOT(zoomIn())); + m_actionList << m_zoomInAction; + + m_zoomOutAction = new QAction(tr("Zoom &out"), parent); + m_zoomOutAction->setPriority(QAction::LowPriority); + m_zoomOutAction->setIcon(QIcon(resourcePath + QLatin1String("/zoomout.png"))); + m_zoomOutAction->setShortcut(QKeySequence::ZoomOut); + connect(m_zoomOutAction, SIGNAL(triggered()), centralWidget, SLOT(zoomOut())); + m_actionList << m_zoomOutAction; + + separator = new QAction(parent); + separator->setSeparator(true); + m_actionList << separator; + + m_copyAction = new QAction(tr("&Copy selected Text"), parent); + m_copyAction->setPriority(QAction::LowPriority); + m_copyAction->setIconText("&Copy"); + m_copyAction->setIcon(QIcon(resourcePath + QLatin1String("/editcopy.png"))); + m_copyAction->setShortcuts(QKeySequence::Copy); + m_copyAction->setEnabled(false); + connect(m_copyAction, SIGNAL(triggered()), centralWidget, SLOT(copy())); + m_actionList << m_copyAction; + + m_printAction = new QAction(tr("&Print..."), parent); + m_printAction->setPriority(QAction::LowPriority); + m_printAction->setIcon(QIcon(resourcePath + QLatin1String("/print.png"))); + m_printAction->setShortcut(QKeySequence::Print); + connect(m_printAction, SIGNAL(triggered()), centralWidget, SLOT(print())); + m_actionList << m_printAction; + + m_findAction = new QAction(tr("&Find in Text..."), parent); + m_findAction->setIconText(tr("&Find")); + m_findAction->setIcon(QIcon(resourcePath + QLatin1String("/find.png"))); + m_findAction->setShortcuts(QKeySequence::Find); + connect(m_findAction, SIGNAL(triggered()), centralWidget, SLOT(showTextSearch())); + m_actionList << m_findAction; + +#ifdef Q_WS_X11 + m_backAction->setIcon(QIcon::fromTheme("go-previous" , m_backAction->icon())); + m_nextAction->setIcon(QIcon::fromTheme("go-next" , m_nextAction->icon())); + m_zoomInAction->setIcon(QIcon::fromTheme("zoom-in" , m_zoomInAction->icon())); + m_zoomOutAction->setIcon(QIcon::fromTheme("zoom-out" , m_zoomOutAction->icon())); + m_copyAction->setIcon(QIcon::fromTheme("edit-copy" , m_copyAction->icon())); + m_findAction->setIcon(QIcon::fromTheme("edit-find" , m_findAction->icon())); + m_homeAction->setIcon(QIcon::fromTheme("go-home" , m_homeAction->icon())); + m_printAction->setIcon(QIcon::fromTheme("document-print" , m_printAction->icon())); +#endif +} + +void GlobalActions::updateActions() +{ + TRACE_OBJ + CentralWidget *centralWidget = CentralWidget::instance(); + m_copyAction->setEnabled(centralWidget->hasSelection()); + m_nextAction->setEnabled(centralWidget->isForwardAvailable()); + m_backAction->setEnabled(centralWidget->isBackwardAvailable()); +} + +void GlobalActions::setCopyAvailable(bool available) +{ + TRACE_OBJ + m_copyAction->setEnabled(available); +} + +#if !defined(QT_NO_WEBKIT) + +void GlobalActions::slotAboutToShowBackMenu() +{ + TRACE_OBJ + m_backMenu->clear(); + if (QWebHistory *history = CentralWidget::instance()->currentHelpViewer()->history()) { + const int currentItemIndex = history->currentItemIndex(); + QList items = history->backItems(history->count()); + for (int i = items.count() - 1; i >= 0; --i) { + QAction *action = new QAction(this); + action->setText(items.at(i).title()); + action->setData(-1 * (currentItemIndex - i)); + m_backMenu->addAction(action); + } + } +} + +void GlobalActions::slotAboutToShowNextMenu() +{ + TRACE_OBJ + m_nextMenu->clear(); + if (QWebHistory *history = CentralWidget::instance()->currentHelpViewer()->history()) { + const int count = history->count(); + QList items = history->forwardItems(count); + for (int i = 0; i < items.count(); ++i) { + QAction *action = new QAction(this); + action->setData(count - i); + action->setText(items.at(i).title()); + m_nextMenu->addAction(action); + } + } +} + +void GlobalActions::slotOpenActionUrl(QAction *action) +{ + TRACE_OBJ + if (HelpViewer* viewer = CentralWidget::instance()->currentHelpViewer()) { + const int offset = action->data().toInt(); + QWebHistory *history = viewer->history(); + if (offset > 0) { + history->goToItem(history->forwardItems(history->count() + - offset + 1).back()); // forward + } else if (offset < 0) { + history->goToItem(history->backItems(-1 * offset).first()); // back + } + } +} + +#endif + +void GlobalActions::setupNavigationMenus(QAction *back, QAction *next, + QWidget *parent) +{ +#if !defined(QT_NO_WEBKIT) + m_backMenu = new QMenu(parent); + connect(m_backMenu, SIGNAL(aboutToShow()), this, + SLOT(slotAboutToShowBackMenu())); + connect(m_backMenu, SIGNAL(triggered(QAction*)), this, + SLOT(slotOpenActionUrl(QAction*))); + back->setMenu(m_backMenu); + + m_nextMenu = new QMenu(parent); + connect(m_nextMenu, SIGNAL(aboutToShow()), this, + SLOT(slotAboutToShowNextMenu())); + connect(m_nextMenu, SIGNAL(triggered(QAction*)), this, + SLOT(slotOpenActionUrl(QAction*))); + next->setMenu(m_nextMenu); +#else + Q_UNUSED(back) + Q_UNUSED(next) + Q_UNUSED(parent) +#endif +} + +GlobalActions *GlobalActions::m_instance = 0; diff --git a/src/assistant/tools/assistant/globalactions.h b/src/assistant/tools/assistant/globalactions.h new file mode 100644 index 000000000..a9059a9a4 --- /dev/null +++ b/src/assistant/tools/assistant/globalactions.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Assistant module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef GLOBALACTION_H +#define GLOBALACTION_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class QAction; +class QMenu; + +class GlobalActions : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(GlobalActions) +public: + static GlobalActions *instance(QObject *parent = 0); + + QList actionList() const { return m_actionList; } + QAction *backAction() const { return m_backAction; } + QAction *nextAction() const { return m_nextAction; } + QAction *homeAction() const { return m_homeAction; } + QAction *zoomInAction() const { return m_zoomInAction; } + QAction *zoomOutAction() const { return m_zoomOutAction; } + QAction *copyAction() const { return m_copyAction; } + QAction *printAction() const { return m_printAction; } + QAction *findAction() const { return m_findAction; } + + Q_SLOT void updateActions(); + Q_SLOT void setCopyAvailable(bool available); + +#if !defined(QT_NO_WEBKIT) +private slots: + void slotAboutToShowBackMenu(); + void slotAboutToShowNextMenu(); + void slotOpenActionUrl(QAction *action); +#endif + +private: + void setupNavigationMenus(QAction *back, QAction *next, QWidget *parent); + +private: + GlobalActions(QObject *parent); + + static GlobalActions *m_instance; + + QAction *m_backAction; + QAction *m_nextAction; + QAction *m_homeAction; + QAction *m_zoomInAction; + QAction *m_zoomOutAction; + QAction *m_copyAction; + QAction *m_printAction; + QAction *m_findAction; + + QList m_actionList; + + QMenu *m_backMenu; + QMenu *m_nextMenu; +}; + +QT_END_NAMESPACE + +#endif // GLOBALACTION_H diff --git a/src/assistant/tools/assistant/helpenginewrapper.cpp b/src/assistant/tools/assistant/helpenginewrapper.cpp new file mode 100644 index 000000000..4c7ff5b30 --- /dev/null +++ b/src/assistant/tools/assistant/helpenginewrapper.cpp @@ -0,0 +1,844 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "tracer.h" + +#include "helpenginewrapper.h" +#include "../shared/collectionconfiguration.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace { + const QString Unfiltered; + const QString AppFontKey(QLatin1String("appFont")); + const QString AppWritingSystemKey(QLatin1String("appWritingSystem")); + const QString BookmarksKey(QLatin1String("Bookmarks")); + const QString BrowserFontKey(QLatin1String("browserFont")); + const QString BrowserWritingSystemKey(QLatin1String("browserWritingSystem")); + const QString HomePageKey(QLatin1String("homepage")); + const QString MainWindowKey(QLatin1String("MainWindow")); + const QString MainWindowGeometryKey(QLatin1String("MainWindowGeometry")); + const QString SearchWasAttachedKey(QLatin1String("SearchWasAttached")); + const QString StartOptionKey(QLatin1String("StartOption")); + const QString UseAppFontKey(QLatin1String("useAppFont")); + const QString UseBrowserFontKey(QLatin1String("useBrowserFont")); + const QString VersionKey(QString(QLatin1String("qtVersion%1$$$%2")). + arg(QLatin1String(QT_VERSION_STR))); + const QString ShowTabsKey(QLatin1String("showTabs")); +} // anonymous namespace + +class TimeoutForwarder : public QObject +{ + Q_OBJECT +public: + TimeoutForwarder(const QString &fileName); +private slots: + void forward(); +private: + friend class HelpEngineWrapperPrivate; + + const QString m_fileName; +}; + +class HelpEngineWrapperPrivate : public QObject +{ + Q_OBJECT + friend class HelpEngineWrapper; + friend class TimeoutForwarder; +private slots: + void qchFileChanged(const QString &fileName); + +signals: + void documentationRemoved(const QString &namespaceName); + void documentationUpdated(const QString &namespaceName); + +private: + HelpEngineWrapperPrivate(const QString &collectionFile); + + void initFileSystemWatchers(); + void checkDocFilesWatched(); + void qchFileChanged(const QString &fileName, bool fromTimeout); + + static const int UpdateGracePeriod = 2000; + + QHelpEngine * const m_helpEngine; + QFileSystemWatcher * const m_qchWatcher; + typedef QPair > RecentSignal; + QMap m_recentQchUpdates; +}; + +const QString HelpEngineWrapper::TrUnfiltered = HelpEngineWrapper::tr("Unfiltered"); + +HelpEngineWrapper *HelpEngineWrapper::helpEngineWrapper = 0; + +HelpEngineWrapper &HelpEngineWrapper::instance(const QString &collectionFile) +{ + TRACE_OBJ + /* + * Note that this Singleton cannot be static, because it has to be + * deleted before the QApplication. + */ + if (helpEngineWrapper == 0) + helpEngineWrapper = new HelpEngineWrapper(collectionFile); + return *helpEngineWrapper; +} + +void HelpEngineWrapper::removeInstance() +{ + TRACE_OBJ + delete helpEngineWrapper; + helpEngineWrapper = 0; +} + +HelpEngineWrapper::HelpEngineWrapper(const QString &collectionFile) + : d(new HelpEngineWrapperPrivate(collectionFile)) +{ + TRACE_OBJ + + /* + * Otherwise we will waste time if several new docs are found, + * because we will start to index them, only to be interrupted + * by the next request. Also, there is a nasty SQLITE bug that will + * cause the application to hang for minutes in that case. + * This call is reverted by initialDocSetupDone(), which must be + * called after the new docs have been installed. + */ + disconnect(d->m_helpEngine, SIGNAL(setupFinished()), + searchEngine(), SLOT(indexDocumentation())); + + connect(d, SIGNAL(documentationRemoved(QString)), + this, SIGNAL(documentationRemoved(QString))); + connect(d, SIGNAL(documentationUpdated(QString)), + this, SIGNAL(documentationUpdated(QString))); + connect(d->m_helpEngine, SIGNAL(currentFilterChanged(QString)), + this, SLOT(handleCurrentFilterChanged(QString))); + connect(d->m_helpEngine, SIGNAL(setupFinished()), + this, SIGNAL(setupFinished())); +} + +HelpEngineWrapper::~HelpEngineWrapper() +{ + TRACE_OBJ + const QStringList &namespaces = d->m_helpEngine->registeredDocumentations(); + foreach (const QString &nameSpace, namespaces) { + const QString &docFile + = d->m_helpEngine->documentationFileName(nameSpace); + d->m_qchWatcher->removePath(docFile); + } + + delete d; +} + +void HelpEngineWrapper::initialDocSetupDone() +{ + TRACE_OBJ + connect(d->m_helpEngine, SIGNAL(setupFinished()), + searchEngine(), SLOT(indexDocumentation())); + setupData(); +} + +QHelpSearchEngine *HelpEngineWrapper::searchEngine() const +{ + TRACE_OBJ + return d->m_helpEngine->searchEngine(); +} + +QHelpContentModel *HelpEngineWrapper::contentModel() const +{ + TRACE_OBJ + return d->m_helpEngine->contentModel(); +} + +QHelpIndexModel *HelpEngineWrapper::indexModel() const +{ + TRACE_OBJ + return d->m_helpEngine->indexModel(); +} + +QHelpContentWidget *HelpEngineWrapper::contentWidget() +{ + TRACE_OBJ + return d->m_helpEngine->contentWidget(); +} + +QHelpIndexWidget *HelpEngineWrapper::indexWidget() +{ + TRACE_OBJ + return d->m_helpEngine->indexWidget(); +} + +const QStringList HelpEngineWrapper::registeredDocumentations() const +{ + TRACE_OBJ + return d->m_helpEngine->registeredDocumentations(); +} + +const QString HelpEngineWrapper::collectionFile() const +{ + TRACE_OBJ + return d->m_helpEngine->collectionFile(); +} + +bool HelpEngineWrapper::registerDocumentation(const QString &docFile) +{ + TRACE_OBJ + d->checkDocFilesWatched(); + if (!d->m_helpEngine->registerDocumentation(docFile)) + return false; + d->m_qchWatcher->addPath(docFile); + d->checkDocFilesWatched(); + return true; +} + +bool HelpEngineWrapper::unregisterDocumentation(const QString &namespaceName) +{ + TRACE_OBJ + d->checkDocFilesWatched(); + const QString &file = d->m_helpEngine->documentationFileName(namespaceName); + if (!d->m_helpEngine->unregisterDocumentation(namespaceName)) + return false; + d->m_qchWatcher->removePath(file); + d->checkDocFilesWatched(); + return true; +} + +bool HelpEngineWrapper::setupData() +{ + TRACE_OBJ + return d->m_helpEngine->setupData(); +} + +bool HelpEngineWrapper::addCustomFilter(const QString &filterName, + const QStringList &attributes) +{ + TRACE_OBJ + return d->m_helpEngine->addCustomFilter(filterName, attributes); +} + +bool HelpEngineWrapper::removeCustomFilter(const QString &filterName) +{ + TRACE_OBJ + return d->m_helpEngine->removeCustomFilter(filterName); +} + +void HelpEngineWrapper::setCurrentFilter(const QString ¤tFilter) +{ + TRACE_OBJ + const QString &filter + = currentFilter == TrUnfiltered ? Unfiltered : currentFilter; + d->m_helpEngine->setCurrentFilter(filter); +} + +const QString HelpEngineWrapper::currentFilter() const +{ + TRACE_OBJ + const QString &filter = d->m_helpEngine->currentFilter(); + return filter == Unfiltered ? TrUnfiltered : filter; +} + +const QStringList HelpEngineWrapper::customFilters() const +{ + TRACE_OBJ + QStringList filters = d->m_helpEngine->customFilters(); + filters.removeOne(Unfiltered); + filters.prepend(TrUnfiltered); + return filters; +} + +QUrl HelpEngineWrapper::findFile(const QUrl &url) const +{ + TRACE_OBJ + return d->m_helpEngine->findFile(url); +} + +QByteArray HelpEngineWrapper::fileData(const QUrl &url) const +{ + TRACE_OBJ + return d->m_helpEngine->fileData(url); +} + +QMap HelpEngineWrapper::linksForIdentifier(const QString &id) const +{ + TRACE_OBJ + return d->m_helpEngine->linksForIdentifier(id); +} + +const QStringList HelpEngineWrapper::filterAttributes() const +{ + TRACE_OBJ + return d->m_helpEngine->filterAttributes(); +} + +const QStringList HelpEngineWrapper::filterAttributes(const QString &filterName) const +{ + TRACE_OBJ + return d->m_helpEngine->filterAttributes(filterName); +} + +QString HelpEngineWrapper::error() const +{ + TRACE_OBJ + return d->m_helpEngine->error(); +} + +const QStringList HelpEngineWrapper::qtDocInfo(const QString &component) const +{ + TRACE_OBJ + return d->m_helpEngine->customValue(VersionKey.arg(component)).toString(). + split(CollectionConfiguration::ListSeparator); +} + +void HelpEngineWrapper::setQtDocInfo(const QString &component, + const QStringList &doc) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(VersionKey.arg(component), + doc.join(CollectionConfiguration::ListSeparator)); +} + +const QStringList HelpEngineWrapper::lastShownPages() const +{ + TRACE_OBJ + return CollectionConfiguration::lastShownPages(*d->m_helpEngine); +} + +void HelpEngineWrapper::setLastShownPages(const QStringList &lastShownPages) +{ + TRACE_OBJ + CollectionConfiguration::setLastShownPages(*d->m_helpEngine, lastShownPages); +} + +const QStringList HelpEngineWrapper::lastZoomFactors() const +{ + TRACE_OBJ + return CollectionConfiguration::lastZoomFactors(*d->m_helpEngine); +} + +void HelpEngineWrapper::setLastZoomFactors(const QStringList &lastZoomFactors) +{ + TRACE_OBJ + CollectionConfiguration::setLastZoomFactors(*d->m_helpEngine, lastZoomFactors); +} + +const QString HelpEngineWrapper::cacheDir() const +{ + TRACE_OBJ + return CollectionConfiguration::cacheDir(*d->m_helpEngine); +} + +bool HelpEngineWrapper::cacheDirIsRelativeToCollection() const +{ + TRACE_OBJ + return CollectionConfiguration::cacheDirIsRelativeToCollection(*d->m_helpEngine); +} + +void HelpEngineWrapper::setCacheDir(const QString &cacheDir, + bool relativeToCollection) +{ + TRACE_OBJ + CollectionConfiguration::setCacheDir(*d->m_helpEngine, cacheDir, + relativeToCollection); +} + +bool HelpEngineWrapper::filterFunctionalityEnabled() const +{ + TRACE_OBJ + return CollectionConfiguration::filterFunctionalityEnabled(*d->m_helpEngine); +} + +void HelpEngineWrapper::setFilterFunctionalityEnabled(bool enabled) +{ + TRACE_OBJ + CollectionConfiguration::setFilterFunctionalityEnabled(*d->m_helpEngine, + enabled); +} + +bool HelpEngineWrapper::filterToolbarVisible() const +{ + TRACE_OBJ + return CollectionConfiguration::filterToolbarVisible(*d->m_helpEngine); +} + +void HelpEngineWrapper::setFilterToolbarVisible(bool visible) +{ + TRACE_OBJ + CollectionConfiguration::setFilterToolbarVisible(*d->m_helpEngine, visible); +} + +bool HelpEngineWrapper::addressBarEnabled() const +{ + TRACE_OBJ + return CollectionConfiguration::addressBarEnabled(*d->m_helpEngine); +} + +void HelpEngineWrapper::setAddressBarEnabled(bool enabled) +{ + TRACE_OBJ + CollectionConfiguration::setAddressBarEnabled(*d->m_helpEngine, enabled); +} + +bool HelpEngineWrapper::addressBarVisible() const +{ + TRACE_OBJ + return CollectionConfiguration::addressBarVisible(*d->m_helpEngine); +} + +void HelpEngineWrapper::setAddressBarVisible(bool visible) +{ + TRACE_OBJ + CollectionConfiguration::setAddressBarVisible(*d->m_helpEngine, visible); +} + +bool HelpEngineWrapper::documentationManagerEnabled() const +{ + TRACE_OBJ + return CollectionConfiguration::documentationManagerEnabled(*d->m_helpEngine); +} + +void HelpEngineWrapper::setDocumentationManagerEnabled(bool enabled) +{ + TRACE_OBJ + CollectionConfiguration::setDocumentationManagerEnabled(*d->m_helpEngine, + enabled); +} + +const QByteArray HelpEngineWrapper::aboutMenuTexts() const +{ + TRACE_OBJ + return CollectionConfiguration::aboutMenuTexts(*d->m_helpEngine); +} + +void HelpEngineWrapper::setAboutMenuTexts(const QByteArray &texts) +{ + TRACE_OBJ + CollectionConfiguration::setAboutMenuTexts(*d->m_helpEngine, texts); +} + +const QByteArray HelpEngineWrapper::aboutIcon() const +{ + TRACE_OBJ + return CollectionConfiguration::aboutIcon(*d->m_helpEngine); +} + +void HelpEngineWrapper::setAboutIcon(const QByteArray &icon) +{ + TRACE_OBJ + CollectionConfiguration::setAboutIcon(*d->m_helpEngine, icon); +} + +const QByteArray HelpEngineWrapper::aboutImages() const +{ + TRACE_OBJ + return CollectionConfiguration::aboutImages(*d->m_helpEngine); +} + +void HelpEngineWrapper::setAboutImages(const QByteArray &images) +{ + TRACE_OBJ + CollectionConfiguration::setAboutImages(*d->m_helpEngine, images); +} + +const QByteArray HelpEngineWrapper::aboutTexts() const +{ + TRACE_OBJ + return CollectionConfiguration::aboutTexts(*d->m_helpEngine); +} + +void HelpEngineWrapper::setAboutTexts(const QByteArray &texts) +{ + TRACE_OBJ + CollectionConfiguration::setAboutTexts(*d->m_helpEngine, texts); +} + +const QString HelpEngineWrapper::windowTitle() const +{ + TRACE_OBJ + return CollectionConfiguration::windowTitle(*d->m_helpEngine); +} + +void HelpEngineWrapper::setWindowTitle(const QString &windowTitle) +{ + TRACE_OBJ + CollectionConfiguration::setWindowTitle(*d->m_helpEngine, windowTitle); +} + +const QByteArray HelpEngineWrapper::applicationIcon() const +{ + TRACE_OBJ + return CollectionConfiguration::applicationIcon(*d->m_helpEngine); +} + +void HelpEngineWrapper::setApplicationIcon(const QByteArray &icon) +{ + TRACE_OBJ + CollectionConfiguration::setApplicationIcon(*d->m_helpEngine, icon); +} + +const QByteArray HelpEngineWrapper::mainWindow() const +{ + TRACE_OBJ + return d->m_helpEngine->customValue(MainWindowKey).toByteArray(); +} + +void HelpEngineWrapper::setMainWindow(const QByteArray &mainWindow) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(MainWindowKey, mainWindow); +} + +const QByteArray HelpEngineWrapper::mainWindowGeometry() const +{ + TRACE_OBJ + return d->m_helpEngine->customValue(MainWindowGeometryKey).toByteArray(); +} + +void HelpEngineWrapper::setMainWindowGeometry(const QByteArray &geometry) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(MainWindowGeometryKey, geometry); +} + +const QByteArray HelpEngineWrapper::bookmarks() const +{ + TRACE_OBJ + return d->m_helpEngine->customValue(BookmarksKey).toByteArray(); +} + +void HelpEngineWrapper::setBookmarks(const QByteArray &bookmarks) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(BookmarksKey, bookmarks); +} + +int HelpEngineWrapper::lastTabPage() const +{ + TRACE_OBJ + return CollectionConfiguration::lastTabPage(*d->m_helpEngine); +} + +void HelpEngineWrapper::setLastTabPage(int lastPage) +{ + TRACE_OBJ + CollectionConfiguration::setLastTabPage(*d->m_helpEngine, lastPage); +} + +int HelpEngineWrapper::startOption() const +{ + TRACE_OBJ + return d->m_helpEngine->customValue(StartOptionKey, ShowLastPages).toInt(); +} + +void HelpEngineWrapper::setStartOption(int option) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(StartOptionKey, option); +} + +const QString HelpEngineWrapper::homePage() const +{ + TRACE_OBJ + const QString &homePage + = d->m_helpEngine->customValue(HomePageKey).toString(); + if (!homePage.isEmpty()) + return homePage; + return defaultHomePage(); +} + +void HelpEngineWrapper::setHomePage(const QString &page) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(HomePageKey, page); + +} + +const QString HelpEngineWrapper::defaultHomePage() const +{ + TRACE_OBJ + return CollectionConfiguration::defaultHomePage(*d->m_helpEngine); +} + +void HelpEngineWrapper::setDefaultHomePage(const QString &page) +{ + TRACE_OBJ + CollectionConfiguration::setDefaultHomePage(*d->m_helpEngine, page); +} + +bool HelpEngineWrapper::hasFontSettings() const +{ + TRACE_OBJ + return d->m_helpEngine->customValue(UseAppFontKey).isValid(); +} + +bool HelpEngineWrapper::usesAppFont() const +{ + TRACE_OBJ + return d->m_helpEngine->customValue(UseAppFontKey).toBool(); +} + +void HelpEngineWrapper::setUseAppFont(bool useAppFont) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(UseAppFontKey, useAppFont); +} + +bool HelpEngineWrapper::usesBrowserFont() const +{ + TRACE_OBJ + return d->m_helpEngine->customValue(UseBrowserFontKey, false).toBool(); +} + +void HelpEngineWrapper::setUseBrowserFont(bool useBrowserFont) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(UseBrowserFontKey, useBrowserFont); +} + +const QFont HelpEngineWrapper::appFont() const +{ + TRACE_OBJ + return qvariant_cast(d->m_helpEngine->customValue(AppFontKey)); +} + +void HelpEngineWrapper::setAppFont(const QFont &font) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(AppFontKey, font); +} + +QFontDatabase::WritingSystem HelpEngineWrapper::appWritingSystem() const +{ + TRACE_OBJ + return static_cast( + d->m_helpEngine->customValue(AppWritingSystemKey).toInt()); +} + +void HelpEngineWrapper::setAppWritingSystem(QFontDatabase::WritingSystem system) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(AppWritingSystemKey, system); +} + +const QFont HelpEngineWrapper::browserFont() const +{ + TRACE_OBJ + return qvariant_cast(d->m_helpEngine->customValue(BrowserFontKey)); +} + +void HelpEngineWrapper::setBrowserFont(const QFont &font) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(BrowserFontKey, font); +} + +QFontDatabase::WritingSystem HelpEngineWrapper::browserWritingSystem() const +{ + TRACE_OBJ + return static_cast( + d->m_helpEngine->customValue(BrowserWritingSystemKey).toInt()); +} + +void HelpEngineWrapper::setBrowserWritingSystem(QFontDatabase::WritingSystem system) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(BrowserWritingSystemKey, system); +} + +void HelpEngineWrapper::handleCurrentFilterChanged(const QString &filter) +{ + TRACE_OBJ + const QString &filterToReport + = filter == Unfiltered ? TrUnfiltered : filter; + emit currentFilterChanged(filterToReport); +} + +bool HelpEngineWrapper::showTabs() const +{ + TRACE_OBJ + return d->m_helpEngine->customValue(ShowTabsKey, false).toBool(); +} + +void HelpEngineWrapper::setShowTabs(bool show) +{ + TRACE_OBJ + d->m_helpEngine->setCustomValue(ShowTabsKey, show); +} + +bool HelpEngineWrapper::fullTextSearchFallbackEnabled() const +{ + TRACE_OBJ + return CollectionConfiguration::fullTextSearchFallbackEnabled(*d->m_helpEngine); +} + +// -- TimeoutForwarder + +TimeoutForwarder::TimeoutForwarder(const QString &fileName) + : m_fileName(fileName) +{ + TRACE_OBJ +} + +void TimeoutForwarder::forward() +{ + TRACE_OBJ + HelpEngineWrapper::instance().d->qchFileChanged(m_fileName, true); +} + +// -- HelpEngineWrapperPrivate + +HelpEngineWrapperPrivate::HelpEngineWrapperPrivate(const QString &collectionFile) + : m_helpEngine(new QHelpEngine(collectionFile, this)), + m_qchWatcher(new QFileSystemWatcher(this)) +{ + TRACE_OBJ + if (!m_helpEngine->customFilters().contains(Unfiltered)) + m_helpEngine->addCustomFilter(Unfiltered, QStringList()); + initFileSystemWatchers(); +} + +void HelpEngineWrapperPrivate::initFileSystemWatchers() +{ + TRACE_OBJ + foreach(const QString &ns, m_helpEngine->registeredDocumentations()) { + const QString &docFile = m_helpEngine->documentationFileName(ns); + m_qchWatcher->addPath(docFile); + connect(m_qchWatcher, SIGNAL(fileChanged(QString)), + this, SLOT(qchFileChanged(QString))); + } + checkDocFilesWatched(); +} + +void HelpEngineWrapperPrivate::qchFileChanged(const QString &fileName) +{ + TRACE_OBJ + qchFileChanged(fileName, false); +} + +void HelpEngineWrapperPrivate::checkDocFilesWatched() +{ + TRACE_OBJ + const int watchedFilesCount = m_qchWatcher->files().count(); + const int docFilesCount = m_helpEngine->registeredDocumentations().count(); + if (watchedFilesCount != docFilesCount) { + qWarning("Strange: Have %d docs, but %d are being watched", + watchedFilesCount, docFilesCount); + } +} + +void HelpEngineWrapperPrivate::qchFileChanged(const QString &fileName, + bool fromTimeout) +{ + TRACE_OBJ + + /* + * We don't use QHelpEngineCore::namespaceName(fileName), because the file + * may not exist anymore or contain a different namespace. + */ + QString ns; + foreach (const QString &curNs, m_helpEngine->registeredDocumentations()) { + if (m_helpEngine->documentationFileName(curNs) == fileName) { + ns = curNs; + break; + } + } + + /* + * We can't do an assertion here, because QFileSystemWatcher may send the + * signal more than once. + */ + if (ns.isEmpty()) { + m_recentQchUpdates.remove(fileName); + return; + } + + /* + * Since the QFileSystemWatcher typically sends the signal more than once, + * we repeatedly delay our reaction a bit until we think the last signal + * was sent. + */ + + QMap::Iterator it = m_recentQchUpdates.find(fileName); + const QDateTime &now = QDateTime::currentDateTime(); + + // Case 1: This is the first recent signal for the file. + if (it == m_recentQchUpdates.end()) { + QSharedPointer forwarder(new TimeoutForwarder(fileName)); + m_recentQchUpdates.insert(fileName, RecentSignal(now, forwarder)); + QTimer::singleShot(UpdateGracePeriod, forwarder.data(), SLOT(forward())); + return; + } + + // Case 2: The last signal for this file has not expired yet. + if (it.value().first > now.addMSecs(-UpdateGracePeriod)) { + if (!fromTimeout) + it.value().first = now; + else + QTimer::singleShot(UpdateGracePeriod, it.value().second.data(), + SLOT(forward())); + return; + } + + // Case 3: The last signal for this file has expired. + if (m_helpEngine->unregisterDocumentation(ns)) { + if (!QFileInfo(fileName).exists() + || !m_helpEngine->registerDocumentation(fileName)) { + m_qchWatcher->removePath(fileName); + emit documentationRemoved(ns); + } else { + emit documentationUpdated(ns); + } + m_helpEngine->setupData(); + } + m_recentQchUpdates.erase(it); +} + +QT_END_NAMESPACE + +#include "helpenginewrapper.moc" diff --git a/src/assistant/tools/assistant/helpenginewrapper.h b/src/assistant/tools/assistant/helpenginewrapper.h new file mode 100644 index 000000000..ff825b04a --- /dev/null +++ b/src/assistant/tools/assistant/helpenginewrapper.h @@ -0,0 +1,218 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef HELPENGINEWRAPPER_H +#define HELPENGINEWRAPPER_H + +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QFileSystemWatcher; +class QHelpContentModel; +class QHelpContentWidget; +class QHelpIndexModel; +class QHelpIndexWidget; +class QHelpSearchEngine; + +enum { + ShowHomePage = 0, + ShowBlankPage = 1, + ShowLastPages = 2 +}; + +class HelpEngineWrapperPrivate; +class TimeoutForwarder; + +class HelpEngineWrapper : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(HelpEngineWrapper) + friend class TimeoutForwarder; +public: + static HelpEngineWrapper &instance(const QString &collectionFile = QString()); + static void removeInstance(); + + // Forwarded help engine member functions, possibly enriched. + QHelpSearchEngine *searchEngine() const; + QHelpContentModel *contentModel() const; + QHelpIndexModel *indexModel() const; + QHelpContentWidget *contentWidget(); + QHelpIndexWidget *indexWidget(); + bool setupData(); + const QStringList registeredDocumentations() const; + const QString collectionFile() const; + bool registerDocumentation(const QString &docFile); + bool unregisterDocumentation(const QString &namespaceName); + bool addCustomFilter(const QString &filterName, + const QStringList &attributes); + bool removeCustomFilter(const QString &filterName); + void setCurrentFilter(const QString &filterName); + const QString currentFilter() const; + const QStringList customFilters() const; + QUrl findFile(const QUrl &url) const; + QByteArray fileData(const QUrl &url) const; + QMap linksForIdentifier(const QString &id) const; + const QStringList filterAttributes() const; + const QStringList filterAttributes(const QString &filterName) const; + QString error() const; + + /* + * To be called after assistant has finished looking for new documentation. + * This will mainly cause the search index to be updated, if necessary. + */ + void initialDocSetupDone(); + + const QStringList qtDocInfo(const QString &component) const; + void setQtDocInfo(const QString &component, const QStringList &doc); + + const QString homePage() const; + void setHomePage(const QString &page); + const QString defaultHomePage() const; + void setDefaultHomePage(const QString &page); + + int lastTabPage() const; + void setLastTabPage(int lastPage); + + // TODO: Don't allow last pages and zoom factors to be set in isolation + // Perhaps also fill up missing elements automatically or assert. + const QStringList lastShownPages() const; + void setLastShownPages(const QStringList &lastShownPages); + const QStringList lastZoomFactors() const; + void setLastZoomFactors(const QStringList &lastZoomFactors); + + const QString cacheDir() const; + bool cacheDirIsRelativeToCollection() const; + void setCacheDir(const QString &cacheDir, bool relativeToCollection); + + bool filterFunctionalityEnabled() const; + void setFilterFunctionalityEnabled(bool enabled); + + bool filterToolbarVisible() const; + void setFilterToolbarVisible(bool visible); + + bool addressBarEnabled() const; + void setAddressBarEnabled(bool enabled); + + bool addressBarVisible() const; + void setAddressBarVisible(bool visible); + + bool documentationManagerEnabled() const; + void setDocumentationManagerEnabled(bool enabled); + + const QByteArray aboutMenuTexts() const; + void setAboutMenuTexts(const QByteArray &texts); + const QByteArray aboutTexts() const; + void setAboutTexts(const QByteArray &texts); + const QByteArray aboutIcon() const; + void setAboutIcon(const QByteArray &icon); + const QByteArray aboutImages() const; + void setAboutImages(const QByteArray &images); + + const QString windowTitle() const; + void setWindowTitle(const QString &windowTitle); + + const QByteArray applicationIcon() const; + void setApplicationIcon(const QByteArray &icon); + + const QByteArray mainWindow() const; + void setMainWindow(const QByteArray &mainWindow); + const QByteArray mainWindowGeometry() const; + void setMainWindowGeometry(const QByteArray &geometry); + + const QByteArray bookmarks() const; + void setBookmarks(const QByteArray &bookmarks); + + int startOption() const; + void setStartOption(int option); + + bool hasFontSettings() const; + bool usesAppFont() const; + void setUseAppFont(bool useAppFont); + bool usesBrowserFont() const; + void setUseBrowserFont(bool useBrowserFont); + const QFont appFont() const; + void setAppFont(const QFont &font); + QFontDatabase::WritingSystem appWritingSystem() const; + void setAppWritingSystem(QFontDatabase::WritingSystem system); + const QFont browserFont() const; + void setBrowserFont(const QFont &font); + QFontDatabase::WritingSystem browserWritingSystem() const; + void setBrowserWritingSystem(QFontDatabase::WritingSystem system); + + bool showTabs() const; + void setShowTabs(bool show); + + static const QString TrUnfiltered; + + bool fullTextSearchFallbackEnabled() const; + +signals: + + // For asynchronous doc updates triggered by external actions. + void documentationRemoved(const QString &namespaceName); + void documentationUpdated(const QString &namespaceName); + + // Forwarded from QHelpEngineCore. + void currentFilterChanged(const QString ¤tFilter); + void setupFinished(); + +private slots: + void handleCurrentFilterChanged(const QString &filter); + +private: + HelpEngineWrapper(const QString &collectionFile); + ~HelpEngineWrapper(); + + static HelpEngineWrapper *helpEngineWrapper; + + HelpEngineWrapperPrivate *d; +}; + +QT_END_NAMESPACE + +#endif // HELPENGINEWRAPPER_H diff --git a/src/assistant/tools/assistant/helpviewer.cpp b/src/assistant/tools/assistant/helpviewer.cpp new file mode 100644 index 000000000..7bed4965a --- /dev/null +++ b/src/assistant/tools/assistant/helpviewer.cpp @@ -0,0 +1,221 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "helpviewer.h" +#include "helpviewer_p.h" + +#include "helpenginewrapper.h" +#include "tracer.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +const QString HelpViewer::DocPath = QLatin1String("qthelp://com.trolltech."); + +const QString HelpViewer::AboutBlank = + QCoreApplication::translate("HelpViewer", "about:blank"); + +const QString HelpViewer::LocalHelpFile = QLatin1String("qthelp://" + "com.trolltech.com.assistantinternal-1.0.0/assistant/assistant.html"); + +const QString HelpViewer::PageNotFoundMessage = + QCoreApplication::translate("HelpViewer", "Error 404...


The page could not be found


'%1'" + "

"); + +struct ExtensionMap { + const char *extension; + const char *mimeType; +} extensionMap[] = { + { ".bmp", "image/bmp" }, + { ".css", "text/css" }, + { ".gif", "image/gif" }, + { ".html", "text/html" }, + { ".htm", "text/html" }, + { ".ico", "image/x-icon" }, + { ".jpeg", "image/jpeg" }, + { ".jpg", "image/jpeg" }, + { ".js", "application/x-javascript" }, + { ".mng", "video/x-mng" }, + { ".pbm", "image/x-portable-bitmap" }, + { ".pgm", "image/x-portable-graymap" }, + { ".pdf", "application/pdf" }, + { ".png", "image/png" }, + { ".ppm", "image/x-portable-pixmap" }, + { ".rss", "application/rss+xml" }, + { ".svg", "image/svg+xml" }, + { ".svgz", "image/svg+xml" }, + { ".text", "text/plain" }, + { ".tif", "image/tiff" }, + { ".tiff", "image/tiff" }, + { ".txt", "text/plain" }, + { ".xbm", "image/x-xbitmap" }, + { ".xml", "text/xml" }, + { ".xpm", "image/x-xpm" }, + { ".xsl", "text/xsl" }, + { ".xhtml", "application/xhtml+xml" }, + { ".wml", "text/vnd.wap.wml" }, + { ".wmlc", "application/vnd.wap.wmlc" }, + { "about:blank", 0 }, + { 0, 0 } +}; + +HelpViewer::~HelpViewer() +{ + TRACE_OBJ + delete d; +} + +bool HelpViewer::isLocalUrl(const QUrl &url) +{ + TRACE_OBJ + const QString &scheme = url.scheme(); + return scheme.isEmpty() + || scheme == QLatin1String("file") + || scheme == QLatin1String("qrc") + || scheme == QLatin1String("data") + || scheme == QLatin1String("qthelp") + || scheme == QLatin1String("about"); +} + +bool HelpViewer::canOpenPage(const QString &url) +{ + TRACE_OBJ + return !mimeFromUrl(url).isEmpty(); +} + +QString HelpViewer::mimeFromUrl(const QUrl &url) +{ + TRACE_OBJ + const QString &path = url.path(); + const int index = path.lastIndexOf(QLatin1Char('.')); + const QByteArray &ext = path.mid(index).toUtf8().toLower(); + + const ExtensionMap *e = extensionMap; + while (e->extension) { + if (ext == e->extension) + return QLatin1String(e->mimeType); + ++e; + } + return QLatin1String(""); +} + +bool HelpViewer::launchWithExternalApp(const QUrl &url) +{ + TRACE_OBJ + if (isLocalUrl(url)) { + const HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + const QUrl &resolvedUrl = helpEngine.findFile(url); + if (!resolvedUrl.isValid()) + return false; + + const QString& path = resolvedUrl.path(); + if (!canOpenPage(path)) { + QTemporaryFile tmpTmpFile; + if (!tmpTmpFile.open()) + return false; + + const QString &extension = QFileInfo(path).completeSuffix(); + QFile actualTmpFile(tmpTmpFile.fileName() % QLatin1String(".") + % extension); + if (!actualTmpFile.open(QIODevice::ReadWrite | QIODevice::Truncate)) + return false; + + actualTmpFile.write(helpEngine.fileData(resolvedUrl)); + actualTmpFile.close(); + return QDesktopServices::openUrl(QUrl(actualTmpFile.fileName())); + } + } else if (url.scheme() == QLatin1String("http")) { + return QDesktopServices::openUrl(url); + } + return false; +} + +// -- public slots + +void HelpViewer::home() +{ + TRACE_OBJ + setSource(HelpEngineWrapper::instance().homePage()); +} + +// -- private slots + +void HelpViewer::setLoadStarted() +{ + d->m_loadFinished = false; +} + +void HelpViewer::setLoadFinished(bool ok) +{ + d->m_loadFinished = ok; + emit sourceChanged(source()); +} + +// -- private + +bool HelpViewer::handleForwardBackwardMouseButtons(QMouseEvent *event) +{ + TRACE_OBJ + if (event->button() == Qt::XButton1) { + backward(); + return true; + } + + if (event->button() == Qt::XButton2) { + forward(); + return true; + } + + return false; +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/helpviewer.h b/src/assistant/tools/assistant/helpviewer.h new file mode 100644 index 000000000..bba01d0e6 --- /dev/null +++ b/src/assistant/tools/assistant/helpviewer.h @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef HELPVIEWER_H +#define HELPVIEWER_H + +#include +#include +#include +#include + +#include +#include + +#if defined(QT_NO_WEBKIT) +#include +#else +#include +#endif + +QT_BEGIN_NAMESPACE + +#if !defined(QT_NO_WEBKIT) +class HelpViewer : public QWebView +#else +class HelpViewer : public QTextBrowser +#endif +{ + Q_OBJECT + class HelpViewerPrivate; + Q_DISABLE_COPY(HelpViewer) + +public: + enum FindFlag { + FindBackward = 0x01, + FindCaseSensitively = 0x02 + }; + Q_DECLARE_FLAGS(FindFlags, FindFlag) + + HelpViewer(qreal zoom, QWidget *parent = 0); + ~HelpViewer(); + + QFont viewerFont() const; + void setViewerFont(const QFont &font); + + void scaleUp(); + void scaleDown(); + + void resetScale(); + qreal scale() const; + + QString title() const; + void setTitle(const QString &title); + + QUrl source() const; + void setSource(const QUrl &url); + + QString selectedText() const; + bool isForwardAvailable() const; + bool isBackwardAvailable() const; + + bool findText(const QString &text, FindFlags flags, bool incremental, + bool fromSearch); + + static const QString DocPath; + static const QString AboutBlank; + static const QString LocalHelpFile; + static const QString PageNotFoundMessage; + + static bool isLocalUrl(const QUrl &url); + static bool canOpenPage(const QString &url); + static QString mimeFromUrl(const QUrl &url); + static bool launchWithExternalApp(const QUrl &url); + +public slots: + void copy(); + void home(); + + void forward(); + void backward(); + +signals: + void titleChanged(); +#if !defined(QT_NO_WEBKIT) + void copyAvailable(bool yes); + void sourceChanged(const QUrl &url); + void forwardAvailable(bool enabled); + void backwardAvailable(bool enabled); + void highlighted(const QString &link); + void printRequested(); +#else + void loadStarted(); + void loadFinished(bool finished); +#endif + +protected: + void keyPressEvent(QKeyEvent *e); + void wheelEvent(QWheelEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + +private slots: + void actionChanged(); + void setLoadStarted(); + void setLoadFinished(bool ok); + +private: + bool eventFilter(QObject *obj, QEvent *event); + void contextMenuEvent(QContextMenuEvent *event); + QVariant loadResource(int type, const QUrl &name); + bool handleForwardBackwardMouseButtons(QMouseEvent *e); + +private: + HelpViewerPrivate *d; +}; + +QT_END_NAMESPACE +Q_DECLARE_METATYPE(HelpViewer*) + +#endif // HELPVIEWER_H diff --git a/src/assistant/tools/assistant/helpviewer_p.h b/src/assistant/tools/assistant/helpviewer_p.h new file mode 100644 index 000000000..378871197 --- /dev/null +++ b/src/assistant/tools/assistant/helpviewer_p.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef HELPVIEWERPRIVATE_H +#define HELPVIEWERPRIVATE_H + +#include "centralwidget.h" +#include "helpviewer.h" +#include "openpagesmanager.h" + +#include +#ifdef QT_NO_WEBKIT +#include +#endif + +QT_BEGIN_NAMESPACE + +class HelpViewer::HelpViewerPrivate : public QObject +{ + Q_OBJECT + +public: +#ifdef QT_NO_WEBKIT + HelpViewerPrivate(int zoom) + : zoomCount(zoom) + , forceFont(false) + , lastAnchor(QString()) +#else + HelpViewerPrivate() +#endif + { + m_loadFinished = false; + } + +#ifdef QT_NO_WEBKIT + bool hasAnchorAt(QTextBrowser *browser, const QPoint& pos) + { + lastAnchor = browser->anchorAt(pos); + if (lastAnchor.isEmpty()) + return false; + + lastAnchor = browser->source().resolved(lastAnchor).toString(); + if (lastAnchor.at(0) == QLatin1Char('#')) { + QString src = browser->source().toString(); + int hsh = src.indexOf(QLatin1Char('#')); + lastAnchor = (hsh >= 0 ? src.left(hsh) : src) + lastAnchor; + } + return true; + } + + void openLink(bool newPage) + { + if(lastAnchor.isEmpty()) + return; + if (newPage) + OpenPagesManager::instance()->createPage(lastAnchor); + else + CentralWidget::instance()->setSource(lastAnchor); + lastAnchor.clear(); + } + +public slots: + void openLink() + { + openLink(false); + } + + void openLinkInNewPage() + { + openLink(true); + } + +public: + int zoomCount; + bool forceFont; + QString lastAnchor; +#endif // QT_NO_WEBKIT + +public: + bool m_loadFinished; +}; + +QT_END_NAMESPACE + +#endif // HELPVIEWERPRIVATE_H diff --git a/src/assistant/tools/assistant/helpviewer_qtb.cpp b/src/assistant/tools/assistant/helpviewer_qtb.cpp new file mode 100644 index 000000000..0a6325cb5 --- /dev/null +++ b/src/assistant/tools/assistant/helpviewer_qtb.cpp @@ -0,0 +1,384 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "helpviewer.h" + +#include "globalactions.h" +#include "helpenginewrapper.h" +#include "helpviewer_p.h" +#include "openpagesmanager.h" +#include "tracer.h" + +#include + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +HelpViewer::HelpViewer(qreal zoom, QWidget *parent) + : QTextBrowser(parent) + , d(new HelpViewerPrivate(zoom)) +{ + TRACE_OBJ + QPalette p = palette(); + p.setColor(QPalette::Inactive, QPalette::Highlight, + p.color(QPalette::Active, QPalette::Highlight)); + p.setColor(QPalette::Inactive, QPalette::HighlightedText, + p.color(QPalette::Active, QPalette::HighlightedText)); + setPalette(p); + + installEventFilter(this); + document()->setDocumentMargin(8); + + QFont font = viewerFont(); + font.setPointSize(int(font.pointSize() + zoom)); + setViewerFont(font); + + connect(this, SIGNAL(sourceChanged(QUrl)), this, SIGNAL(titleChanged())); + connect(this, SIGNAL(loadFinished(bool)), this, SLOT(setLoadFinished(bool))); +} + +QFont HelpViewer::viewerFont() const +{ + TRACE_OBJ + if (HelpEngineWrapper::instance().usesBrowserFont()) + return HelpEngineWrapper::instance().browserFont(); + return qApp->font(); +} + +void HelpViewer::setViewerFont(const QFont &newFont) +{ + TRACE_OBJ + if (font() != newFont) { + d->forceFont = true; + setFont(newFont); + d->forceFont = false; + } +} + +void HelpViewer::scaleUp() +{ + TRACE_OBJ + if (d->zoomCount < 10) { + d->zoomCount++; + d->forceFont = true; + zoomIn(); + d->forceFont = false; + } +} + +void HelpViewer::scaleDown() +{ + TRACE_OBJ + if (d->zoomCount > -5) { + d->zoomCount--; + d->forceFont = true; + zoomOut(); + d->forceFont = false; + } +} + +void HelpViewer::resetScale() +{ + TRACE_OBJ + if (d->zoomCount != 0) { + d->forceFont = true; + zoomOut(d->zoomCount); + d->forceFont = false; + } + d->zoomCount = 0; +} + +qreal HelpViewer::scale() const +{ + TRACE_OBJ + return d->zoomCount; +} + +QString HelpViewer::title() const +{ + TRACE_OBJ + return documentTitle(); +} + +void HelpViewer::setTitle(const QString &title) +{ + TRACE_OBJ + setDocumentTitle(title); +} + +QUrl HelpViewer::source() const +{ + TRACE_OBJ + return QTextBrowser::source(); +} + +void HelpViewer::setSource(const QUrl &url) +{ + TRACE_OBJ + if (launchWithExternalApp(url)) + return; + + emit loadStarted(); + QString string = url.toString(); + const HelpEngineWrapper &engine = HelpEngineWrapper::instance(); + const QUrl &resolvedUrl = (string == QLatin1String("help") ? LocalHelpFile : + engine.findFile(string)); + QTextBrowser::setSource(resolvedUrl); + if (!url.isValid()) { + setHtml(string == QLatin1String("about:blank") ? AboutBlank + : PageNotFoundMessage.arg(url.toString())); + } + emit loadFinished(true); +} + +QString HelpViewer::selectedText() const +{ + TRACE_OBJ + return textCursor().selectedText(); +} + +bool HelpViewer::isForwardAvailable() const +{ + TRACE_OBJ + return QTextBrowser::isForwardAvailable(); +} + +bool HelpViewer::isBackwardAvailable() const +{ + TRACE_OBJ + return QTextBrowser::isBackwardAvailable(); +} + +bool HelpViewer::findText(const QString &text, FindFlags flags, bool incremental, + bool fromSearch) +{ + TRACE_OBJ + QTextDocument *doc = document(); + QTextCursor cursor = textCursor(); + if (!doc || cursor.isNull()) + return false; + + const int position = cursor.selectionStart(); + if (incremental) + cursor.setPosition(position); + + QTextDocument::FindFlags textDocFlags; + if (flags & HelpViewer::FindBackward) + textDocFlags |= QTextDocument::FindBackward; + if (flags & HelpViewer::FindCaseSensitively) + textDocFlags |= QTextDocument::FindCaseSensitively; + + QTextCursor found = doc->find(text, cursor, textDocFlags); + if (found.isNull()) { + if ((flags & HelpViewer::FindBackward) == 0) + cursor.movePosition(QTextCursor::Start); + else + cursor.movePosition(QTextCursor::End); + found = doc->find(text, cursor, textDocFlags); + } + + if (fromSearch) { + cursor.beginEditBlock(); + viewport()->setUpdatesEnabled(false); + + QTextCharFormat marker; + marker.setForeground(Qt::red); + cursor.movePosition(QTextCursor::Start); + setTextCursor(cursor); + + while (find(text)) { + QTextCursor hit = textCursor(); + hit.mergeCharFormat(marker); + } + + viewport()->setUpdatesEnabled(true); + cursor.endEditBlock(); + } + + bool cursorIsNull = found.isNull(); + if (cursorIsNull) { + found = textCursor(); + found.setPosition(position); + } + setTextCursor(found); + return !cursorIsNull; +} + +// -- public slots + +void HelpViewer::copy() +{ + TRACE_OBJ + QTextBrowser::copy(); +} + +void HelpViewer::forward() +{ + TRACE_OBJ + QTextBrowser::forward(); +} + +void HelpViewer::backward() +{ + TRACE_OBJ + QTextBrowser::backward(); +} + +// -- protected + +void HelpViewer::keyPressEvent(QKeyEvent *e) +{ + TRACE_OBJ + if ((e->key() == Qt::Key_Home && e->modifiers() != Qt::NoModifier) + || (e->key() == Qt::Key_End && e->modifiers() != Qt::NoModifier)) { + QKeyEvent* event = new QKeyEvent(e->type(), e->key(), Qt::NoModifier, + e->text(), e->isAutoRepeat(), e->count()); + e = event; + } + QTextBrowser::keyPressEvent(e); +} + + +void HelpViewer::wheelEvent(QWheelEvent *e) +{ + TRACE_OBJ + if (e->modifiers() == Qt::ControlModifier) { + e->accept(); + e->delta() > 0 ? scaleUp() : scaleDown(); + } else { + QTextBrowser::wheelEvent(e); + } +} + +void HelpViewer::mousePressEvent(QMouseEvent *e) +{ + TRACE_OBJ +#ifdef Q_OS_LINUX + if (handleForwardBackwardMouseButtons(e)) + return; +#endif + + QTextBrowser::mousePressEvent(e); +} + +void HelpViewer::mouseReleaseEvent(QMouseEvent *e) +{ + TRACE_OBJ +#ifndef Q_OS_LINUX + if (handleForwardBackwardMouseButtons(e)) + return; +#endif + + bool controlPressed = e->modifiers() & Qt::ControlModifier; + if ((controlPressed && d->hasAnchorAt(this, e->pos())) || + (e->button() == Qt::MidButton && d->hasAnchorAt(this, e->pos()))) { + d->openLinkInNewPage(); + return; + } + + QTextBrowser::mouseReleaseEvent(e); +} + +// -- private slots + +void HelpViewer::actionChanged() +{ + // stub + TRACE_OBJ +} + +// -- private + +bool HelpViewer::eventFilter(QObject *obj, QEvent *event) +{ + TRACE_OBJ + if (event->type() == QEvent::FontChange && !d->forceFont) + return true; + return QTextBrowser::eventFilter(obj, event); +} + +void HelpViewer::contextMenuEvent(QContextMenuEvent *event) +{ + TRACE_OBJ + + QMenu menu(QString(), 0); + QUrl link; + QAction *copyAnchorAction = 0; + if (d->hasAnchorAt(this, event->pos())) { + link = anchorAt(event->pos()); + if (link.isRelative()) + link = source().resolved(link); + menu.addAction(tr("Open Link"), d, SLOT(openLink())); + menu.addAction(tr("Open Link in New Tab\tCtrl+LMB"), d, SLOT(openLinkInNewPage())); + + if (!link.isEmpty() && link.isValid()) + copyAnchorAction = menu.addAction(tr("Copy &Link Location")); + } else if (!selectedText().isEmpty()) { + menu.addAction(tr("Copy"), this, SLOT(copy())); + } else { + menu.addAction(tr("Reload"), this, SLOT(reload())); + } + + if (copyAnchorAction == menu.exec(event->globalPos())) + QApplication::clipboard()->setText(link.toString()); +} + +QVariant HelpViewer::loadResource(int type, const QUrl &name) +{ + TRACE_OBJ + QByteArray ba; + if (type < 4) { + ba = HelpEngineWrapper::instance().fileData(name); + if (name.toString().endsWith(QLatin1String(".svg"), Qt::CaseInsensitive)) { + QImage image; + image.loadFromData(ba, "svg"); + if (!image.isNull()) + return image; + } + } + return ba; +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/helpviewer_qwv.cpp b/src/assistant/tools/assistant/helpviewer_qwv.cpp new file mode 100644 index 000000000..efb9b5900 --- /dev/null +++ b/src/assistant/tools/assistant/helpviewer_qwv.cpp @@ -0,0 +1,495 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "helpviewer.h" +#include "helpviewer_p.h" + +#include "centralwidget.h" +#include "helpenginewrapper.h" +#include "openpagesmanager.h" +#include "tracer.h" + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +// -- HelpNetworkReply + +class HelpNetworkReply : public QNetworkReply +{ +public: + HelpNetworkReply(const QNetworkRequest &request, const QByteArray &fileData, + const QString &mimeType); + + virtual void abort(); + + virtual qint64 bytesAvailable() const + { return data.length() + QNetworkReply::bytesAvailable(); } + +protected: + virtual qint64 readData(char *data, qint64 maxlen); + +private: + QByteArray data; + qint64 origLen; +}; + +HelpNetworkReply::HelpNetworkReply(const QNetworkRequest &request, + const QByteArray &fileData, const QString& mimeType) + : data(fileData), origLen(fileData.length()) +{ + TRACE_OBJ + setRequest(request); + setOpenMode(QIODevice::ReadOnly); + + setHeader(QNetworkRequest::ContentTypeHeader, mimeType); + setHeader(QNetworkRequest::ContentLengthHeader, QByteArray::number(origLen)); + QTimer::singleShot(0, this, SIGNAL(metaDataChanged())); + QTimer::singleShot(0, this, SIGNAL(readyRead())); +} + +void HelpNetworkReply::abort() +{ + TRACE_OBJ +} + +qint64 HelpNetworkReply::readData(char *buffer, qint64 maxlen) +{ + TRACE_OBJ + qint64 len = qMin(qint64(data.length()), maxlen); + if (len) { + memcpy(buffer, data.constData(), len); + data.remove(0, len); + } + if (!data.length()) + QTimer::singleShot(0, this, SIGNAL(finished())); + return len; +} + +// -- HelpNetworkAccessManager + +class HelpNetworkAccessManager : public QNetworkAccessManager +{ +public: + HelpNetworkAccessManager(QObject *parent); + +protected: + virtual QNetworkReply *createRequest(Operation op, + const QNetworkRequest &request, QIODevice *outgoingData = 0); +}; + +HelpNetworkAccessManager::HelpNetworkAccessManager(QObject *parent) + : QNetworkAccessManager(parent) +{ + TRACE_OBJ +} + +QNetworkReply *HelpNetworkAccessManager::createRequest(Operation /*op*/, + const QNetworkRequest &request, QIODevice* /*outgoingData*/) +{ + TRACE_OBJ + QString url = request.url().toString(); + const HelpEngineWrapper &engine = HelpEngineWrapper::instance(); + // TODO: For some reason the url to load is already wrong (passed from webkit) + // though the css file and the references inside should work that way. One + // possible problem might be that the css is loaded at the same level as the + // html, thus a path inside the css like (../images/foo.png) might cd out of + // the virtual folder + if (!engine.findFile(url).isValid()) { + if (url.startsWith(HelpViewer::DocPath)) { + QUrl newUrl = request.url(); + if (!newUrl.path().startsWith(QLatin1String("/qdoc/"))) { + newUrl.setPath(QLatin1String("qdoc") + newUrl.path()); + url = newUrl.toString(); + } + } + } + + const QString &mimeType = HelpViewer::mimeFromUrl(url); + const QByteArray &data = engine.findFile(url).isValid() ? engine.fileData(url) + : HelpViewer::PageNotFoundMessage.arg(url).toUtf8(); + + return new HelpNetworkReply(request, data, mimeType.isEmpty() + ? QLatin1String("application/octet-stream") : mimeType); +} + +// -- HelpPage + +class HelpPage : public QWebPage +{ +public: + HelpPage(QObject *parent); + +protected: + virtual QWebPage *createWindow(QWebPage::WebWindowType); + virtual void triggerAction(WebAction action, bool checked = false); + + virtual bool acceptNavigationRequest(QWebFrame *frame, + const QNetworkRequest &request, NavigationType type); + +private: + bool closeNewTabIfNeeded; + + friend class HelpViewer; + QUrl m_loadingUrl; + Qt::MouseButtons m_pressedButtons; + Qt::KeyboardModifiers m_keyboardModifiers; +}; + +HelpPage::HelpPage(QObject *parent) + : QWebPage(parent) + , closeNewTabIfNeeded(false) + , m_pressedButtons(Qt::NoButton) + , m_keyboardModifiers(Qt::NoModifier) +{ + TRACE_OBJ +} + +QWebPage *HelpPage::createWindow(QWebPage::WebWindowType) +{ + TRACE_OBJ + HelpPage* newPage = static_cast(OpenPagesManager::instance() + ->createPage()->page()); + newPage->closeNewTabIfNeeded = closeNewTabIfNeeded; + closeNewTabIfNeeded = false; + return newPage; +} + +void HelpPage::triggerAction(WebAction action, bool checked) +{ + TRACE_OBJ + switch (action) { + case OpenLinkInNewWindow: + closeNewTabIfNeeded = true; + default: // fall through + QWebPage::triggerAction(action, checked); + break; + } +} + +bool HelpPage::acceptNavigationRequest(QWebFrame *, + const QNetworkRequest &request, QWebPage::NavigationType type) +{ + TRACE_OBJ + const bool closeNewTab = closeNewTabIfNeeded; + closeNewTabIfNeeded = false; + + const QUrl &url = request.url(); + if (HelpViewer::launchWithExternalApp(url)) { + if (closeNewTab) + QMetaObject::invokeMethod(OpenPagesManager::instance(), "closeCurrentPage"); + return false; + } + + if (type == QWebPage::NavigationTypeLinkClicked + && (m_keyboardModifiers & Qt::ControlModifier || m_pressedButtons == Qt::MidButton)) { + m_pressedButtons = Qt::NoButton; + m_keyboardModifiers = Qt::NoModifier; + OpenPagesManager::instance()->createPage(url); + return false; + } + + m_loadingUrl = url; // because of async page loading, we will hit some kind + // of race condition while using a remote command, like a combination of + // SetSource; SyncContent. SetSource would be called and SyncContents shortly + // afterwards, but the page might not have finished loading and the old url + // would be returned. + return true; +} + +// -- HelpViewer + +HelpViewer::HelpViewer(qreal zoom, QWidget *parent) + : QWebView(parent) + , d(new HelpViewerPrivate) +{ + TRACE_OBJ + setAcceptDrops(false); + settings()->setAttribute(QWebSettings::JavaEnabled, false); + settings()->setAttribute(QWebSettings::PluginsEnabled, false); + + setPage(new HelpPage(this)); + page()->setNetworkAccessManager(new HelpNetworkAccessManager(this)); + + QAction* action = pageAction(QWebPage::OpenLinkInNewWindow); + action->setText(tr("Open Link in New Page")); + + pageAction(QWebPage::DownloadLinkToDisk)->setVisible(false); + pageAction(QWebPage::DownloadImageToDisk)->setVisible(false); + pageAction(QWebPage::OpenImageInNewWindow)->setVisible(false); + + connect(pageAction(QWebPage::Copy), SIGNAL(changed()), this, + SLOT(actionChanged())); + connect(pageAction(QWebPage::Back), SIGNAL(changed()), this, + SLOT(actionChanged())); + connect(pageAction(QWebPage::Forward), SIGNAL(changed()), this, + SLOT(actionChanged())); + connect(page(), SIGNAL(linkHovered(QString, QString, QString)), this, + SIGNAL(highlighted(QString))); + connect(this, SIGNAL(urlChanged(QUrl)), this, SIGNAL(sourceChanged(QUrl))); + connect(this, SIGNAL(loadStarted()), this, SLOT(setLoadStarted())); + connect(this, SIGNAL(loadFinished(bool)), this, SLOT(setLoadFinished(bool))); + connect(this, SIGNAL(titleChanged(QString)), this, SIGNAL(titleChanged())); + connect(page(), SIGNAL(printRequested(QWebFrame*)), this, SIGNAL(printRequested())); + + setFont(viewerFont()); + setTextSizeMultiplier(zoom == 0.0 ? 1.0 : zoom); +} + +QFont HelpViewer::viewerFont() const +{ + TRACE_OBJ + if (HelpEngineWrapper::instance().usesBrowserFont()) + return HelpEngineWrapper::instance().browserFont(); + + QWebSettings *webSettings = QWebSettings::globalSettings(); + return QFont(webSettings->fontFamily(QWebSettings::StandardFont), + webSettings->fontSize(QWebSettings::DefaultFontSize)); +} + +void HelpViewer::setViewerFont(const QFont &font) +{ + TRACE_OBJ + QWebSettings *webSettings = settings(); + webSettings->setFontFamily(QWebSettings::StandardFont, font.family()); + webSettings->setFontSize(QWebSettings::DefaultFontSize, font.pointSize()); +} + +void HelpViewer::scaleUp() +{ + TRACE_OBJ + setTextSizeMultiplier(textSizeMultiplier() + 0.1); +} + +void HelpViewer::scaleDown() +{ + TRACE_OBJ + setTextSizeMultiplier(qMax(0.0, textSizeMultiplier() - 0.1)); +} + +void HelpViewer::resetScale() +{ + TRACE_OBJ + setTextSizeMultiplier(1.0); +} + +qreal HelpViewer::scale() const +{ + TRACE_OBJ + return textSizeMultiplier(); +} + +QString HelpViewer::title() const +{ + TRACE_OBJ + return QWebView::title(); +} + +void HelpViewer::setTitle(const QString &title) +{ + TRACE_OBJ + Q_UNUSED(title) +} + +QUrl HelpViewer::source() const +{ + TRACE_OBJ + HelpPage *currentPage = static_cast (page()); + if (currentPage && !d->m_loadFinished) { + // see HelpPage::acceptNavigationRequest(...) + return currentPage->m_loadingUrl; + } + return url(); +} + +void HelpViewer::setSource(const QUrl &url) +{ + TRACE_OBJ + load(url.toString() == QLatin1String("help") ? LocalHelpFile : url); +} + +QString HelpViewer::selectedText() const +{ + TRACE_OBJ + return QWebView::selectedText(); +} + +bool HelpViewer::isForwardAvailable() const +{ + TRACE_OBJ + return pageAction(QWebPage::Forward)->isEnabled(); +} + +bool HelpViewer::isBackwardAvailable() const +{ + TRACE_OBJ + return pageAction(QWebPage::Back)->isEnabled(); +} + +bool HelpViewer::findText(const QString &text, FindFlags flags, bool incremental, + bool fromSearch) +{ + TRACE_OBJ + Q_UNUSED(incremental); Q_UNUSED(fromSearch); + QWebPage::FindFlags options = QWebPage::FindWrapsAroundDocument; + if (flags & FindBackward) + options |= QWebPage::FindBackward; + if (flags & FindCaseSensitively) + options |= QWebPage::FindCaseSensitively; + + bool found = QWebView::findText(text, options); + options = QWebPage::HighlightAllOccurrences; + QWebView::findText(QLatin1String(""), options); // clear first + QWebView::findText(text, options); // force highlighting of all other matches + return found; +} + +// -- public slots + +void HelpViewer::copy() +{ + TRACE_OBJ + triggerPageAction(QWebPage::Copy); +} + +void HelpViewer::forward() +{ + TRACE_OBJ + QWebView::forward(); +} + +void HelpViewer::backward() +{ + TRACE_OBJ + back(); +} + +// -- protected + +void HelpViewer::keyPressEvent(QKeyEvent *e) +{ + TRACE_OBJ + // TODO: remove this once we support multiple keysequences per command + if (e->key() == Qt::Key_Insert && e->modifiers() == Qt::CTRL) { + if (!selectedText().isEmpty()) + copy(); + } + QWebView::keyPressEvent(e); +} + +void HelpViewer::wheelEvent(QWheelEvent *event) +{ + TRACE_OBJ + if (event->modifiers()& Qt::ControlModifier) { + event->accept(); + event->delta() > 0 ? scaleUp() : scaleDown(); + } else { + QWebView::wheelEvent(event); + } +} + +void HelpViewer::mousePressEvent(QMouseEvent *event) +{ + TRACE_OBJ +#ifdef Q_OS_LINUX + if (handleForwardBackwardMouseButtons(event)) + return; +#endif + + if (HelpPage *currentPage = static_cast (page())) { + currentPage->m_pressedButtons = event->buttons(); + currentPage->m_keyboardModifiers = event->modifiers(); + } + + QWebView::mousePressEvent(event); +} + +void HelpViewer::mouseReleaseEvent(QMouseEvent *event) +{ + TRACE_OBJ +#ifndef Q_OS_LINUX + if (handleForwardBackwardMouseButtons(event)) + return; +#endif + + QWebView::mouseReleaseEvent(event); +} + +// -- private slots + +void HelpViewer::actionChanged() +{ + TRACE_OBJ + QAction *a = qobject_cast(sender()); + if (a == pageAction(QWebPage::Copy)) + emit copyAvailable(a->isEnabled()); + else if (a == pageAction(QWebPage::Back)) + emit backwardAvailable(a->isEnabled()); + else if (a == pageAction(QWebPage::Forward)) + emit forwardAvailable(a->isEnabled()); +} + +// -- private + +bool HelpViewer::eventFilter(QObject *obj, QEvent *event) +{ + TRACE_OBJ + return QWebView::eventFilter(obj, event); +} + +void HelpViewer::contextMenuEvent(QContextMenuEvent *event) +{ + TRACE_OBJ + QWebView::contextMenuEvent(event); +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/images/assistant-128.png b/src/assistant/tools/assistant/images/assistant-128.png new file mode 100644 index 000000000..f05949f6d Binary files /dev/null and b/src/assistant/tools/assistant/images/assistant-128.png differ diff --git a/src/assistant/tools/assistant/images/assistant.png b/src/assistant/tools/assistant/images/assistant.png new file mode 100644 index 000000000..ea4d1e70c Binary files /dev/null and b/src/assistant/tools/assistant/images/assistant.png differ diff --git a/src/assistant/tools/assistant/images/bookmark.png b/src/assistant/tools/assistant/images/bookmark.png new file mode 100644 index 000000000..57e57e343 Binary files /dev/null and b/src/assistant/tools/assistant/images/bookmark.png differ diff --git a/src/assistant/tools/assistant/images/closebutton.png b/src/assistant/tools/assistant/images/closebutton.png new file mode 100644 index 000000000..c978cf51a Binary files /dev/null and b/src/assistant/tools/assistant/images/closebutton.png differ diff --git a/src/assistant/tools/assistant/images/darkclosebutton.png b/src/assistant/tools/assistant/images/darkclosebutton.png new file mode 100644 index 000000000..1077663b2 Binary files /dev/null and b/src/assistant/tools/assistant/images/darkclosebutton.png differ diff --git a/src/assistant/tools/assistant/images/mac/addtab.png b/src/assistant/tools/assistant/images/mac/addtab.png new file mode 100644 index 000000000..20928fb40 Binary files /dev/null and b/src/assistant/tools/assistant/images/mac/addtab.png differ diff --git a/src/assistant/tools/assistant/images/mac/book.png b/src/assistant/tools/assistant/images/mac/book.png new file mode 100644 index 000000000..7a3204c87 Binary files /dev/null and b/src/assistant/tools/assistant/images/mac/book.png differ diff --git a/src/assistant/tools/assistant/images/mac/closetab.png b/src/assistant/tools/assistant/images/mac/closetab.png new file mode 100644 index 000000000..ab9d669ee Binary files /dev/null and b/src/assistant/tools/assistant/images/mac/closetab.png differ diff --git a/src/assistant/tools/assistant/images/mac/editcopy.png b/src/assistant/tools/assistant/images/mac/editcopy.png new file mode 100644 index 000000000..f55136446 Binary files /dev/null and b/src/assistant/tools/assistant/images/mac/editcopy.png differ diff --git a/src/assistant/tools/assistant/images/mac/find.png b/src/assistant/tools/assistant/images/mac/find.png new file mode 100644 index 000000000..3561745f0 Binary files /dev/null and b/src/assistant/tools/assistant/images/mac/find.png differ diff --git a/src/assistant/tools/assistant/images/mac/home.png b/src/assistant/tools/assistant/images/mac/home.png new file mode 100644 index 000000000..78d94da18 Binary files /dev/null and b/src/assistant/tools/assistant/images/mac/home.png differ diff --git a/src/assistant/tools/assistant/images/mac/next.png b/src/assistant/tools/assistant/images/mac/next.png new file mode 100644 index 000000000..a585cab80 Binary files /dev/null and b/src/assistant/tools/assistant/images/mac/next.png differ diff --git a/src/assistant/tools/assistant/images/mac/previous.png b/src/assistant/tools/assistant/images/mac/previous.png new file mode 100644 index 000000000..612fb34dc Binary files /dev/null and b/src/assistant/tools/assistant/images/mac/previous.png differ diff --git a/src/assistant/tools/assistant/images/mac/print.png b/src/assistant/tools/assistant/images/mac/print.png new file mode 100644 index 000000000..10ca56c82 Binary files /dev/null and b/src/assistant/tools/assistant/images/mac/print.png differ diff --git a/src/assistant/tools/assistant/images/mac/resetzoom.png b/src/assistant/tools/assistant/images/mac/resetzoom.png new file mode 100644 index 000000000..759b38296 Binary files /dev/null and b/src/assistant/tools/assistant/images/mac/resetzoom.png differ diff --git a/src/assistant/tools/assistant/images/mac/synctoc.png b/src/assistant/tools/assistant/images/mac/synctoc.png new file mode 100644 index 000000000..067fa941b Binary files /dev/null and b/src/assistant/tools/assistant/images/mac/synctoc.png differ diff --git a/src/assistant/tools/assistant/images/mac/zoomin.png b/src/assistant/tools/assistant/images/mac/zoomin.png new file mode 100644 index 000000000..d46f5aff0 Binary files /dev/null and b/src/assistant/tools/assistant/images/mac/zoomin.png differ diff --git a/src/assistant/tools/assistant/images/mac/zoomout.png b/src/assistant/tools/assistant/images/mac/zoomout.png new file mode 100644 index 000000000..46326566d Binary files /dev/null and b/src/assistant/tools/assistant/images/mac/zoomout.png differ diff --git a/src/assistant/tools/assistant/images/trolltech-logo.png b/src/assistant/tools/assistant/images/trolltech-logo.png new file mode 100644 index 000000000..c53e744ca Binary files /dev/null and b/src/assistant/tools/assistant/images/trolltech-logo.png differ diff --git a/src/assistant/tools/assistant/images/win/addtab.png b/src/assistant/tools/assistant/images/win/addtab.png new file mode 100644 index 000000000..4bb0feb92 Binary files /dev/null and b/src/assistant/tools/assistant/images/win/addtab.png differ diff --git a/src/assistant/tools/assistant/images/win/book.png b/src/assistant/tools/assistant/images/win/book.png new file mode 100644 index 000000000..09ec4d33f Binary files /dev/null and b/src/assistant/tools/assistant/images/win/book.png differ diff --git a/src/assistant/tools/assistant/images/win/closetab.png b/src/assistant/tools/assistant/images/win/closetab.png new file mode 100644 index 000000000..ef9e02086 Binary files /dev/null and b/src/assistant/tools/assistant/images/win/closetab.png differ diff --git a/src/assistant/tools/assistant/images/win/editcopy.png b/src/assistant/tools/assistant/images/win/editcopy.png new file mode 100644 index 000000000..1121b47d8 Binary files /dev/null and b/src/assistant/tools/assistant/images/win/editcopy.png differ diff --git a/src/assistant/tools/assistant/images/win/find.png b/src/assistant/tools/assistant/images/win/find.png new file mode 100644 index 000000000..6ea35e930 Binary files /dev/null and b/src/assistant/tools/assistant/images/win/find.png differ diff --git a/src/assistant/tools/assistant/images/win/home.png b/src/assistant/tools/assistant/images/win/home.png new file mode 100644 index 000000000..b1c6ae191 Binary files /dev/null and b/src/assistant/tools/assistant/images/win/home.png differ diff --git a/src/assistant/tools/assistant/images/win/next.png b/src/assistant/tools/assistant/images/win/next.png new file mode 100644 index 000000000..8df4127a0 Binary files /dev/null and b/src/assistant/tools/assistant/images/win/next.png differ diff --git a/src/assistant/tools/assistant/images/win/previous.png b/src/assistant/tools/assistant/images/win/previous.png new file mode 100644 index 000000000..0780bc23d Binary files /dev/null and b/src/assistant/tools/assistant/images/win/previous.png differ diff --git a/src/assistant/tools/assistant/images/win/print.png b/src/assistant/tools/assistant/images/win/print.png new file mode 100644 index 000000000..ba7c02dc1 Binary files /dev/null and b/src/assistant/tools/assistant/images/win/print.png differ diff --git a/src/assistant/tools/assistant/images/win/resetzoom.png b/src/assistant/tools/assistant/images/win/resetzoom.png new file mode 100644 index 000000000..b69ae4e7f Binary files /dev/null and b/src/assistant/tools/assistant/images/win/resetzoom.png differ diff --git a/src/assistant/tools/assistant/images/win/synctoc.png b/src/assistant/tools/assistant/images/win/synctoc.png new file mode 100644 index 000000000..da301bc59 Binary files /dev/null and b/src/assistant/tools/assistant/images/win/synctoc.png differ diff --git a/src/assistant/tools/assistant/images/win/zoomin.png b/src/assistant/tools/assistant/images/win/zoomin.png new file mode 100644 index 000000000..2e586fc7b Binary files /dev/null and b/src/assistant/tools/assistant/images/win/zoomin.png differ diff --git a/src/assistant/tools/assistant/images/win/zoomout.png b/src/assistant/tools/assistant/images/win/zoomout.png new file mode 100644 index 000000000..a736d3934 Binary files /dev/null and b/src/assistant/tools/assistant/images/win/zoomout.png differ diff --git a/src/assistant/tools/assistant/images/wrap.png b/src/assistant/tools/assistant/images/wrap.png new file mode 100644 index 000000000..90f18d9f7 Binary files /dev/null and b/src/assistant/tools/assistant/images/wrap.png differ diff --git a/src/assistant/tools/assistant/indexwindow.cpp b/src/assistant/tools/assistant/indexwindow.cpp new file mode 100644 index 000000000..38bc8b96a --- /dev/null +++ b/src/assistant/tools/assistant/indexwindow.cpp @@ -0,0 +1,231 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "indexwindow.h" + +#include "centralwidget.h" +#include "helpenginewrapper.h" +#include "helpviewer.h" +#include "openpagesmanager.h" +#include "topicchooser.h" +#include "tracer.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +IndexWindow::IndexWindow(QWidget *parent) + : QWidget(parent) + , m_searchLineEdit(new QLineEdit) + , m_indexWidget(HelpEngineWrapper::instance().indexWidget()) +{ + TRACE_OBJ + QVBoxLayout *layout = new QVBoxLayout(this); + QLabel *l = new QLabel(tr("&Look for:")); + layout->addWidget(l); + + l->setBuddy(m_searchLineEdit); + connect(m_searchLineEdit, SIGNAL(textChanged(QString)), this, + SLOT(filterIndices(QString))); + m_searchLineEdit->installEventFilter(this); + layout->setMargin(4); + layout->addWidget(m_searchLineEdit); + + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + m_indexWidget->installEventFilter(this); + connect(helpEngine.indexModel(), SIGNAL(indexCreationStarted()), this, + SLOT(disableSearchLineEdit())); + connect(helpEngine.indexModel(), SIGNAL(indexCreated()), this, + SLOT(enableSearchLineEdit())); + connect(m_indexWidget, SIGNAL(linkActivated(QUrl,QString)), this, + SIGNAL(linkActivated(QUrl))); + connect(m_indexWidget, SIGNAL(linksActivated(QMap,QString)), + this, SIGNAL(linksActivated(QMap,QString))); + connect(m_searchLineEdit, SIGNAL(returnPressed()), m_indexWidget, + SLOT(activateCurrentItem())); + layout->addWidget(m_indexWidget); + + m_indexWidget->viewport()->installEventFilter(this); +} + +IndexWindow::~IndexWindow() +{ + TRACE_OBJ +} + +void IndexWindow::filterIndices(const QString &filter) +{ + TRACE_OBJ + if (filter.contains(QLatin1Char('*'))) + m_indexWidget->filterIndices(filter, filter); + else + m_indexWidget->filterIndices(filter, QString()); +} + +bool IndexWindow::eventFilter(QObject *obj, QEvent *e) +{ + TRACE_OBJ + if (obj == m_searchLineEdit && e->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast(e); + QModelIndex idx = m_indexWidget->currentIndex(); + switch (ke->key()) { + case Qt::Key_Up: + idx = m_indexWidget->model()->index(idx.row()-1, + idx.column(), idx.parent()); + if (idx.isValid()) { + m_indexWidget->setCurrentIndex(idx); + return true; + } + break; + case Qt::Key_Down: + idx = m_indexWidget->model()->index(idx.row()+1, + idx.column(), idx.parent()); + if (idx.isValid()) { + m_indexWidget->setCurrentIndex(idx); + return true; + } + break; + case Qt::Key_Escape: + emit escapePressed(); + return true; + default: ; // stop complaining + } + } else if (obj == m_indexWidget && e->type() == QEvent::ContextMenu) { + QContextMenuEvent *ctxtEvent = static_cast(e); + QModelIndex idx = m_indexWidget->indexAt(ctxtEvent->pos()); + if (idx.isValid()) { + QMenu menu; + QAction *curTab = menu.addAction(tr("Open Link")); + QAction *newTab = menu.addAction(tr("Open Link in New Tab")); + menu.move(m_indexWidget->mapToGlobal(ctxtEvent->pos())); + + QAction *action = menu.exec(); + if (curTab == action) + m_indexWidget->activateCurrentItem(); + else if (newTab == action) { + open(m_indexWidget, idx); + } + } + } else if (m_indexWidget && obj == m_indexWidget->viewport() + && e->type() == QEvent::MouseButtonRelease) { + QMouseEvent *mouseEvent = static_cast(e); + QModelIndex idx = m_indexWidget->indexAt(mouseEvent->pos()); + if (idx.isValid()) { + Qt::MouseButtons button = mouseEvent->button(); + if (((button == Qt::LeftButton) && (mouseEvent->modifiers() & Qt::ControlModifier)) + || (button == Qt::MidButton)) { + open(m_indexWidget, idx); + } + } + } +#ifdef Q_OS_MAC + else if (obj == m_indexWidget && e->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast(e); + if (ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter) + m_indexWidget->activateCurrentItem(); + } +#endif + return QWidget::eventFilter(obj, e); +} + +void IndexWindow::enableSearchLineEdit() +{ + TRACE_OBJ + m_searchLineEdit->setDisabled(false); + filterIndices(m_searchLineEdit->text()); +} + +void IndexWindow::disableSearchLineEdit() +{ + TRACE_OBJ + m_searchLineEdit->setDisabled(true); +} + +void IndexWindow::setSearchLineEditText(const QString &text) +{ + TRACE_OBJ + m_searchLineEdit->setText(text); +} + +void IndexWindow::focusInEvent(QFocusEvent *e) +{ + TRACE_OBJ + if (e->reason() != Qt::MouseFocusReason) { + m_searchLineEdit->selectAll(); + m_searchLineEdit->setFocus(); + } +} + +void IndexWindow::open(QHelpIndexWidget* indexWidget, const QModelIndex &index) +{ + TRACE_OBJ + QHelpIndexModel *model = qobject_cast(indexWidget->model()); + if (model) { + QString keyword = model->data(index, Qt::DisplayRole).toString(); + QMap links = model->linksForKeyword(keyword); + + QUrl url; + if (links.count() > 1) { + TopicChooser tc(this, keyword, links); + if (tc.exec() == QDialog::Accepted) + url = tc.link(); + } else if (links.count() == 1) { + url = links.constBegin().value(); + } else { + return; + } + + if (!HelpViewer::canOpenPage(url.path())) + CentralWidget::instance()->setSource(url); + else + OpenPagesManager::instance()->createPage(url); + } +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/indexwindow.h b/src/assistant/tools/assistant/indexwindow.h new file mode 100644 index 000000000..6c1c4e14e --- /dev/null +++ b/src/assistant/tools/assistant/indexwindow.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef INDEXWINDOW_H +#define INDEXWINDOW_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QHelpIndexWidget; +class QModelIndex; + +class IndexWindow : public QWidget +{ + Q_OBJECT + +public: + IndexWindow(QWidget *parent = 0); + ~IndexWindow(); + + void setSearchLineEditText(const QString &text); + QString searchLineEditText() const + { + return m_searchLineEdit->text(); + } + +signals: + void linkActivated(const QUrl &link); + void linksActivated(const QMap &links, + const QString &keyword); + void escapePressed(); + +private slots: + void filterIndices(const QString &filter); + void enableSearchLineEdit(); + void disableSearchLineEdit(); + +private: + bool eventFilter(QObject *obj, QEvent *e); + void focusInEvent(QFocusEvent *e); + void open(QHelpIndexWidget *indexWidget, const QModelIndex &index); + + QLineEdit *m_searchLineEdit; + QHelpIndexWidget *m_indexWidget; +}; + +QT_END_NAMESPACE + +#endif // INDEXWINDOW_H diff --git a/src/assistant/tools/assistant/installdialog.cpp b/src/assistant/tools/assistant/installdialog.cpp new file mode 100644 index 000000000..29473a2f9 --- /dev/null +++ b/src/assistant/tools/assistant/installdialog.cpp @@ -0,0 +1,355 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "tracer.h" + +#include "installdialog.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +QT_BEGIN_NAMESPACE +#ifndef QT_NO_HTTP + +#define QCH_FILENAME 92943 +#define QCH_NAMESPACE 92944 +#define QCH_CHECKSUM 92945 + +InstallDialog::InstallDialog(QHelpEngineCore *helpEngine, QWidget *parent, + const QString &host, int port) + : QDialog(parent), m_helpEngine(helpEngine), m_host(host), m_port(port) +{ + TRACE_OBJ + m_ui.setupUi(this); + + m_ui.installButton->setEnabled(false); + m_ui.cancelButton->setEnabled(false); + m_ui.pathLineEdit->setText(QFileInfo(m_helpEngine->collectionFile()).absolutePath()); + m_ui.progressBar->hide(); + + m_windowTitle = tr("Install Documentation"); + + m_http = new QHttp(this); + connect(m_http, SIGNAL(requestFinished(int,bool)), + this, SLOT(httpRequestFinished(int,bool))); + connect(m_http, SIGNAL(dataReadProgress(int,int)), + this, SLOT(updateDataReadProgress(int,int))); + connect(m_http, SIGNAL(responseHeaderReceived(QHttpResponseHeader)), + this, SLOT(readResponseHeader(QHttpResponseHeader))); + connect(m_ui.installButton, SIGNAL(clicked()), this, SLOT(install())); + connect(m_ui.cancelButton, SIGNAL(clicked()), this, SLOT(cancelDownload())); + connect(m_ui.browseButton, SIGNAL(clicked()), this, SLOT(browseDirectories())); + + connect(m_ui.listWidget, SIGNAL(itemChanged(QListWidgetItem*)), + this, SLOT(updateInstallButton())); + + QTimer::singleShot(0, this, SLOT(init())); +} + +InstallDialog::~InstallDialog() +{ + TRACE_OBJ +} + +QStringList InstallDialog::installedDocumentations() const +{ + TRACE_OBJ + return m_installedDocumentations; +} + +void InstallDialog::init() +{ + TRACE_OBJ + m_ui.statusLabel->setText(tr("Downloading documentation info...")); + m_ui.progressBar->show(); + + QUrl url(QLatin1String("http://qt.nokia.com/doc/assistantdocs/docs.txt")); + m_buffer = new QBuffer(); + m_buffer->open(QBuffer::ReadWrite); + + if (m_port > -1) + m_http->setProxy(m_host, m_port); + m_http->setHost(url.host()); + m_httpAborted = false; + m_docInfoId = m_http->get(url.path(), m_buffer); + + m_ui.cancelButton->setEnabled(true); + m_ui.closeButton->setEnabled(false); +} + +void InstallDialog::updateInstallButton() +{ + TRACE_OBJ + QListWidgetItem *item = 0; + for (int i=0; icount(); ++i) { + item = m_ui.listWidget->item(i); + if (item->checkState() == Qt::Checked + && item->flags() & Qt::ItemIsEnabled) { + m_ui.installButton->setEnabled(true); + return; + } + } + m_ui.installButton->setEnabled(false); +} + +void InstallDialog::updateDocItemList() +{ + TRACE_OBJ + QStringList registeredDocs = m_helpEngine->registeredDocumentations(); + QListWidgetItem *item = 0; + for (int i=0; icount(); ++i) { + item = m_ui.listWidget->item(i); + QString ns = item->data(QCH_NAMESPACE).toString(); + if (!ns.isEmpty() && registeredDocs.contains(ns)) { + item->setFlags(Qt::ItemIsUserCheckable); + item->setCheckState(Qt::Checked); + } + item->setCheckState(Qt::Unchecked); + } +} + +void InstallDialog::cancelDownload() +{ + TRACE_OBJ + m_ui.statusLabel->setText(tr("Download canceled.")); + m_httpAborted = true; + m_itemsToInstall.clear(); + m_http->abort(); + m_ui.cancelButton->setEnabled(false); + m_ui.closeButton->setEnabled(true); + updateInstallButton(); +} + +void InstallDialog::install() +{ + TRACE_OBJ + QListWidgetItem *item = 0; + for (int i=0; icount(); ++i) { + item = m_ui.listWidget->item(i); + if (item->checkState() == Qt::Checked) + m_itemsToInstall.append(item); + } + m_ui.installButton->setEnabled(false); + downloadNextFile(); +} + +void InstallDialog::downloadNextFile() +{ + TRACE_OBJ + if (!m_itemsToInstall.count()) { + m_ui.cancelButton->setEnabled(false); + m_ui.closeButton->setEnabled(true); + m_ui.statusLabel->setText(tr("Done.")); + m_ui.progressBar->hide(); + updateDocItemList(); + updateInstallButton(); + return; + } + + QListWidgetItem *item = m_itemsToInstall.dequeue(); + m_currentCheckSum = item->data(QCH_CHECKSUM).toString(); + QString fileName = item->data(QCH_FILENAME).toString(); + QString saveFileName = m_ui.pathLineEdit->text() + QDir::separator() + + fileName; + + if (QFile::exists(saveFileName) + && QMessageBox::information(this, m_windowTitle, + tr("The file %1 already exists. Do you want to overwrite it?") + .arg(saveFileName), QMessageBox::Yes | QMessageBox::No, + QMessageBox::Yes) == QMessageBox::No) { + installFile(saveFileName); + downloadNextFile(); + return; + } + + m_file = new QFile(saveFileName); + if (!m_file->open(QIODevice::WriteOnly|QIODevice::Truncate)) { + QMessageBox::information(this, m_windowTitle, + tr("Unable to save the file %1: %2.") + .arg(saveFileName).arg(m_file->errorString())); + delete m_file; + m_file = 0; + downloadNextFile(); + return; + } + + m_ui.statusLabel->setText(tr("Downloading %1...").arg(fileName)); + m_ui.progressBar->show(); + + QLatin1String urlStr("http://qt.nokia.com/doc/assistantdocs/%1"); + QUrl url(QString(urlStr).arg(fileName)); + + m_httpAborted = false; + m_docId = m_http->get(url.path(), m_file); + + m_ui.cancelButton->setEnabled(true); + m_ui.closeButton->setEnabled(false); +} + +void InstallDialog::httpRequestFinished(int requestId, bool error) +{ + TRACE_OBJ + if (requestId == m_docInfoId && m_buffer) { + m_ui.progressBar->hide(); + if (error) { + QMessageBox::information(this, m_windowTitle, + tr("Download failed: %1.") + .arg(m_http->errorString())); + } else if (!m_httpAborted) { + QStringList registeredDocs = m_helpEngine->registeredDocumentations(); + m_buffer->seek(0); + while (m_buffer->canReadLine()) { + QByteArray ba = m_buffer->readLine(); + QStringList lst = QString::fromAscii(ba.constData()).split(QLatin1Char('|')); + if (lst.count() != 4) { + QMessageBox::information(this, m_windowTitle, + tr("Documentation info file is corrupt!")); + } else { + QListWidgetItem *item = new QListWidgetItem(m_ui.listWidget); + item->setText(lst.at(2).trimmed()); + item->setData(QCH_FILENAME, lst.first()); + item->setData(QCH_NAMESPACE, lst.at(1)); + item->setData(QCH_CHECKSUM, lst.last().trimmed()); + } + } + updateDocItemList(); + } + if (m_buffer) + m_buffer->close(); + delete m_buffer; + m_buffer = 0; + m_ui.statusLabel->setText(tr("Done.")); + m_ui.cancelButton->setEnabled(false); + m_ui.closeButton->setEnabled(true); + updateInstallButton(); + } else if (requestId == m_docId) { + m_file->close(); + if (!m_httpAborted) { + QString checkSum; + if (m_file->open(QIODevice::ReadOnly)) { + QByteArray digest = QCryptographicHash::hash(m_file->readAll(), + QCryptographicHash::Md5); + m_file->close(); + checkSum = QString::fromLatin1(digest.toHex()); + } + if (error) { + m_file->remove(); + QMessageBox::warning(this, m_windowTitle, + tr("Download failed: %1.") + .arg(m_http->errorString())); + } else if (checkSum.isEmpty() || m_currentCheckSum != checkSum) { + m_file->remove(); + QMessageBox::warning(this, m_windowTitle, + tr("Download failed: Downloaded file is corrupted.")); + } else { + m_ui.statusLabel->setText(tr("Installing documentation %1...") + .arg(QFileInfo(m_file->fileName()).fileName())); + m_ui.progressBar->setMaximum(0); + m_ui.statusLabel->setText(tr("Done.")); + installFile(m_file->fileName()); + } + } else { + m_file->remove(); + } + delete m_file; + m_file = 0; + downloadNextFile(); + } +} + +void InstallDialog::installFile(const QString &fileName) +{ + TRACE_OBJ + if (m_helpEngine->registerDocumentation(fileName)) { + m_installedDocumentations + .append(QHelpEngineCore::namespaceName(fileName)); + } else { + QMessageBox::information(this, m_windowTitle, + tr("Error while installing documentation:\n%1") + .arg(m_helpEngine->error())); + } +} + +void InstallDialog::readResponseHeader(const QHttpResponseHeader &responseHeader) +{ + TRACE_OBJ + if (responseHeader.statusCode() != 200) { + QMessageBox::information(this, m_windowTitle, + tr("Download failed: %1.") + .arg(responseHeader.reasonPhrase())); + m_httpAborted = true; + m_ui.progressBar->hide(); + m_http->abort(); + return; + } +} + +void InstallDialog::updateDataReadProgress(int bytesRead, int totalBytes) +{ + TRACE_OBJ + if (m_httpAborted) + return; + + m_ui.progressBar->setMaximum(totalBytes); + m_ui.progressBar->setValue(bytesRead); +} + +void InstallDialog::browseDirectories() +{ + TRACE_OBJ + QString dir = QFileDialog::getExistingDirectory(this, m_windowTitle, + m_ui.pathLineEdit->text()); + if (!dir.isEmpty()) + m_ui.pathLineEdit->setText(dir); +} + +#endif +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/installdialog.h b/src/assistant/tools/assistant/installdialog.h new file mode 100644 index 000000000..0fb45a130 --- /dev/null +++ b/src/assistant/tools/assistant/installdialog.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef INSTALLDIALOG_H +#define INSTALLDIALOG_H + +#include +#include +#include +#include "ui_installdialog.h" + +#ifndef QT_NO_HTTP + +QT_BEGIN_NAMESPACE + +class QHttp; +class QBuffer; +class QFile; +class QHelpEngineCore; + +class InstallDialog : public QDialog +{ + Q_OBJECT + +public: + explicit InstallDialog(QHelpEngineCore *helpEngine, QWidget *parent = 0, + const QString &host = QString(), int port = -1); + ~InstallDialog(); + + QStringList installedDocumentations() const; + +private slots: + void init(); + void cancelDownload(); + void install(); + void httpRequestFinished(int requestId, bool error); + void readResponseHeader(const QHttpResponseHeader &responseHeader); + void updateDataReadProgress(int bytesRead, int totalBytes); + void updateInstallButton(); + void browseDirectories(); + +private: + void downloadNextFile(); + void updateDocItemList(); + void installFile(const QString &fileName); + + Ui::InstallDialog m_ui; + QHelpEngineCore *m_helpEngine; + QHttp *m_http; + QBuffer *m_buffer; + QFile *m_file; + bool m_httpAborted; + int m_docInfoId; + int m_docId; + QQueue m_itemsToInstall; + QString m_currentCheckSum; + QString m_windowTitle; + QStringList m_installedDocumentations; + QString m_host; + int m_port; +}; + +QT_END_NAMESPACE + +#endif + +#endif // INSTALLDIALOG_H diff --git a/src/assistant/tools/assistant/installdialog.ui b/src/assistant/tools/assistant/installdialog.ui new file mode 100644 index 000000000..21a05da77 --- /dev/null +++ b/src/assistant/tools/assistant/installdialog.ui @@ -0,0 +1,118 @@ + + InstallDialog + + + + 0 + 0 + 436 + 245 + + + + Install Documentation + + + + + + Available Documentation: + + + + + + + + + + Install + + + + + + + Cancel + + + + + + + Close + + + + + + + Qt::Vertical + + + + 20 + 56 + + + + + + + + Installation Path: + + + + + + + + + + ... + + + + + + + Qt::Horizontal + + + + + + + + + + 0 + + + Qt::Horizontal + + + + + + + + + closeButton + clicked() + InstallDialog + accept() + + + 330 + 107 + + + 332 + 158 + + + + + diff --git a/src/assistant/tools/assistant/main.cpp b/src/assistant/tools/assistant/main.cpp new file mode 100644 index 000000000..84972c546 --- /dev/null +++ b/src/assistant/tools/assistant/main.cpp @@ -0,0 +1,440 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "tracer.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include "../shared/collectionconfiguration.h" +#include "helpenginewrapper.h" +#include "mainwindow.h" +#include "cmdlineparser.h" + +// #define TRACING_REQUESTED + +QT_USE_NAMESPACE + +#if defined(USE_STATIC_SQLITE_PLUGIN) + #include + Q_IMPORT_PLUGIN(qsqlite) +#endif + +namespace { + +void +updateLastPagesOnUnregister(QHelpEngineCore& helpEngine, const QString& nsName) +{ + TRACE_OBJ + int lastPage = CollectionConfiguration::lastTabPage(helpEngine); + QStringList currentPages = CollectionConfiguration::lastShownPages(helpEngine); + if (!currentPages.isEmpty()) { + QStringList zoomList = CollectionConfiguration::lastZoomFactors(helpEngine); + while (zoomList.count() < currentPages.count()) + zoomList.append(CollectionConfiguration::DefaultZoomFactor); + + for (int i = currentPages.count(); --i >= 0;) { + if (QUrl(currentPages.at(i)).host() == nsName) { + zoomList.removeAt(i); + currentPages.removeAt(i); + lastPage = (lastPage == (i + 1)) ? 1 : lastPage; + } + } + + CollectionConfiguration::setLastShownPages(helpEngine, currentPages); + CollectionConfiguration::setLastTabPage(helpEngine, lastPage); + CollectionConfiguration::setLastZoomFactors(helpEngine, zoomList); + } +} + +bool +updateUserCollection(QHelpEngineCore& user, const QHelpEngineCore& caller) +{ + TRACE_OBJ + if (!CollectionConfiguration::isNewer(caller, user)) + return false; + CollectionConfiguration::copyConfiguration(caller, user); + return true; +} + +void stripNonexistingDocs(QHelpEngineCore& collection) +{ + TRACE_OBJ + const QStringList &namespaces = collection.registeredDocumentations(); + foreach (const QString &ns, namespaces) { + QFileInfo fi(collection.documentationFileName(ns)); + if (!fi.exists() || !fi.isFile()) + collection.unregisterDocumentation(ns); + } +} + +QString indexFilesFolder(const QString &collectionFile) +{ + TRACE_OBJ + QString indexFilesFolder = QLatin1String(".fulltextsearch"); + if (!collectionFile.isEmpty()) { + QFileInfo fi(collectionFile); + indexFilesFolder = QLatin1Char('.') + + fi.fileName().left(fi.fileName().lastIndexOf(QLatin1String(".qhc"))); + } + return indexFilesFolder; +} + +/* + * Returns the expected absolute file path of the cached collection file + * correspondinging to the given collection's file. + * It may or may not exist yet. + */ +QString constructCachedCollectionFilePath(const QHelpEngineCore &collection) +{ + TRACE_OBJ + const QString &filePath = collection.collectionFile(); + const QString &fileName = QFileInfo(filePath).fileName(); + const QString &cacheDir = CollectionConfiguration::cacheDir(collection); + const QString &dir = !cacheDir.isEmpty() + && CollectionConfiguration::cacheDirIsRelativeToCollection(collection) + ? QFileInfo(filePath).dir().absolutePath() + + QDir::separator() + cacheDir + : MainWindow::collectionFileDirectory(false, cacheDir); + return dir + QDir::separator() + fileName; +} + +bool synchronizeDocs(QHelpEngineCore &collection, + QHelpEngineCore &cachedCollection, + CmdLineParser &cmd) +{ + TRACE_OBJ + const QDateTime &lastCollectionRegisterTime = + CollectionConfiguration::lastRegisterTime(collection); + if (!lastCollectionRegisterTime.isValid() || lastCollectionRegisterTime + < CollectionConfiguration::lastRegisterTime(cachedCollection)) + return true; + + const QStringList &docs = collection.registeredDocumentations(); + const QStringList &cachedDocs = cachedCollection.registeredDocumentations(); + + /* + * Ensure that the cached collection contains all docs that + * the collection contains. + */ + foreach (const QString &doc, docs) { + if (!cachedDocs.contains(doc)) { + const QString &docFile = collection.documentationFileName(doc); + if (!cachedCollection.registerDocumentation(docFile)) { + cmd.showMessage(QCoreApplication::translate("Assistant", + "Error registering documentation file '%1': %2"). + arg(docFile).arg(cachedCollection.error()), true); + return false; + } + } + } + + CollectionConfiguration::updateLastRegisterTime(cachedCollection); + + return true; +} + +bool removeSearchIndex(const QString &collectionFile) +{ + TRACE_OBJ + QString path = QFileInfo(collectionFile).path(); + path += QLatin1Char('/') + indexFilesFolder(collectionFile); + + QLocalSocket localSocket; + localSocket.connectToServer(QString(QLatin1String("QtAssistant%1")) + .arg(QLatin1String(QT_VERSION_STR))); + + QDir dir(path); // check if there is no other instance ruinning + if (!dir.exists() || localSocket.waitForConnected()) + return false; + + QStringList lst = dir.entryList(QDir::Files | QDir::Hidden); + foreach (const QString &item, lst) + dir.remove(item); + return true; +} + +bool rebuildSearchIndex(QCoreApplication &app, const QString &collectionFile, + CmdLineParser &cmd) +{ + TRACE_OBJ + QHelpEngine engine(collectionFile); + if (!engine.setupData()) { + cmd.showMessage(QCoreApplication::translate("Assistant", "Error: %1") + .arg(engine.error()), true); + return false; + } + + QHelpSearchEngine * const searchEngine = engine.searchEngine(); + QObject::connect(searchEngine, SIGNAL(indexingFinished()), &app, + SLOT(quit())); + searchEngine->reindexDocumentation(); + return app.exec() == 0; +} + +bool useGui(int argc, char *argv[]) +{ + TRACE_OBJ + bool gui = true; +#ifndef Q_OS_WIN + // Look for arguments that imply command-line mode. + const char * cmdModeArgs[] = { + "-help", "-register", "-unregister", "-remove-search-index", + "-rebuild-search-index" + }; + for (int i = 1; i < argc; ++i) { + for (size_t j = 0; j < sizeof cmdModeArgs/sizeof *cmdModeArgs; ++j) { + if(strcmp(argv[i], cmdModeArgs[j]) == 0) { + gui = false; + break; + } + } + } +#else + Q_UNUSED(argc) + Q_UNUSED(argv) +#endif + return gui; +} + +bool registerDocumentation(QHelpEngineCore &collection, CmdLineParser &cmd, + bool printSuccess) +{ + TRACE_OBJ + if (!collection.registerDocumentation(cmd.helpFile())) { + cmd.showMessage(QCoreApplication::translate("Assistant", + "Could not register documentation file\n%1\n\nReason:\n%2") + .arg(cmd.helpFile()).arg(collection.error()), true); + return false; + } + if (printSuccess) + cmd.showMessage(QCoreApplication::translate("Assistant", + "Documentation successfully registered."), + false); + CollectionConfiguration::updateLastRegisterTime(collection); + return true; +} + +bool unregisterDocumentation(QHelpEngineCore &collection, + const QString &namespaceName, CmdLineParser &cmd, bool printSuccess) +{ + TRACE_OBJ + if (!collection.unregisterDocumentation(namespaceName)) { + cmd.showMessage(QCoreApplication::translate("Assistant", + "Could not unregister documentation" + " file\n%1\n\nReason:\n%2"). + arg(cmd.helpFile()).arg(collection.error()), true); + return false; + } + updateLastPagesOnUnregister(collection, namespaceName); + if (printSuccess) + cmd.showMessage(QCoreApplication::translate("Assistant", + "Documentation successfully unregistered."), + false); + return true; +} + +void setupTranslation(const QString &fileName, const QString &dir) +{ + QTranslator *translator = new QTranslator(QCoreApplication::instance()); + if (translator->load(fileName, dir)) { + QCoreApplication::installTranslator(translator); + } else if (!fileName.endsWith(QLatin1String("en_US")) + && !fileName.endsWith(QLatin1String("_C"))) { + qWarning("Could not load translation file %s in directory %s.", + qPrintable(fileName), qPrintable(dir)); + } +} + +void setupTranslations() +{ + TRACE_OBJ + const QString& locale = QLocale::system().name(); + const QString &resourceDir + = QLibraryInfo::location(QLibraryInfo::TranslationsPath); + setupTranslation(QLatin1String("assistant_") + locale, resourceDir); + setupTranslation(QLatin1String("qt_") + locale, resourceDir); + setupTranslation(QLatin1String("qt_help_") + locale, resourceDir); +} + +} // Anonymous namespace. + +int main(int argc, char *argv[]) +{ + TRACE_OBJ + QApplication a(argc, argv, useGui(argc, argv)); + a.addLibraryPath(a.applicationDirPath() + QLatin1String("/plugins")); + setupTranslations(); + + // Parse arguments. + CmdLineParser cmd(a.arguments()); + CmdLineParser::Result res = cmd.parse(); + if (res == CmdLineParser::Help) + return 0; + else if (res == CmdLineParser::Error) + return -1; + + /* + * Create the collection objects that we need. We always have the + * cached collection file. Depending on whether the user specified + * one, we also may have an input collection file. + */ + const QString collectionFile = cmd.collectionFile(); + const bool collectionFileGiven = !collectionFile.isEmpty(); + QScopedPointer collection; + if (collectionFileGiven) { + collection.reset(new QHelpEngineCore(collectionFile)); + if (!collection->setupData()) { + cmd.showMessage(QCoreApplication::translate("Assistant", + "Error reading collection file '%1': %2."). + arg(collectionFile).arg(collection->error()), true); + return EXIT_FAILURE; + } + } + const QString &cachedCollectionFile = collectionFileGiven + ? constructCachedCollectionFilePath(*collection) + : MainWindow::defaultHelpCollectionFileName(); + if (collectionFileGiven && !QFileInfo(cachedCollectionFile).exists() + && !collection->copyCollectionFile(cachedCollectionFile)) { + cmd.showMessage(QCoreApplication::translate("Assistant", + "Error creating collection file '%1': %2."). + arg(cachedCollectionFile).arg(collection->error()), true); + return EXIT_FAILURE; + } + QHelpEngineCore cachedCollection(cachedCollectionFile); + if (!cachedCollection.setupData()) { + cmd.showMessage(QCoreApplication::translate("Assistant", + "Error reading collection file '%1': %2."). + arg(cachedCollectionFile). + arg(cachedCollection.error()), true); + return EXIT_FAILURE; + } + + stripNonexistingDocs(cachedCollection); + if (collectionFileGiven) { + if (CollectionConfiguration::isNewer(*collection, cachedCollection)) + CollectionConfiguration::copyConfiguration(*collection, + cachedCollection); + if (!synchronizeDocs(*collection, cachedCollection, cmd)) + return EXIT_FAILURE; + } + + if (cmd.registerRequest() != CmdLineParser::None) { + const QStringList &cachedDocs = + cachedCollection.registeredDocumentations(); + const QString &namespaceName = + QHelpEngineCore::namespaceName(cmd.helpFile()); + if (cmd.registerRequest() == CmdLineParser::Register) { + if (collectionFileGiven + && !registerDocumentation(*collection, cmd, true)) + return EXIT_FAILURE; + if (!cachedDocs.contains(namespaceName) + && !registerDocumentation(cachedCollection, cmd, !collectionFileGiven)) + return EXIT_FAILURE; + return EXIT_SUCCESS; + } + if (cmd.registerRequest() == CmdLineParser::Unregister) { + if (collectionFileGiven + && !unregisterDocumentation(*collection, namespaceName, cmd, true)) + return EXIT_FAILURE; + if (cachedDocs.contains(namespaceName) + && !unregisterDocumentation(cachedCollection, namespaceName, + cmd, !collectionFileGiven)) + return EXIT_FAILURE; + return EXIT_SUCCESS; + } + } + + if (cmd.removeSearchIndex()) { + return removeSearchIndex(cachedCollectionFile) + ? EXIT_SUCCESS : EXIT_FAILURE; + } + + if (cmd.rebuildSearchIndex()) { + return rebuildSearchIndex(a, cachedCollectionFile, cmd) + ? EXIT_SUCCESS : EXIT_FAILURE; + } + + if (!QSqlDatabase::isDriverAvailable(QLatin1String("QSQLITE"))) { + cmd.showMessage(QCoreApplication::translate("Assistant", + "Cannot load sqlite database driver!"), + true); + return EXIT_FAILURE; + } + + if (!cmd.currentFilter().isEmpty()) { + if (collectionFileGiven) + collection->setCurrentFilter(cmd.currentFilter()); + cachedCollection.setCurrentFilter(cmd.currentFilter()); + } + + if (collectionFileGiven) + cmd.setCollectionFile(cachedCollectionFile); + + MainWindow *w = new MainWindow(&cmd); + w->show(); + a.connect(&a, SIGNAL(lastWindowClosed()), &a, SLOT(quit())); + + /* + * We need to be careful here: The main window has to be deleted before + * the help engine wrapper, which has to be deleted before the + * QApplication. + */ + const int retval = a.exec(); + delete w; + HelpEngineWrapper::removeInstance(); + return retval; +} diff --git a/src/assistant/tools/assistant/mainwindow.cpp b/src/assistant/tools/assistant/mainwindow.cpp new file mode 100644 index 000000000..342fc76da --- /dev/null +++ b/src/assistant/tools/assistant/mainwindow.cpp @@ -0,0 +1,1099 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mainwindow.h" + +#include "aboutdialog.h" +#include "bookmarkmanager.h" +#include "centralwidget.h" +#include "cmdlineparser.h" +#include "contentwindow.h" +#include "globalactions.h" +#include "helpenginewrapper.h" +#include "indexwindow.h" +#include "openpagesmanager.h" +#include "preferencesdialog.h" +#include "qtdocinstaller.h" +#include "remotecontrol.h" +#include "searchwidget.h" +#include "topicchooser.h" +#include "tracer.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +MainWindow::MainWindow(CmdLineParser *cmdLine, QWidget *parent) + : QMainWindow(parent) + , m_bookmarkWidget(0) + , m_filterCombo(0) + , m_toolBarMenu(0) + , m_cmdLine(cmdLine) + , m_progressWidget(0) + , m_qtDocInstaller(0) + , m_connectedInitSignals(false) +{ + TRACE_OBJ + + setToolButtonStyle(Qt::ToolButtonFollowStyle); + setDockOptions(dockOptions() | AllowNestedDocks); + + QString collectionFile; + if (usesDefaultCollection()) { + MainWindow::collectionFileDirectory(true); + collectionFile = MainWindow::defaultHelpCollectionFileName(); + } else { + collectionFile = cmdLine->collectionFile(); + } + HelpEngineWrapper &helpEngineWrapper = + HelpEngineWrapper::instance(collectionFile); + BookmarkManager *bookMarkManager = BookmarkManager::instance(); + + if (!initHelpDB(!cmdLine->collectionFileGiven())) { + qDebug("Fatal error: Help engine initialization failed. " + "Error message was: %s\nAssistant will now exit.", + qPrintable(HelpEngineWrapper::instance().error())); + std::exit(1); + } + + m_centralWidget = new CentralWidget(this); + setCentralWidget(m_centralWidget); + + m_indexWindow = new IndexWindow(this); + QDockWidget *indexDock = new QDockWidget(tr("Index"), this); + indexDock->setObjectName(QLatin1String("IndexWindow")); + indexDock->setWidget(m_indexWindow); + addDockWidget(Qt::LeftDockWidgetArea, indexDock); + + m_contentWindow = new ContentWindow; + QDockWidget *contentDock = new QDockWidget(tr("Contents"), this); + contentDock->setObjectName(QLatin1String("ContentWindow")); + contentDock->setWidget(m_contentWindow); + addDockWidget(Qt::LeftDockWidgetArea, contentDock); + + m_searchWindow = new SearchWidget(helpEngineWrapper.searchEngine()); + m_searchWindow->setFont(!helpEngineWrapper.usesBrowserFont() ? qApp->font() + : helpEngineWrapper.browserFont()); + QDockWidget *searchDock = new QDockWidget(tr("Search"), this); + searchDock->setObjectName(QLatin1String("SearchWindow")); + searchDock->setWidget(m_searchWindow); + addDockWidget(Qt::LeftDockWidgetArea, searchDock); + + QDockWidget *bookmarkDock = new QDockWidget(tr("Bookmarks"), this); + bookmarkDock->setObjectName(QLatin1String("BookmarkWindow")); + bookmarkDock->setWidget(m_bookmarkWidget + = bookMarkManager->bookmarkDockWidget()); + addDockWidget(Qt::LeftDockWidgetArea, bookmarkDock); + + QDockWidget *openPagesDock = new QDockWidget(tr("Open Pages"), this); + openPagesDock->setObjectName(QLatin1String("Open Pages")); + OpenPagesManager *openPagesManager + = OpenPagesManager::createInstance(this, usesDefaultCollection(), m_cmdLine->url()); + openPagesDock->setWidget(openPagesManager->openPagesWidget()); + addDockWidget(Qt::LeftDockWidgetArea, openPagesDock); + + connect(m_centralWidget, SIGNAL(addBookmark(QString, QString)), + bookMarkManager, SLOT(addBookmark(QString, QString))); + connect(bookMarkManager, SIGNAL(escapePressed()), this, + SLOT(activateCurrentCentralWidgetTab())); + connect(bookMarkManager, SIGNAL(setSource(QUrl)), m_centralWidget, + SLOT(setSource(QUrl))); + connect(bookMarkManager, SIGNAL(setSourceInNewTab(QUrl)), + openPagesManager, SLOT(createPage(QUrl))); + + QHelpSearchEngine *searchEngine = helpEngineWrapper.searchEngine(); + connect(searchEngine, SIGNAL(indexingStarted()), this, SLOT(indexingStarted())); + connect(searchEngine, SIGNAL(indexingFinished()), this, SLOT(indexingFinished())); + + QString defWindowTitle = tr("Qt Assistant"); + setWindowTitle(defWindowTitle); + + setupActions(); + statusBar()->show(); + m_centralWidget->connectTabBar(); + + setupFilterToolbar(); + setupAddressToolbar(); + + const QString windowTitle = helpEngineWrapper.windowTitle(); + setWindowTitle(windowTitle.isEmpty() ? defWindowTitle : windowTitle); + QByteArray iconArray = helpEngineWrapper.applicationIcon(); + if (iconArray.size() > 0) { + QPixmap pix; + pix.loadFromData(iconArray); + QIcon appIcon(pix); + qApp->setWindowIcon(appIcon); + } else { + QIcon appIcon(QLatin1String(":/trolltech/assistant/images/assistant-128.png")); + qApp->setWindowIcon(appIcon); + } + + QToolBar *toolBar = addToolBar(tr("Bookmark Toolbar")); + toolBar->setObjectName(QLatin1String("Bookmark Toolbar")); + bookMarkManager->setBookmarksToolbar(toolBar); + + // Show the widget here, otherwise the restore geometry and state won't work + // on x11. + show(); + + toolBar->hide(); + toolBarMenu()->addAction(toolBar->toggleViewAction()); + + QByteArray ba(helpEngineWrapper.mainWindow()); + if (!ba.isEmpty()) + restoreState(ba); + + ba = helpEngineWrapper.mainWindowGeometry(); + if (!ba.isEmpty()) { + restoreGeometry(ba); + } else { + tabifyDockWidget(contentDock, indexDock); + tabifyDockWidget(indexDock, bookmarkDock); + tabifyDockWidget(bookmarkDock, searchDock); + contentDock->raise(); + const QRect screen = QApplication::desktop()->screenGeometry(); + resize(4*screen.width()/5, 4*screen.height()/5); + } + + if (!helpEngineWrapper.hasFontSettings()) { + helpEngineWrapper.setUseAppFont(false); + helpEngineWrapper.setUseBrowserFont(false); + helpEngineWrapper.setAppFont(qApp->font()); + helpEngineWrapper.setAppWritingSystem(QFontDatabase::Latin); + helpEngineWrapper.setBrowserFont(qApp->font()); + helpEngineWrapper.setBrowserWritingSystem(QFontDatabase::Latin); + } else { + updateApplicationFont(); + } + + updateAboutMenuText(); + + QTimer::singleShot(0, this, SLOT(insertLastPages())); + if (m_cmdLine->enableRemoteControl()) + (void)new RemoteControl(this); + + if (m_cmdLine->contents() == CmdLineParser::Show) + showContents(); + else if (m_cmdLine->contents() == CmdLineParser::Hide) + hideContents(); + + if (m_cmdLine->index() == CmdLineParser::Show) + showIndex(); + else if (m_cmdLine->index() == CmdLineParser::Hide) + hideIndex(); + + if (m_cmdLine->bookmarks() == CmdLineParser::Show) + showBookmarksDockWidget(); + else if (m_cmdLine->bookmarks() == CmdLineParser::Hide) + hideBookmarksDockWidget(); + + if (m_cmdLine->search() == CmdLineParser::Show) + showSearch(); + else if (m_cmdLine->search() == CmdLineParser::Hide) + hideSearch(); + + if (m_cmdLine->contents() == CmdLineParser::Activate) + showContents(); + else if (m_cmdLine->index() == CmdLineParser::Activate) + showIndex(); + else if (m_cmdLine->bookmarks() == CmdLineParser::Activate) + showBookmarksDockWidget(); + + if (!m_cmdLine->currentFilter().isEmpty()) { + const QString &curFilter = m_cmdLine->currentFilter(); + if (helpEngineWrapper.customFilters().contains(curFilter)) + helpEngineWrapper.setCurrentFilter(curFilter); + } + + if (usesDefaultCollection()) + QTimer::singleShot(0, this, SLOT(lookForNewQtDocumentation())); + else + checkInitState(); + + connect(&helpEngineWrapper, SIGNAL(documentationRemoved(QString)), + this, SLOT(documentationRemoved(QString))); + connect(&helpEngineWrapper, SIGNAL(documentationUpdated(QString)), + this, SLOT(documentationUpdated(QString))); + + setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North); + GlobalActions::instance()->updateActions(); + if (helpEngineWrapper.addressBarEnabled()) + showNewAddress(); +} + +MainWindow::~MainWindow() +{ + TRACE_OBJ + if (m_qtDocInstaller) + delete m_qtDocInstaller; +} + +bool MainWindow::usesDefaultCollection() const +{ + TRACE_OBJ + return m_cmdLine->collectionFile().isEmpty(); +} + +void MainWindow::closeEvent(QCloseEvent *e) +{ + TRACE_OBJ + BookmarkManager::destroy(); + HelpEngineWrapper::instance().setMainWindow(saveState()); + HelpEngineWrapper::instance().setMainWindowGeometry(saveGeometry()); + QMainWindow::closeEvent(e); +} + +bool MainWindow::initHelpDB(bool registerInternalDoc) +{ + TRACE_OBJ + HelpEngineWrapper &helpEngineWrapper = HelpEngineWrapper::instance(); + if (!helpEngineWrapper.setupData()) + return false; + + if (!registerInternalDoc) { + if (helpEngineWrapper.defaultHomePage() == QLatin1String("help")) + helpEngineWrapper.setDefaultHomePage(QLatin1String("about:blank")); + return true; + } + bool assistantInternalDocRegistered = false; + QString intern(QLatin1String("com.trolltech.com.assistantinternal-")); + foreach (const QString &ns, helpEngineWrapper.registeredDocumentations()) { + if (ns.startsWith(intern)) { + intern = ns; + assistantInternalDocRegistered = true; + break; + } + } + + const QString &collectionFile = helpEngineWrapper.collectionFile(); + QFileInfo fi(collectionFile); + QString helpFile; + QTextStream(&helpFile) << fi.absolutePath() << QDir::separator() + << QLatin1String("assistant.qch.") << (QT_VERSION >> 16) + << QLatin1Char('.') << ((QT_VERSION >> 8) & 0xFF); + + bool needsSetup = false; + if (!assistantInternalDocRegistered || !QFile::exists(helpFile)) { + QFile file(helpFile); + if (file.open(QIODevice::WriteOnly)) { + QResource res(QLatin1String(":/trolltech/assistant/assistant.qch")); + if (file.write((const char*)res.data(), res.size()) != res.size()) + qDebug() << QLatin1String("could not write assistant.qch..."); + + file.close(); + } + helpEngineWrapper.unregisterDocumentation(intern); + helpEngineWrapper.registerDocumentation(helpFile); + needsSetup = true; + } + + if (needsSetup) + helpEngineWrapper.setupData(); + return true; +} + +void MainWindow::lookForNewQtDocumentation() +{ + TRACE_OBJ + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + QStringList docs; + docs << QLatin1String("assistant") + << QLatin1String("designer") + << QLatin1String("linguist") + << QLatin1String("qmake") + << QLatin1String("qt"); + QList qtDocInfos; + foreach (const QString &doc, docs) + qtDocInfos.append(QtDocInstaller::DocInfo(doc, helpEngine.qtDocInfo(doc))); + + m_qtDocInstaller = new QtDocInstaller(qtDocInfos); + connect(m_qtDocInstaller, SIGNAL(docsInstalled(bool)), this, + SLOT(qtDocumentationInstalled())); + connect(m_qtDocInstaller, SIGNAL(qchFileNotFound(QString)), this, + SLOT(resetQtDocInfo(QString))); + connect(m_qtDocInstaller, SIGNAL(registerDocumentation(QString, QString)), + this, SLOT(registerDocumentation(QString, QString))); + if (helpEngine.qtDocInfo(QLatin1String("qt")).count() != 2) + statusBar()->showMessage(tr("Looking for Qt Documentation...")); + m_qtDocInstaller->installDocs(); +} + +void MainWindow::qtDocumentationInstalled() +{ + TRACE_OBJ + statusBar()->clearMessage(); + checkInitState(); +} + +void MainWindow::checkInitState() +{ + TRACE_OBJ + HelpEngineWrapper::instance().initialDocSetupDone(); + if (!m_cmdLine->enableRemoteControl()) + return; + + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + if (helpEngine.contentModel()->isCreatingContents() + || helpEngine.indexModel()->isCreatingIndex()) { + if (!m_connectedInitSignals) { + connect(helpEngine.contentModel(), SIGNAL(contentsCreated()), + this, SLOT(checkInitState())); + connect(helpEngine.indexModel(), SIGNAL(indexCreated()), this, + SLOT(checkInitState())); + m_connectedInitSignals = true; + } + } else { + if (m_connectedInitSignals) { + disconnect(helpEngine.contentModel(), 0, this, 0); + disconnect(helpEngine.indexModel(), 0, this, 0); + } + emit initDone(); + } +} + +void MainWindow::insertLastPages() +{ + TRACE_OBJ + if (m_cmdLine->search() == CmdLineParser::Activate) + showSearch(); +} + +void MainWindow::setupActions() +{ + TRACE_OBJ + QString resourcePath = QLatin1String(":/trolltech/assistant/images/"); +#ifdef Q_OS_MAC + setUnifiedTitleAndToolBarOnMac(true); + resourcePath.append(QLatin1String("mac")); +#else + resourcePath.append(QLatin1String("win")); +#endif + + QMenu *menu = menuBar()->addMenu(tr("&File")); + + OpenPagesManager * const openPages = OpenPagesManager::instance(); + m_newTabAction + = menu->addAction(tr("New &Tab"), openPages, SLOT(createPage())); + m_newTabAction->setShortcut(QKeySequence::AddTab); + m_closeTabAction = menu->addAction(tr("&Close Tab"), + openPages, SLOT(closeCurrentPage())); + m_closeTabAction->setShortcuts(QKeySequence::Close); + + menu->addSeparator(); + + m_pageSetupAction = menu->addAction(tr("Page Set&up..."), m_centralWidget, + SLOT(pageSetup())); + m_printPreviewAction = menu->addAction(tr("Print Preview..."), m_centralWidget, + SLOT(printPreview())); + + GlobalActions *globalActions = GlobalActions::instance(this); + menu->addAction(globalActions->printAction()); + menu->addSeparator(); + + QIcon appExitIcon = QIcon::fromTheme("application-exit"); + QAction *tmp; +#ifdef Q_OS_WIN + tmp = menu->addAction(appExitIcon, tr("E&xit"), this, SLOT(close())); + tmp->setShortcut(QKeySequence(tr("CTRL+Q"))); +#else + tmp = menu->addAction(appExitIcon, tr("&Quit"), this, SLOT(close())); + tmp->setShortcut(QKeySequence::Quit); +#endif + tmp->setMenuRole(QAction::QuitRole); + + menu = menuBar()->addMenu(tr("&Edit")); + menu->addAction(globalActions->copyAction()); + menu->addAction(globalActions->findAction()); + + QAction *findNextAction = menu->addAction(tr("Find &Next"), m_centralWidget, + SLOT(findNext())); + findNextAction->setShortcuts(QKeySequence::FindNext); + + QAction *findPreviousAction = menu->addAction(tr("Find &Previous"), + m_centralWidget, SLOT(findPrevious())); + findPreviousAction->setShortcuts(QKeySequence::FindPrevious); + + menu->addSeparator(); + tmp = menu->addAction(tr("Preferences..."), this, SLOT(showPreferences())); + tmp->setMenuRole(QAction::PreferencesRole); + + m_viewMenu = menuBar()->addMenu(tr("&View")); + m_viewMenu->addAction(globalActions->zoomInAction()); + m_viewMenu->addAction(globalActions->zoomOutAction()); + + m_resetZoomAction = m_viewMenu->addAction(tr("Normal &Size"), m_centralWidget, + SLOT(resetZoom())); + m_resetZoomAction->setPriority(QAction::LowPriority); + m_resetZoomAction->setIcon(QIcon(resourcePath + QLatin1String("/resetzoom.png"))); + m_resetZoomAction->setShortcut(tr("Ctrl+0")); + + m_viewMenu->addSeparator(); + + m_viewMenu->addAction(tr("Contents"), this, SLOT(showContents()), + QKeySequence(tr("ALT+C"))); + m_viewMenu->addAction(tr("Index"), this, SLOT(showIndex()), + QKeySequence(tr("ALT+I"))); + m_viewMenu->addAction(tr("Bookmarks"), this, SLOT(showBookmarksDockWidget()), + QKeySequence(tr("ALT+O"))); + m_viewMenu->addAction(tr("Search"), this, SLOT(showSearch()), + QKeySequence(tr("ALT+S"))); + m_viewMenu->addAction(tr("Open Pages"), this, SLOT(showOpenPages()), + QKeySequence(tr("ALT+P"))); + + menu = menuBar()->addMenu(tr("&Go")); + menu->addAction(globalActions->homeAction()); + menu->addAction(globalActions->backAction()); + menu->addAction(globalActions->nextAction()); + + m_syncAction = menu->addAction(tr("Sync with Table of Contents"), this, + SLOT(syncContents())); + m_syncAction->setIconText(tr("Sync")); + m_syncAction->setIcon(QIcon(resourcePath + QLatin1String("/synctoc.png"))); + + menu->addSeparator(); + + tmp = menu->addAction(tr("Next Page"), openPages, SLOT(nextPage())); + tmp->setShortcuts(QList() << QKeySequence(tr("Ctrl+Alt+Right")) + << QKeySequence(Qt::CTRL + Qt::Key_PageDown)); + + tmp = menu->addAction(tr("Previous Page"), openPages, SLOT(previousPage())); + tmp->setShortcuts(QList() << QKeySequence(tr("Ctrl+Alt+Left")) + << QKeySequence(Qt::CTRL + Qt::Key_PageUp)); + +#ifdef Q_WS_MAC + QShortcut *sct = new QShortcut(QKeySequence(Qt::ALT + Qt::Key_Tab), this); + connect(sct, SIGNAL(activated()), openPages, SLOT(nextPageWithSwitcher())); + sct = new QShortcut(QKeySequence(Qt::ALT + Qt::SHIFT + Qt::Key_Tab), this); + connect(sct, SIGNAL(activated()), openPages, SLOT(previousPageWithSwitcher())); +#else + QShortcut *sct = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Tab), this); + connect(sct, SIGNAL(activated()), openPages, SLOT(nextPageWithSwitcher())); + sct = new QShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Tab), this); + connect(sct, SIGNAL(activated()), openPages, SLOT(previousPageWithSwitcher())); +#endif + + BookmarkManager::instance()->setBookmarksMenu(menuBar()->addMenu(tr("&Bookmarks"))); + + menu = menuBar()->addMenu(tr("&Help")); + m_aboutAction = menu->addAction(tr("About..."), this, SLOT(showAboutDialog())); + m_aboutAction->setMenuRole(QAction::AboutRole); + +#ifdef Q_WS_X11 + m_resetZoomAction->setIcon(QIcon::fromTheme("zoom-original" , m_resetZoomAction->icon())); + m_syncAction->setIcon(QIcon::fromTheme("view-refresh" , m_syncAction->icon())); +#endif + + QToolBar *navigationBar = addToolBar(tr("Navigation Toolbar")); + navigationBar->setObjectName(QLatin1String("NavigationToolBar")); + navigationBar->addAction(globalActions->backAction()); + navigationBar->addAction(globalActions->nextAction()); + navigationBar->addAction(globalActions->homeAction()); + navigationBar->addAction(m_syncAction); + navigationBar->addSeparator(); + navigationBar->addAction(globalActions->copyAction()); + navigationBar->addAction(globalActions->printAction()); + navigationBar->addAction(globalActions->findAction()); + navigationBar->addSeparator(); + navigationBar->addAction(globalActions->zoomInAction()); + navigationBar->addAction(globalActions->zoomOutAction()); + navigationBar->addAction(m_resetZoomAction); + +#if defined(Q_WS_MAC) + QMenu *windowMenu = new QMenu(tr("&Window"), this); + menuBar()->insertMenu(menu->menuAction(), windowMenu); + windowMenu->addAction(tr("Zoom"), this, SLOT(showMaximized())); + windowMenu->addAction(tr("Minimize"), this, SLOT(showMinimized()), + QKeySequence(tr("Ctrl+M"))); +#endif + + // content viewer connections + connect(m_centralWidget, SIGNAL(copyAvailable(bool)), globalActions, + SLOT(setCopyAvailable(bool))); + connect(m_centralWidget, SIGNAL(currentViewerChanged()), globalActions, + SLOT(updateActions())); + connect(m_centralWidget, SIGNAL(forwardAvailable(bool)), globalActions, + SLOT(updateActions())); + connect(m_centralWidget, SIGNAL(backwardAvailable(bool)), globalActions, + SLOT(updateActions())); + connect(m_centralWidget, SIGNAL(highlighted(QString)), statusBar(), + SLOT(showMessage(QString))); + + // index window + connect(m_indexWindow, SIGNAL(linkActivated(QUrl)), m_centralWidget, + SLOT(setSource(QUrl))); + connect(m_indexWindow, SIGNAL(linksActivated(QMap,QString)), + this, SLOT(showTopicChooser(QMap,QString))); + connect(m_indexWindow, SIGNAL(escapePressed()), this, + SLOT(activateCurrentCentralWidgetTab())); + + // content window + connect(m_contentWindow, SIGNAL(linkActivated(QUrl)), m_centralWidget, + SLOT(setSource(QUrl))); + connect(m_contentWindow, SIGNAL(escapePressed()), this, + SLOT(activateCurrentCentralWidgetTab())); + + // search window + connect(m_searchWindow, SIGNAL(requestShowLink(QUrl)), + CentralWidget::instance(), SLOT(setSourceFromSearch(QUrl))); + connect(m_searchWindow, SIGNAL(requestShowLinkInNewTab(QUrl)), + OpenPagesManager::instance(), SLOT(createNewPageFromSearch(QUrl))); + +#if defined(QT_NO_PRINTER) + m_pageSetupAction->setVisible(false); + m_printPreviewAction->setVisible(false); + m_printAction->setVisible(false); +#endif +} + +QMenu *MainWindow::toolBarMenu() +{ + TRACE_OBJ + if (!m_toolBarMenu) { + m_viewMenu->addSeparator(); + m_toolBarMenu = m_viewMenu->addMenu(tr("Toolbars")); + } + return m_toolBarMenu; +} + +void MainWindow::setupFilterToolbar() +{ + TRACE_OBJ + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + if (!helpEngine.filterFunctionalityEnabled()) + return; + + m_filterCombo = new QComboBox(this); + m_filterCombo->setMinimumWidth(QFontMetrics(QFont()). + width(QLatin1String("MakeTheComboBoxWidthEnough"))); + + QToolBar *filterToolBar = addToolBar(tr("Filter Toolbar")); + filterToolBar->setObjectName(QLatin1String("FilterToolBar")); + filterToolBar->addWidget(new QLabel(tr("Filtered by:").append(QLatin1Char(' ')), + this)); + filterToolBar->addWidget(m_filterCombo); + + if (!helpEngine.filterToolbarVisible()) + filterToolBar->hide(); + toolBarMenu()->addAction(filterToolBar->toggleViewAction()); + + connect(&helpEngine, SIGNAL(setupFinished()), this, + SLOT(setupFilterCombo()), Qt::QueuedConnection); + connect(m_filterCombo, SIGNAL(activated(QString)), this, + SLOT(filterDocumentation(QString))); + connect(&helpEngine, SIGNAL(currentFilterChanged(QString)), this, + SLOT(currentFilterChanged(QString))); + + setupFilterCombo(); +} + +void MainWindow::setupAddressToolbar() +{ + TRACE_OBJ + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + if (!helpEngine.addressBarEnabled()) + return; + + m_addressLineEdit = new QLineEdit(this); + QToolBar *addressToolBar = addToolBar(tr("Address Toolbar")); + addressToolBar->setObjectName(QLatin1String("AddressToolBar")); + insertToolBarBreak(addressToolBar); + + addressToolBar->addWidget(new QLabel(tr("Address:").append(QLatin1String(" ")), + this)); + addressToolBar->addWidget(m_addressLineEdit); + + if (!helpEngine.addressBarVisible()) + addressToolBar->hide(); + toolBarMenu()->addAction(addressToolBar->toggleViewAction()); + + // address lineedit + connect(m_addressLineEdit, SIGNAL(returnPressed()), this, + SLOT(gotoAddress())); + connect(m_centralWidget, SIGNAL(currentViewerChanged()), this, + SLOT(showNewAddress())); + connect(m_centralWidget, SIGNAL(sourceChanged(QUrl)), this, + SLOT(showNewAddress(QUrl))); +} + +void MainWindow::updateAboutMenuText() +{ + TRACE_OBJ + QByteArray ba = HelpEngineWrapper::instance().aboutMenuTexts(); + if (ba.size() > 0) { + QString lang; + QString str; + QString trStr; + QString currentLang = QLocale::system().name(); + int i = currentLang.indexOf(QLatin1Char('_')); + if (i > -1) + currentLang = currentLang.left(i); + QDataStream s(&ba, QIODevice::ReadOnly); + while (!s.atEnd()) { + s >> lang; + s >> str; + if (lang == QLatin1String("default") && trStr.isEmpty()) { + trStr = str; + } else if (lang == currentLang) { + trStr = str; + break; + } + } + if (!trStr.isEmpty()) + m_aboutAction->setText(trStr); + } +} + +void MainWindow::showNewAddress() +{ + TRACE_OBJ + showNewAddress(m_centralWidget->currentSource()); +} + +void MainWindow::showNewAddress(const QUrl &url) +{ + TRACE_OBJ + m_addressLineEdit->setText(url.toString()); +} + +void MainWindow::gotoAddress() +{ + TRACE_OBJ + m_centralWidget->setSource(m_addressLineEdit->text()); +} + +void MainWindow::showTopicChooser(const QMap &links, + const QString &keyword) +{ + TRACE_OBJ + TopicChooser tc(this, keyword, links); + if (tc.exec() == QDialog::Accepted) { + m_centralWidget->setSource(tc.link()); + } +} + +void MainWindow::showPreferences() +{ + TRACE_OBJ + PreferencesDialog dia(this); + connect(&dia, SIGNAL(updateApplicationFont()), this, + SLOT(updateApplicationFont())); + connect(&dia, SIGNAL(updateBrowserFont()), m_centralWidget, + SLOT(updateBrowserFont())); + connect(&dia, SIGNAL(updateUserInterface()), m_centralWidget, + SLOT(updateUserInterface())); + dia.showDialog(); +} + +void MainWindow::syncContents() +{ + TRACE_OBJ + qApp->setOverrideCursor(QCursor(Qt::WaitCursor)); + const QUrl url = m_centralWidget->currentSource(); + showContents(); + if (!m_contentWindow->syncToContent(url)) + statusBar()->showMessage( + tr("Could not find the associated content item."), 3000); + qApp->restoreOverrideCursor(); +} + +void MainWindow::showAboutDialog() +{ + TRACE_OBJ + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + QByteArray contents; + QByteArray ba = helpEngine.aboutTexts(); + if (!ba.isEmpty()) { + QString lang; + QByteArray cba; + QString currentLang = QLocale::system().name(); + int i = currentLang.indexOf(QLatin1Char('_')); + if (i > -1) + currentLang = currentLang.left(i); + QDataStream s(&ba, QIODevice::ReadOnly); + while (!s.atEnd()) { + s >> lang; + s >> cba; + if (lang == QLatin1String("default") && contents.isEmpty()) { + contents = cba; + } else if (lang == currentLang) { + contents = cba; + break; + } + } + } + + AboutDialog aboutDia(this); + + QByteArray iconArray; + if (!contents.isEmpty()) { + iconArray = helpEngine.aboutIcon(); + QByteArray resources = helpEngine.aboutImages(); + QPixmap pix; + pix.loadFromData(iconArray); + aboutDia.setText(QString::fromUtf8(contents), resources); + if (!pix.isNull()) + aboutDia.setPixmap(pix); + aboutDia.setWindowTitle(aboutDia.documentTitle()); + } else { + QByteArray resources; + aboutDia.setText(tr("
" + "

%1

" + "

Version %2

" + "

Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).

") + .arg(tr("Qt Assistant")).arg(QLatin1String(QT_VERSION_STR)), + resources); + QLatin1String path(":/trolltech/assistant/images/assistant-128.png"); + aboutDia.setPixmap(QString(path)); + } + if (aboutDia.windowTitle().isEmpty()) + aboutDia.setWindowTitle(tr("About %1").arg(windowTitle())); + aboutDia.exec(); +} + +void MainWindow::setContentsVisible(bool visible) +{ + TRACE_OBJ + if (visible) + showContents(); + else + hideContents(); +} + +void MainWindow::showContents() +{ + TRACE_OBJ + activateDockWidget(m_contentWindow); +} + +void MainWindow::hideContents() +{ + TRACE_OBJ + m_contentWindow->parentWidget()->hide(); +} + +void MainWindow::setIndexVisible(bool visible) +{ + TRACE_OBJ + if (visible) + showIndex(); + else + hideIndex(); +} + +void MainWindow::showIndex() +{ + TRACE_OBJ + activateDockWidget(m_indexWindow); +} + +void MainWindow::hideIndex() +{ + TRACE_OBJ + m_indexWindow->parentWidget()->hide(); +} + +void MainWindow::setBookmarksVisible(bool visible) +{ + TRACE_OBJ + if (visible) + showBookmarksDockWidget(); + else + hideBookmarksDockWidget(); +} + +void MainWindow::showBookmarksDockWidget() +{ + TRACE_OBJ + activateDockWidget(m_bookmarkWidget); +} + +void MainWindow::hideBookmarksDockWidget() +{ + TRACE_OBJ + m_bookmarkWidget->parentWidget()->hide(); +} + +void MainWindow::setSearchVisible(bool visible) +{ + TRACE_OBJ + if (visible) + showSearch(); + else + hideSearch(); +} + +void MainWindow::showSearch() +{ + TRACE_OBJ + activateDockWidget(m_searchWindow); +} + +void MainWindow::showOpenPages() +{ + TRACE_OBJ + activateDockWidget(OpenPagesManager::instance()->openPagesWidget()); +} + +void MainWindow::hideSearch() +{ + TRACE_OBJ + m_searchWindow->parentWidget()->hide(); +} + +void MainWindow::activateDockWidget(QWidget *w) +{ + TRACE_OBJ + w->parentWidget()->show(); + w->parentWidget()->raise(); + w->setFocus(); +} + +void MainWindow::setIndexString(const QString &str) +{ + TRACE_OBJ + m_indexWindow->setSearchLineEditText(str); +} + +void MainWindow::activateCurrentBrowser() +{ + TRACE_OBJ + CentralWidget::instance()->activateTab(); +} + +void MainWindow::activateCurrentCentralWidgetTab() +{ + TRACE_OBJ + m_centralWidget->activateTab(); +} + +void MainWindow::updateApplicationFont() +{ + TRACE_OBJ + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + QFont font = qApp->font(); + if (helpEngine.usesAppFont()) + font = helpEngine.appFont(); + + const QWidgetList &widgets = qApp->allWidgets(); + foreach (QWidget* widget, widgets) + widget->setFont(font); +} + +void MainWindow::setupFilterCombo() +{ + TRACE_OBJ + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + QString curFilter = m_filterCombo->currentText(); + if (curFilter.isEmpty()) + curFilter = helpEngine.currentFilter(); + m_filterCombo->clear(); + m_filterCombo->addItems(helpEngine.customFilters()); + int idx = m_filterCombo->findText(curFilter); + if (idx < 0) + idx = 0; + m_filterCombo->setCurrentIndex(idx); +} + +void MainWindow::filterDocumentation(const QString &customFilter) +{ + TRACE_OBJ + HelpEngineWrapper::instance().setCurrentFilter(customFilter); +} + +void MainWindow::expandTOC(int depth) +{ + TRACE_OBJ + Q_ASSERT(depth >= -1); + m_contentWindow->expandToDepth(depth); +} + +void MainWindow::indexingStarted() +{ + TRACE_OBJ + if (!m_progressWidget) { + m_progressWidget = new QWidget(); + QLayout* hlayout = new QHBoxLayout(m_progressWidget); + + QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); + + QLabel *label = new QLabel(tr("Updating search index")); + label->setSizePolicy(sizePolicy); + hlayout->addWidget(label); + + QProgressBar *progressBar = new QProgressBar(); + progressBar->setRange(0, 0); + progressBar->setTextVisible(false); + progressBar->setSizePolicy(sizePolicy); + + hlayout->setSpacing(6); + hlayout->setMargin(0); + hlayout->addWidget(progressBar); + + statusBar()->addPermanentWidget(m_progressWidget); + } +} + +void MainWindow::indexingFinished() +{ + TRACE_OBJ + statusBar()->removeWidget(m_progressWidget); + delete m_progressWidget; + m_progressWidget = 0; +} + +QString MainWindow::collectionFileDirectory(bool createDir, const QString &cacheDir) +{ + TRACE_OBJ + QString collectionPath = + QDesktopServices::storageLocation(QDesktopServices::DataLocation); + if (collectionPath.isEmpty()) { + if (cacheDir.isEmpty()) + collectionPath = QDir::homePath() + QDir::separator() + + QLatin1String(".assistant"); + else + collectionPath = QDir::homePath() + QLatin1String("/.") + cacheDir; + } else { + if (cacheDir.isEmpty()) + collectionPath = collectionPath + QLatin1String("/Trolltech/Assistant"); + else + collectionPath = collectionPath + QDir::separator() + cacheDir; + } + collectionPath = QDir::cleanPath(collectionPath); + if (createDir) { + QDir dir; + if (!dir.exists(collectionPath)) + dir.mkpath(collectionPath); + } + return collectionPath; +} + +QString MainWindow::defaultHelpCollectionFileName() +{ + TRACE_OBJ + // forces creation of the default collection file path + return collectionFileDirectory(true) + QDir::separator() + + QString(QLatin1String("qthelpcollection_%1.qhc")). + arg(QLatin1String(QT_VERSION_STR)); +} + +void MainWindow::currentFilterChanged(const QString &filter) +{ + TRACE_OBJ + const int index = m_filterCombo->findText(filter); + Q_ASSERT(index != -1); + m_filterCombo->setCurrentIndex(index); +} + +void MainWindow::documentationRemoved(const QString &namespaceName) +{ + TRACE_OBJ + OpenPagesManager::instance()->closePages(namespaceName); +} + +void MainWindow::documentationUpdated(const QString &namespaceName) +{ + TRACE_OBJ + OpenPagesManager::instance()->reloadPages(namespaceName); +} + +void MainWindow::resetQtDocInfo(const QString &component) +{ + TRACE_OBJ + HelpEngineWrapper::instance().setQtDocInfo(component, + QStringList(QDateTime().toString(Qt::ISODate))); +} + +void MainWindow::registerDocumentation(const QString &component, + const QString &absFileName) +{ + TRACE_OBJ + QString ns = QHelpEngineCore::namespaceName(absFileName); + if (ns.isEmpty()) + return; + + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + if (helpEngine.registeredDocumentations().contains(ns)) + helpEngine.unregisterDocumentation(ns); + if (!helpEngine.registerDocumentation(absFileName)) { + QMessageBox::warning(this, tr("Qt Assistant"), + tr("Could not register file '%1': %2"). + arg(absFileName).arg(helpEngine.error())); + } else { + QStringList docInfo; + docInfo << QFileInfo(absFileName).lastModified().toString(Qt::ISODate) + << absFileName; + helpEngine.setQtDocInfo(component, docInfo); + } +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/mainwindow.h b/src/assistant/tools/assistant/mainwindow.h new file mode 100644 index 000000000..6fe10ec45 --- /dev/null +++ b/src/assistant/tools/assistant/mainwindow.h @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QAction; +class QComboBox; +class QFileSystemWatcher; +class QLineEdit; +class QMenu; + +class CentralWidget; +class CmdLineParser; +class ContentWindow; +class IndexWindow; +class OpenPagesWindow; +class QtDocInstaller; +class QHelpEngineCore; +class QHelpEngine; +class SearchWidget; + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(CmdLineParser *cmdLine, QWidget *parent = 0); + ~MainWindow(); + + static void activateCurrentBrowser(); + static QString collectionFileDirectory(bool createDir = false, + const QString &cacheDir = QString()); + static QString defaultHelpCollectionFileName(); + +public: + void setIndexString(const QString &str); + void expandTOC(int depth); + bool usesDefaultCollection() const; + +signals: + void initDone(); + +public slots: + void setContentsVisible(bool visible); + void setIndexVisible(bool visible); + void setBookmarksVisible(bool visible); + void setSearchVisible(bool visible); + void syncContents(); + void activateCurrentCentralWidgetTab(); + void currentFilterChanged(const QString &filter); + +private slots: + void showContents(); + void showIndex(); + void showSearch(); + void showOpenPages(); + void insertLastPages(); + void gotoAddress(); + void showPreferences(); + void showNewAddress(); + void showAboutDialog(); + void showNewAddress(const QUrl &url); + void showTopicChooser(const QMap &links, const QString &keyword); + void updateApplicationFont(); + void filterDocumentation(const QString &customFilter); + void setupFilterCombo(); + void lookForNewQtDocumentation(); + void indexingStarted(); + void indexingFinished(); + void qtDocumentationInstalled(); + void registerDocumentation(const QString &component, + const QString &absFileName); + void resetQtDocInfo(const QString &component); + void checkInitState(); + void documentationRemoved(const QString &namespaceName); + void documentationUpdated(const QString &namespaceName); + +private: + bool initHelpDB(bool registerInternalDoc); + void setupActions(); + void closeEvent(QCloseEvent *e); + void activateDockWidget(QWidget *w); + void updateAboutMenuText(); + void setupFilterToolbar(); + void setupAddressToolbar(); + QMenu *toolBarMenu(); + void hideContents(); + void hideIndex(); + void hideSearch(); + +private slots: + void showBookmarksDockWidget(); + void hideBookmarksDockWidget(); + +private: + QWidget *m_bookmarkWidget; + +private: + CentralWidget *m_centralWidget; + IndexWindow *m_indexWindow; + ContentWindow *m_contentWindow; + SearchWidget *m_searchWindow; + QLineEdit *m_addressLineEdit; + QComboBox *m_filterCombo; + + QAction *m_syncAction; + QAction *m_printPreviewAction; + QAction *m_pageSetupAction; + QAction *m_resetZoomAction; + QAction *m_aboutAction; + QAction *m_closeTabAction; + QAction *m_newTabAction; + + QMenu *m_viewMenu; + QMenu *m_toolBarMenu; + + CmdLineParser *m_cmdLine; + + QWidget *m_progressWidget; + QtDocInstaller *m_qtDocInstaller; + + bool m_connectedInitSignals; +}; + +QT_END_NAMESPACE + +#endif // MAINWINDOW_H diff --git a/src/assistant/tools/assistant/openpagesmanager.cpp b/src/assistant/tools/assistant/openpagesmanager.cpp new file mode 100644 index 000000000..272d9e242 --- /dev/null +++ b/src/assistant/tools/assistant/openpagesmanager.cpp @@ -0,0 +1,378 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Assistant module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "openpagesmanager.h" + +#include "centralwidget.h" +#include "helpenginewrapper.h" +#include "helpviewer.h" +#include "openpagesmodel.h" +#include "openpagesswitcher.h" +#include "openpageswidget.h" +#include "tracer.h" +#include "../shared/collectionconfiguration.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +OpenPagesManager *OpenPagesManager::m_instance = 0; + +OpenPagesManager *OpenPagesManager::createInstance(QObject *parent, + bool defaultCollection, const QUrl &cmdLineUrl) +{ + TRACE_OBJ + Q_ASSERT(!m_instance); + m_instance = new OpenPagesManager(parent, defaultCollection, cmdLineUrl); + return m_instance; +} + +OpenPagesManager *OpenPagesManager::instance() +{ + TRACE_OBJ + Q_ASSERT(m_instance); + return m_instance; +} + +OpenPagesManager::OpenPagesManager(QObject *parent, bool defaultCollection, + const QUrl &cmdLineUrl) + : QObject(parent) + , m_model(new OpenPagesModel(this)) + , m_openPagesWidget(0) + , m_openPagesSwitcher(0) +{ + TRACE_OBJ + m_openPagesWidget = new OpenPagesWidget(m_model); + m_openPagesWidget->setFrameStyle(QFrame::NoFrame); + connect(m_openPagesWidget, SIGNAL(setCurrentPage(QModelIndex)), this, + SLOT(setCurrentPage(QModelIndex))); + connect(m_openPagesWidget, SIGNAL(closePage(QModelIndex)), this, + SLOT(closePage(QModelIndex))); + connect(m_openPagesWidget, SIGNAL(closePagesExcept(QModelIndex)), this, + SLOT(closePagesExcept(QModelIndex))); + + m_openPagesSwitcher = new OpenPagesSwitcher(m_model); + connect(m_openPagesSwitcher, SIGNAL(closePage(QModelIndex)), this, + SLOT(closePage(QModelIndex))); + connect(m_openPagesSwitcher, SIGNAL(setCurrentPage(QModelIndex)), this, + SLOT(setCurrentPage(QModelIndex))); + + setupInitialPages(defaultCollection, cmdLineUrl); +} + +OpenPagesManager ::~OpenPagesManager() +{ + TRACE_OBJ + m_instance = 0; + delete m_openPagesSwitcher; +} + +int OpenPagesManager::pageCount() const +{ + TRACE_OBJ + return m_model->rowCount(); +} + +void OpenPagesManager::setupInitialPages(bool defaultCollection, + const QUrl &cmdLineUrl) +{ + TRACE_OBJ + if (cmdLineUrl.isValid()) { + createPage(cmdLineUrl); + return; + } + + HelpEngineWrapper &helpEngine = HelpEngineWrapper::instance(); + int initialPage = 0; + switch (helpEngine.startOption()) { + case ShowHomePage: + m_model->addPage(helpEngine.homePage()); + break; + case ShowBlankPage: + m_model->addPage(QUrl(QLatin1String("about:blank"))); + break; + case ShowLastPages: { + const QStringList &lastShownPageList = helpEngine.lastShownPages(); + const int pageCount = lastShownPageList.count(); + if (pageCount == 0) { + if (defaultCollection) + m_model->addPage(QUrl(QLatin1String("help"))); + else + m_model->addPage(QUrl(QLatin1String("about:blank"))); + } else { + QStringList zoomFactors = helpEngine.lastZoomFactors(); + while (zoomFactors.count() < pageCount) + zoomFactors.append(CollectionConfiguration::DefaultZoomFactor); + initialPage = helpEngine.lastTabPage(); + if (initialPage >= pageCount) { + qWarning("Initial page set to %d, maximum possible value is %d", + initialPage, pageCount - 1); + initialPage = 0; + } + for (int curPage = 0; curPage < pageCount; ++curPage) { + const QString &curFile = lastShownPageList.at(curPage); + if (helpEngine.findFile(curFile).isValid() + || curFile == QLatin1String("about:blank")) { + m_model->addPage(curFile, zoomFactors.at(curPage).toFloat()); + } else if (curPage <= initialPage && initialPage > 0) + --initialPage; + } + } + break; + } + default: + Q_ASSERT(!"Unhandled option"); + } + + if (m_model->rowCount() == 0) + m_model->addPage(helpEngine.homePage()); + for (int i = 0; i < m_model->rowCount(); ++i) + CentralWidget::instance()->addPage(m_model->pageAt(i)); + setCurrentPage((initialPage >= m_model->rowCount()) + ? m_model->rowCount() - 1 : initialPage); + m_openPagesSwitcher->selectCurrentPage(); +} + +HelpViewer *OpenPagesManager::createPage() +{ + TRACE_OBJ + return createPage(QUrl(QLatin1String("about:blank"))); +} + +void OpenPagesManager::closeCurrentPage() +{ + TRACE_OBJ + Q_ASSERT(m_model->rowCount() > 1); + const QModelIndexList selectedIndexes + = m_openPagesWidget->selectionModel()->selectedRows(); + if (selectedIndexes.isEmpty()) + return; + Q_ASSERT(selectedIndexes.count() == 1); + removePage(selectedIndexes.first().row()); +} + +HelpViewer *OpenPagesManager::createPage(const QUrl &url, bool fromSearch) +{ + TRACE_OBJ + if (HelpViewer::launchWithExternalApp(url)) + return 0; + + m_model->addPage(url); + const int index = m_model->rowCount() - 1; + HelpViewer * const page = m_model->pageAt(index); + CentralWidget::instance()->addPage(page, fromSearch); + setCurrentPage(index); + return page; +} + +HelpViewer *OpenPagesManager::createNewPageFromSearch(const QUrl &url) +{ + TRACE_OBJ + return createPage(url, true); +} + +void OpenPagesManager::closePage(HelpViewer *viewer) +{ + TRACE_OBJ + for (int i = 0; i < m_model->rowCount(); ++i) { + if (m_model->pageAt(i) == viewer) { + removePage(i); + break; + } + } +} + +void OpenPagesManager::closePage(const QModelIndex &index) +{ + TRACE_OBJ + if (index.isValid()) + removePage(index.row()); +} + +void OpenPagesManager::closePages(const QString &nameSpace) +{ + TRACE_OBJ + closeOrReloadPages(nameSpace, false); +} + +void OpenPagesManager::reloadPages(const QString &nameSpace) +{ + TRACE_OBJ + closeOrReloadPages(nameSpace, true); + m_openPagesWidget->selectCurrentPage(); +} + +void OpenPagesManager::closeOrReloadPages(const QString &nameSpace, bool tryReload) +{ + TRACE_OBJ + for (int i = m_model->rowCount() - 1; i >= 0; --i) { + HelpViewer *page = m_model->pageAt(i); + if (page->source().host() != nameSpace) + continue; + if (tryReload && HelpEngineWrapper::instance().findFile(page->source()).isValid()) + page->reload(); + else if (m_model->rowCount() == 1) + page->setSource(QUrl(QLatin1String("about:blank"))); + else + removePage(i); + } +} + +bool OpenPagesManager::pagesOpenForNamespace(const QString &nameSpace) const +{ + TRACE_OBJ + for (int i = 0; i < m_model->rowCount(); ++i) + if (m_model->pageAt(i)->source().host() == nameSpace) + return true; + return false; +} + +void OpenPagesManager::setCurrentPage(const QModelIndex &index) +{ + TRACE_OBJ + if (index.isValid()) + setCurrentPage(index.row()); +} + +void OpenPagesManager::setCurrentPage(int index) +{ + TRACE_OBJ + setCurrentPage(m_model->pageAt(index)); +} + +void OpenPagesManager::setCurrentPage(HelpViewer *page) +{ + TRACE_OBJ + CentralWidget::instance()->setCurrentPage(page); + m_openPagesWidget->selectCurrentPage(); +} + +void OpenPagesManager::removePage(int index) +{ + TRACE_OBJ + CentralWidget::instance()->removePage(index); + m_model->removePage(index); + m_openPagesWidget->selectCurrentPage(); +} + + +void OpenPagesManager::closePagesExcept(const QModelIndex &index) +{ + TRACE_OBJ + if (!index.isValid()) + return; + + int i = 0; + HelpViewer *viewer = m_model->pageAt(index.row()); + while (m_model->rowCount() > 1) { + if (m_model->pageAt(i) != viewer) + removePage(i); + else + ++i; + } +} + +QAbstractItemView *OpenPagesManager::openPagesWidget() const +{ + TRACE_OBJ + return m_openPagesWidget; +} + +void OpenPagesManager::nextPage() +{ + TRACE_OBJ + nextOrPreviousPage(1); +} + +void OpenPagesManager::nextPageWithSwitcher() +{ + TRACE_OBJ + if (!m_openPagesSwitcher->isVisible()) { + m_openPagesSwitcher->selectCurrentPage(); + m_openPagesSwitcher->gotoNextPage(); + showSwitcherOrSelectPage(); + } else { + m_openPagesSwitcher->gotoNextPage(); + } +} + +void OpenPagesManager::previousPage() +{ + TRACE_OBJ + nextOrPreviousPage(-1); +} + +void OpenPagesManager::previousPageWithSwitcher() +{ + TRACE_OBJ + if (!m_openPagesSwitcher->isVisible()) { + m_openPagesSwitcher->selectCurrentPage(); + m_openPagesSwitcher->gotoPreviousPage(); + showSwitcherOrSelectPage(); + } else { + m_openPagesSwitcher->gotoPreviousPage(); + } +} + +void OpenPagesManager::nextOrPreviousPage(int offset) +{ + TRACE_OBJ + setCurrentPage((CentralWidget::instance()->currentIndex() + offset + + m_model->rowCount()) % m_model->rowCount()); +} + +void OpenPagesManager::showSwitcherOrSelectPage() const +{ + TRACE_OBJ + if (QApplication::keyboardModifiers() != Qt::NoModifier) { + const int width = CentralWidget::instance()->width(); + const int height = CentralWidget::instance()->height(); + const QPoint p(CentralWidget::instance()->mapToGlobal(QPoint(0, 0))); + m_openPagesSwitcher->move((width - m_openPagesSwitcher->width()) / 2 + p.x(), + (height - m_openPagesSwitcher->height()) / 2 + p.y()); + m_openPagesSwitcher->setVisible(true); + } else { + m_openPagesSwitcher->selectAndHide(); + } +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/openpagesmanager.h b/src/assistant/tools/assistant/openpagesmanager.h new file mode 100644 index 000000000..c34686c8c --- /dev/null +++ b/src/assistant/tools/assistant/openpagesmanager.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Assistant module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef OPENPAGESMANAGER_H +#define OPENPAGESMANAGER_H + +#include + +QT_BEGIN_NAMESPACE + +class QAbstractItemView; +class QModelIndex; +class QUrl; + +class HelpViewer; +class OpenPagesModel; +class OpenPagesSwitcher; +class OpenPagesWidget; + +class OpenPagesManager : public QObject +{ + Q_OBJECT +public: + static OpenPagesManager *createInstance(QObject *parent, + bool defaultCollection, const QUrl &cmdLineUrl); + static OpenPagesManager *instance(); + + bool pagesOpenForNamespace(const QString &nameSpace) const; + void closePages(const QString &nameSpace); + void reloadPages(const QString &nameSpace); + + QAbstractItemView* openPagesWidget() const; + + int pageCount() const; + void setCurrentPage(int index); + +public slots: + HelpViewer *createPage(const QUrl &url, bool fromSearch = false); + HelpViewer *createNewPageFromSearch(const QUrl &url); + HelpViewer *createPage(); + void closeCurrentPage(); + + void nextPage(); + void nextPageWithSwitcher(); + void previousPage(); + void previousPageWithSwitcher(); + + void closePage(HelpViewer *page); + void setCurrentPage(HelpViewer *page); + +private slots: + void setCurrentPage(const QModelIndex &index); + void closePage(const QModelIndex &index); + void closePagesExcept(const QModelIndex &index); + +private: + OpenPagesManager(QObject *parent, bool defaultCollection, + const QUrl &cmdLineUrl); + ~OpenPagesManager(); + + void setupInitialPages(bool defaultCollection, const QUrl &cmdLineUrl); + void closeOrReloadPages(const QString &nameSpace, bool tryReload); + void removePage(int index); + + void nextOrPreviousPage(int offset); + void showSwitcherOrSelectPage() const; + + OpenPagesModel *m_model; + OpenPagesWidget *m_openPagesWidget; + OpenPagesSwitcher *m_openPagesSwitcher; + + static OpenPagesManager *m_instance; +}; + +QT_END_NAMESPACE + +#endif // OPENPAGESMANAGER_H diff --git a/src/assistant/tools/assistant/openpagesmodel.cpp b/src/assistant/tools/assistant/openpagesmodel.cpp new file mode 100644 index 000000000..3517693f9 --- /dev/null +++ b/src/assistant/tools/assistant/openpagesmodel.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Assistant module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "openpagesmodel.h" + +#include "helpenginewrapper.h" +#include "helpviewer.h" +#include "tracer.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +OpenPagesModel::OpenPagesModel(QObject *parent) : QAbstractTableModel(parent) +{ + TRACE_OBJ +} + +int OpenPagesModel::rowCount(const QModelIndex &parent) const +{ + TRACE_OBJ + return parent.isValid() ? 0 : m_pages.count(); +} + +int OpenPagesModel::columnCount(const QModelIndex &/*parent*/) const +{ + TRACE_OBJ + return 2; +} + +QVariant OpenPagesModel::data(const QModelIndex &index, int role) const +{ + TRACE_OBJ + if (!index.isValid() || index.row() >= rowCount() || index.column() > 0 + || role != Qt::DisplayRole) + return QVariant(); + QString title = m_pages.at(index.row())->title(); + title.replace(QLatin1Char('&'), QLatin1String("&&")); + return title.isEmpty() ? QLatin1String("(Untitled)") : title; +} + +void OpenPagesModel::addPage(const QUrl &url, qreal zoom) +{ + TRACE_OBJ + beginInsertRows(QModelIndex(), rowCount(), rowCount()); + HelpViewer *page = new HelpViewer(zoom); + connect(page, SIGNAL(titleChanged()), this, SLOT(handleTitleChanged())); + m_pages << page; + endInsertRows(); + page->setSource(url); +} + +void OpenPagesModel::removePage(int index) +{ + TRACE_OBJ + Q_ASSERT(index >= 0 && index < rowCount()); + beginRemoveRows(QModelIndex(), index, index); + HelpViewer *page = m_pages.at(index); + m_pages.removeAt(index); + endRemoveRows(); + page->deleteLater(); +} + +HelpViewer *OpenPagesModel::pageAt(int index) const +{ + TRACE_OBJ + Q_ASSERT(index >= 0 && index < rowCount()); + return m_pages.at(index); +} + +void OpenPagesModel::handleTitleChanged() +{ + TRACE_OBJ + HelpViewer *page = static_cast(sender()); + const int row = m_pages.indexOf(page); + Q_ASSERT(row != -1 ); + const QModelIndex &item = index(row, 0); + emit dataChanged(item, item); +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/openpagesmodel.h b/src/assistant/tools/assistant/openpagesmodel.h new file mode 100644 index 000000000..dd28a7c5f --- /dev/null +++ b/src/assistant/tools/assistant/openpagesmodel.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Assistant module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef OPENPAGESMODEL_H +#define OPENPAGESMODEL_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class HelpViewer; +class QUrl; + +class OpenPagesModel : public QAbstractTableModel +{ + Q_OBJECT +public: + OpenPagesModel(QObject *parent); + + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + + void addPage(const QUrl &url, qreal zoom = 0); + void removePage(int index); + HelpViewer *pageAt(int index) const; + +private slots: + void handleTitleChanged(); + +private: + QList m_pages; +}; + +QT_END_NAMESPACE + +#endif // OPENPAGESMODEL_H diff --git a/src/assistant/tools/assistant/openpagesswitcher.cpp b/src/assistant/tools/assistant/openpagesswitcher.cpp new file mode 100644 index 000000000..8e7f29bf0 --- /dev/null +++ b/src/assistant/tools/assistant/openpagesswitcher.cpp @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Assistant module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "openpagesswitcher.h" + +#include "centralwidget.h" +#include "openpagesmodel.h" +#include "openpageswidget.h" +#include "tracer.h" + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +const int gWidth = 300; +const int gHeight = 200; + +OpenPagesSwitcher::OpenPagesSwitcher(OpenPagesModel *model) + : QFrame(0, Qt::Popup) + , m_openPagesModel(model) +{ + TRACE_OBJ + resize(gWidth, gHeight); + + m_openPagesWidget = new OpenPagesWidget(m_openPagesModel); + + // We disable the frame on this list view and use a QFrame around it instead. + // This improves the look with QGTKStyle. +#ifndef Q_WS_MAC + setFrameStyle(m_openPagesWidget->frameStyle()); +#endif + m_openPagesWidget->setFrameStyle(QFrame::NoFrame); + + m_openPagesWidget->allowContextMenu(false); + m_openPagesWidget->installEventFilter(this); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->setMargin(0); + layout->addWidget(m_openPagesWidget); + + connect(m_openPagesWidget, SIGNAL(closePage(QModelIndex)), this, + SIGNAL(closePage(QModelIndex))); + connect(m_openPagesWidget, SIGNAL(setCurrentPage(QModelIndex)), this, + SIGNAL(setCurrentPage(QModelIndex))); +} + +OpenPagesSwitcher::~OpenPagesSwitcher() +{ + TRACE_OBJ +} + +void OpenPagesSwitcher::gotoNextPage() +{ + TRACE_OBJ + selectPageUpDown(1); +} + +void OpenPagesSwitcher::gotoPreviousPage() +{ + TRACE_OBJ + selectPageUpDown(-1); +} + +void OpenPagesSwitcher::selectAndHide() +{ + TRACE_OBJ + setVisible(false); + emit setCurrentPage(m_openPagesWidget->currentIndex()); +} + +void OpenPagesSwitcher::selectCurrentPage() +{ + TRACE_OBJ + m_openPagesWidget->selectCurrentPage(); +} + +void OpenPagesSwitcher::setVisible(bool visible) +{ + TRACE_OBJ + QWidget::setVisible(visible); + if (visible) + setFocus(); +} + +void OpenPagesSwitcher::focusInEvent(QFocusEvent *event) +{ + TRACE_OBJ + Q_UNUSED(event) + m_openPagesWidget->setFocus(); +} + +bool OpenPagesSwitcher::eventFilter(QObject *object, QEvent *event) +{ + TRACE_OBJ + if (object == m_openPagesWidget) { + if (event->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast(event); + if (ke->key() == Qt::Key_Escape) { + setVisible(false); + return true; + } + + const int key = ke->key(); + if (key == Qt::Key_Return || key == Qt::Key_Enter || key == Qt::Key_Space) { + emit setCurrentPage(m_openPagesWidget->currentIndex()); + return true; + } + + Qt::KeyboardModifier modifier = Qt::ControlModifier; +#ifdef Q_WS_MAC + modifier = Qt::AltModifier; +#endif + if (key == Qt::Key_Backtab + && (ke->modifiers() == (modifier | Qt::ShiftModifier))) + gotoPreviousPage(); + else if (key == Qt::Key_Tab && (ke->modifiers() == modifier)) + gotoNextPage(); + } else if (event->type() == QEvent::KeyRelease) { + QKeyEvent *ke = static_cast(event); + if (ke->modifiers() == 0 + /*HACK this is to overcome some event inconsistencies between platforms*/ + || (ke->modifiers() == Qt::AltModifier + && (ke->key() == Qt::Key_Alt || ke->key() == -1))) { + selectAndHide(); + } + } + } + return QWidget::eventFilter(object, event); +} + +void OpenPagesSwitcher::selectPageUpDown(int summand) +{ + TRACE_OBJ + const int pageCount = m_openPagesModel->rowCount(); + if (pageCount < 2) + return; + + const QModelIndexList &list = m_openPagesWidget->selectionModel()->selectedIndexes(); + if (list.isEmpty()) + return; + + QModelIndex index = list.first(); + if (!index.isValid()) + return; + + index = m_openPagesModel->index((index.row() + summand + pageCount) % pageCount, 0); + if (index.isValid()) { + m_openPagesWidget->setCurrentIndex(index); + m_openPagesWidget->scrollTo(index, QAbstractItemView::PositionAtCenter); + } +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/openpagesswitcher.h b/src/assistant/tools/assistant/openpagesswitcher.h new file mode 100644 index 000000000..80c7e965d --- /dev/null +++ b/src/assistant/tools/assistant/openpagesswitcher.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Assistant module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef OPENPAGESSWITCHER_H +#define OPENPAGESSWITCHER_H + +#include + +QT_BEGIN_NAMESPACE + +class OpenPagesModel; +class OpenPagesWidget; +class QModelIndex; + +class OpenPagesSwitcher : public QFrame +{ + Q_OBJECT + +public: + OpenPagesSwitcher(OpenPagesModel *model); + ~OpenPagesSwitcher(); + + void gotoNextPage(); + void gotoPreviousPage(); + + void selectAndHide(); + void selectCurrentPage(); + + void setVisible(bool visible); + void focusInEvent(QFocusEvent *event); + bool eventFilter(QObject *object, QEvent *event); + +signals: + void closePage(const QModelIndex &index); + void setCurrentPage(const QModelIndex &index); + +private: + void selectPageUpDown(int summand); + +private: + OpenPagesModel *m_openPagesModel; + OpenPagesWidget *m_openPagesWidget; +}; + +QT_END_NAMESPACE + +#endif // OPENPAGESSWITCHER_H diff --git a/src/assistant/tools/assistant/openpageswidget.cpp b/src/assistant/tools/assistant/openpageswidget.cpp new file mode 100644 index 000000000..db037125b --- /dev/null +++ b/src/assistant/tools/assistant/openpageswidget.cpp @@ -0,0 +1,237 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Assistant module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "openpageswidget.h" + +#include "centralwidget.h" +#include "openpagesmodel.h" +#include "tracer.h" + +#include +#include +#include +#include +#include +#include + +#ifdef Q_WS_MAC +#include +#endif + +QT_BEGIN_NAMESPACE + +OpenPagesDelegate::OpenPagesDelegate(QObject *parent) + : QStyledItemDelegate(parent) +{ + TRACE_OBJ +} + +void OpenPagesDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + TRACE_OBJ + if (option.state & QStyle::State_MouseOver) { + if ((QApplication::mouseButtons() & Qt::LeftButton) == 0) + pressedIndex = QModelIndex(); + QBrush brush = option.palette.alternateBase(); + if (index == pressedIndex) + brush = option.palette.dark(); + painter->fillRect(option.rect, brush); + } + + QStyledItemDelegate::paint(painter, option, index); + + if (index.column() == 1 && index.model()->rowCount() > 1 + && option.state & QStyle::State_MouseOver) { + QIcon icon((option.state & QStyle::State_Selected) + ? ":/trolltech/assistant/images/closebutton.png" + : ":/trolltech/assistant/images/darkclosebutton.png"); + + const QRect iconRect(option.rect.right() - option.rect.height(), + option.rect.top(), option.rect.height(), option.rect.height()); + icon.paint(painter, iconRect, Qt::AlignRight | Qt::AlignVCenter); + } +} + +// -- OpenPagesWidget + +OpenPagesWidget::OpenPagesWidget(OpenPagesModel *model) + : m_allowContextMenu(true) +{ + TRACE_OBJ + setModel(model); + setIndentation(0); + setItemDelegate((m_delegate = new OpenPagesDelegate(this))); + + setTextElideMode(Qt::ElideMiddle); + setAttribute(Qt::WA_MacShowFocusRect, false); + + viewport()->setAttribute(Qt::WA_Hover); + setSelectionBehavior(QAbstractItemView::SelectRows); + setSelectionMode(QAbstractItemView::SingleSelection); + + header()->hide(); + header()->setStretchLastSection(false); + header()->setResizeMode(0, QHeaderView::Stretch); + header()->setResizeMode(1, QHeaderView::Fixed); + header()->resizeSection(1, 18); + + installEventFilter(this); + setUniformRowHeights(true); + setContextMenuPolicy(Qt::CustomContextMenu); + + connect(this, SIGNAL(clicked(QModelIndex)), this, + SLOT(handleClicked(QModelIndex))); + connect(this, SIGNAL(pressed(QModelIndex)), this, + SLOT(handlePressed(QModelIndex))); + connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, + SLOT(contextMenuRequested(QPoint))); +} + +OpenPagesWidget::~OpenPagesWidget() +{ + TRACE_OBJ +} + +void OpenPagesWidget::selectCurrentPage() +{ + TRACE_OBJ + const QModelIndex ¤t = + model()->index(CentralWidget::instance()->currentIndex(), 0); + + QItemSelectionModel * const selModel = selectionModel(); + selModel->select(current, + QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); + selModel->clearSelection(); + + setCurrentIndex(current); + scrollTo(currentIndex()); +} + +void OpenPagesWidget::allowContextMenu(bool ok) +{ + TRACE_OBJ + m_allowContextMenu = ok; +} + +void OpenPagesWidget::contextMenuRequested(QPoint pos) +{ + TRACE_OBJ + QModelIndex index = indexAt(pos); + if (!index.isValid() || !m_allowContextMenu) + return; + + if (index.column() == 1) + index = index.sibling(index.row(), 0); + QMenu contextMenu; + QAction *closeEditor = contextMenu.addAction(tr("Close %1").arg(index.data() + .toString())); + QAction *closeOtherEditors = contextMenu.addAction(tr("Close All Except %1") + .arg(index.data().toString())); + + if (model()->rowCount() == 1) { + closeEditor->setEnabled(false); + closeOtherEditors->setEnabled(false); + } + + QAction *action = contextMenu.exec(mapToGlobal(pos)); + if (action == closeEditor) + emit closePage(index); + else if (action == closeOtherEditors) + emit closePagesExcept(index); +} + +void OpenPagesWidget::handlePressed(const QModelIndex &index) +{ + TRACE_OBJ + if (index.column() == 0) + emit setCurrentPage(index); + + if (index.column() == 1) + m_delegate->pressedIndex = index; +} + +void OpenPagesWidget::handleClicked(const QModelIndex &index) +{ + TRACE_OBJ + // implemented here to handle the funky close button and to work around a + // bug in item views where the delegate wouldn't get the QStyle::State_MouseOver + if (index.column() == 1) { + if (model()->rowCount() > 1) + emit closePage(index); + + QWidget *vp = viewport(); + const QPoint &cursorPos = QCursor::pos(); + QMouseEvent e(QEvent::MouseMove, vp->mapFromGlobal(cursorPos), cursorPos, + Qt::NoButton, 0, 0); + QCoreApplication::sendEvent(vp, &e); + } +} + +bool OpenPagesWidget::eventFilter(QObject *obj, QEvent *event) +{ + TRACE_OBJ + if (obj != this) + return QWidget::eventFilter(obj, event); + + if (event->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast(event); + if (currentIndex().isValid() && ke->modifiers() == 0) { + const int key = ke->key(); + if (key == Qt::Key_Return || key == Qt::Key_Enter + || key == Qt::Key_Space) { + emit setCurrentPage(currentIndex()); + } else if ((key == Qt::Key_Delete || key == Qt::Key_Backspace) + && model()->rowCount() > 1) { + emit closePage(currentIndex()); + } + } + } else if (event->type() == QEvent::KeyRelease) { + QKeyEvent *ke = static_cast(event); + if (ke->modifiers() == 0 + && (ke->key() == Qt::Key_Up || ke->key() == Qt::Key_Down)) { + emit setCurrentPage(currentIndex()); + } + } + return QWidget::eventFilter(obj, event); +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/openpageswidget.h b/src/assistant/tools/assistant/openpageswidget.h new file mode 100644 index 000000000..6041fe22d --- /dev/null +++ b/src/assistant/tools/assistant/openpageswidget.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Assistant module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef OPENPAGESWIDGET_H +#define OPENPAGESWIDGET_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class OpenPagesModel; + +class OpenPagesDelegate : public QStyledItemDelegate +{ + Q_OBJECT +public: + explicit OpenPagesDelegate(QObject *parent = 0); + void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const; + + mutable QModelIndex pressedIndex; +}; + +class OpenPagesWidget : public QTreeView +{ + Q_OBJECT +public: + OpenPagesWidget(OpenPagesModel *model); + ~OpenPagesWidget(); + + void selectCurrentPage(); + void allowContextMenu(bool ok); + +signals: + void setCurrentPage(const QModelIndex &index); + void closePage(const QModelIndex &index); + void closePagesExcept(const QModelIndex &index); + +private slots: + void contextMenuRequested(QPoint pos); + void handlePressed(const QModelIndex &index); + void handleClicked(const QModelIndex &index); + +private: + bool eventFilter(QObject *obj, QEvent *event); + + bool m_allowContextMenu; + OpenPagesDelegate *m_delegate; +}; + +QT_END_NAMESPACE + +#endif // OPENPAGESWIDGET_H diff --git a/src/assistant/tools/assistant/preferencesdialog.cpp b/src/assistant/tools/assistant/preferencesdialog.cpp new file mode 100644 index 000000000..9bfd35c00 --- /dev/null +++ b/src/assistant/tools/assistant/preferencesdialog.cpp @@ -0,0 +1,507 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "preferencesdialog.h" + +#include "centralwidget.h" +#include "filternamedialog.h" +#include "fontpanel.h" +#include "helpenginewrapper.h" +#include "installdialog.h" +#include "openpagesmanager.h" +#include "tracer.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +PreferencesDialog::PreferencesDialog(QWidget *parent) + : QDialog(parent) + , m_appFontChanged(false) + , m_browserFontChanged(false) + , helpEngine(HelpEngineWrapper::instance()) +{ + TRACE_OBJ + m_ui.setupUi(this); + + connect(m_ui.buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), + this, SLOT(applyChanges())); + connect(m_ui.buttonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), + this, SLOT(reject())); + + m_hideFiltersTab = !helpEngine.filterFunctionalityEnabled(); + m_hideDocsTab = !helpEngine.documentationManagerEnabled(); + + if (!m_hideFiltersTab) { + m_ui.attributeWidget->header()->hide(); + m_ui.attributeWidget->setRootIsDecorated(false); + + connect(m_ui.attributeWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)), + this, SLOT(updateFilterMap())); + + connect(m_ui.filterWidget, + SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), this, + SLOT(updateAttributes(QListWidgetItem*))); + + connect(m_ui.filterAddButton, SIGNAL(clicked()), this, + SLOT(addFilter())); + connect(m_ui.filterRemoveButton, SIGNAL(clicked()), this, + SLOT(removeFilter())); + + updateFilterPage(); + } else { + m_ui.tabWidget->removeTab(m_ui.tabWidget->indexOf(m_ui.filtersTab)); + } + + if (!m_hideDocsTab) { + connect(m_ui.docAddButton, SIGNAL(clicked()), this, + SLOT(addDocumentationLocal())); + connect(m_ui.docRemoveButton, SIGNAL(clicked()), this, + SLOT(removeDocumentation())); + + m_docsBackup = helpEngine.registeredDocumentations(); + m_ui.registeredDocsListWidget->addItems(m_docsBackup); + } else { + m_ui.tabWidget->removeTab(m_ui.tabWidget->indexOf(m_ui.docsTab)); + } + + updateFontSettingsPage(); + updateOptionsPage(); + + if (helpEngine.usesAppFont()) + setFont(helpEngine.appFont()); +} + +PreferencesDialog::~PreferencesDialog() +{ + TRACE_OBJ + if (m_appFontChanged) { + helpEngine.setAppFont(m_appFontPanel->selectedFont()); + helpEngine.setUseAppFont(m_appFontPanel->isChecked()); + helpEngine.setAppWritingSystem(m_appFontPanel->writingSystem()); + emit updateApplicationFont(); + } + + if (m_browserFontChanged) { + helpEngine.setBrowserFont(m_browserFontPanel->selectedFont()); + helpEngine.setUseBrowserFont(m_browserFontPanel->isChecked()); + helpEngine.setBrowserWritingSystem(m_browserFontPanel->writingSystem()); + emit updateBrowserFont(); + } + + QString homePage = m_ui.homePageLineEdit->text(); + if (homePage.isEmpty()) + homePage = QLatin1String("help"); + helpEngine.setHomePage(homePage); + + int option = m_ui.helpStartComboBox->currentIndex(); + helpEngine.setStartOption(option); +} + +void PreferencesDialog::showDialog() +{ + TRACE_OBJ + if (exec() != Accepted) + m_appFontChanged = m_browserFontChanged = false; +} + +void PreferencesDialog::updateFilterPage() +{ + TRACE_OBJ + m_ui.filterWidget->clear(); + m_ui.attributeWidget->clear(); + + m_filterMapBackup.clear(); + const QStringList &filters = helpEngine.customFilters(); + foreach (const QString &filter, filters) { + if (filter == HelpEngineWrapper::TrUnfiltered) + continue; + QStringList atts = helpEngine.filterAttributes(filter); + m_filterMapBackup.insert(filter, atts); + if (!m_filterMap.contains(filter)) + m_filterMap.insert(filter, atts); + } + + m_ui.filterWidget->addItems(m_filterMap.keys()); + + foreach (const QString &a, helpEngine.filterAttributes()) + new QTreeWidgetItem(m_ui.attributeWidget, QStringList() << a); + + if (!m_filterMap.keys().isEmpty()) + m_ui.filterWidget->setCurrentRow(0); +} + +void PreferencesDialog::updateAttributes(QListWidgetItem *item) +{ + TRACE_OBJ + QStringList checkedList; + if (item) + checkedList = m_filterMap.value(item->text()); + QTreeWidgetItem *itm; + for (int i = 0; i < m_ui.attributeWidget->topLevelItemCount(); ++i) { + itm = m_ui.attributeWidget->topLevelItem(i); + if (checkedList.contains(itm->text(0))) + itm->setCheckState(0, Qt::Checked); + else + itm->setCheckState(0, Qt::Unchecked); + } +} + +void PreferencesDialog::updateFilterMap() +{ + TRACE_OBJ + if (!m_ui.filterWidget->currentItem()) + return; + QString filter = m_ui.filterWidget->currentItem()->text(); + if (!m_filterMap.contains(filter)) + return; + + QStringList newAtts; + QTreeWidgetItem *itm = 0; + for (int i = 0; i < m_ui.attributeWidget->topLevelItemCount(); ++i) { + itm = m_ui.attributeWidget->topLevelItem(i); + if (itm->checkState(0) == Qt::Checked) + newAtts.append(itm->text(0)); + } + m_filterMap[filter] = newAtts; +} + +void PreferencesDialog::addFilter() +{ + TRACE_OBJ + FilterNameDialog dia(this); + if (dia.exec() == QDialog::Rejected) + return; + + QString filterName = dia.filterName(); + if (!m_filterMap.contains(filterName)) { + m_filterMap.insert(filterName, QStringList()); + m_ui.filterWidget->addItem(filterName); + } + + QList lst = m_ui.filterWidget + ->findItems(filterName, Qt::MatchCaseSensitive); + m_ui.filterWidget->setCurrentItem(lst.first()); +} + +void PreferencesDialog::removeFilter() +{ + TRACE_OBJ + QListWidgetItem *item = + m_ui.filterWidget ->takeItem(m_ui.filterWidget->currentRow()); + if (!item) + return; + + m_filterMap.remove(item->text()); + m_removedFilters.append(item->text()); + delete item; + if (m_ui.filterWidget->count()) + m_ui.filterWidget->setCurrentRow(0); +} + +void PreferencesDialog::addDocumentationLocal() +{ + TRACE_OBJ + const QStringList fileNames = QFileDialog::getOpenFileNames(this, + tr("Add Documentation"), QString(), tr("Qt Compressed Help Files (*.qch)")); + if (fileNames.isEmpty()) + return; + + QStringList invalidFiles; + QStringList alreadyRegistered; + foreach (const QString &fileName, fileNames) { + const QString nameSpace = QHelpEngineCore::namespaceName(fileName); + if (nameSpace.isEmpty()) { + invalidFiles.append(fileName); + continue; + } + + if (m_ui.registeredDocsListWidget->findItems(nameSpace, + Qt::MatchFixedString).count()) { + alreadyRegistered.append(nameSpace); + continue; + } + + if (helpEngine.registerDocumentation(fileName)) { + m_ui.registeredDocsListWidget->addItem(nameSpace); + m_regDocs.append(nameSpace); + m_unregDocs.removeAll(nameSpace); + } + } + + if (!invalidFiles.isEmpty() || !alreadyRegistered.isEmpty()) { + QString message; + if (!alreadyRegistered.isEmpty()) { + foreach (const QString &ns, alreadyRegistered) { + message += tr("The namespace %1 is already registered!") + .arg(QString("%1").arg(ns)) + QLatin1String("
"); + } + if (!invalidFiles.isEmpty()) + message.append(QLatin1String("
")); + } + + if (!invalidFiles.isEmpty()) { + message += tr("The specified file is not a valid Qt Help File!"); + message.append(QLatin1String("
    ")); + foreach (const QString &file, invalidFiles) + message += QLatin1String("
  • ") + file + QLatin1String("
  • "); + message.append(QLatin1String("
")); + } + QMessageBox::warning(this, tr("Add Documentation"), message); + } + + updateFilterPage(); +} + +void PreferencesDialog::removeDocumentation() +{ + TRACE_OBJ + + bool foundBefore = false; + QList l = m_ui.registeredDocsListWidget->selectedItems(); + foreach (QListWidgetItem* item, l) { + const QString& ns = item->text(); + if (!foundBefore && OpenPagesManager::instance()->pagesOpenForNamespace(ns)) { + if (0 == QMessageBox::information(this, tr("Remove Documentation"), + tr("Some documents currently opened in Assistant reference the " + "documentation you are attempting to remove. Removing the " + "documentation will close those documents."), tr("Cancel"), + tr("OK"))) return; + foundBefore = true; + } + + m_unregDocs.append(ns); + delete m_ui.registeredDocsListWidget->takeItem( + m_ui.registeredDocsListWidget->row(item)); + } + + if (m_ui.registeredDocsListWidget->count()) { + m_ui.registeredDocsListWidget->setCurrentRow(0, + QItemSelectionModel::ClearAndSelect); + } +} + +void PreferencesDialog::applyChanges() +{ + TRACE_OBJ + bool filtersWereChanged = false; + if (!m_hideFiltersTab) { + if (m_filterMap.count() != m_filterMapBackup.count()) { + filtersWereChanged = true; + } else { + QMapIterator it(m_filterMapBackup); + while (it.hasNext() && !filtersWereChanged) { + it.next(); + if (!m_filterMap.contains(it.key())) { + filtersWereChanged = true; + } else { + QStringList a = it.value(); + QStringList b = m_filterMap.value(it.key()); + if (a.count() != b.count()) { + filtersWereChanged = true; + } else { + QStringList::const_iterator i(a.constBegin()); + while (i != a.constEnd()) { + if (!b.contains(*i)) { + filtersWereChanged = true; + break; + } + ++i; + } + } + } + } + } + } + + if (filtersWereChanged) { + foreach (const QString &filter, m_removedFilters) + helpEngine.removeCustomFilter(filter); + QMapIterator it(m_filterMap); + while (it.hasNext()) { + it.next(); + helpEngine.addCustomFilter(it.key(), it.value()); + } + } + + foreach (const QString &doc, m_unregDocs) { + OpenPagesManager::instance()->closePages(doc); + helpEngine.unregisterDocumentation(doc); + } + + if (filtersWereChanged || !m_regDocs.isEmpty() || !m_unregDocs.isEmpty()) + helpEngine.setupData(); + + helpEngine.setShowTabs(m_ui.showTabs->isChecked()); + if (m_showTabs != m_ui.showTabs->isChecked()) + emit updateUserInterface(); + + accept(); +} + +void PreferencesDialog::updateFontSettingsPage() +{ + TRACE_OBJ + m_browserFontPanel = new FontPanel(this); + m_browserFontPanel->setCheckable(true); + m_ui.stackedWidget_2->insertWidget(0, m_browserFontPanel); + + m_appFontPanel = new FontPanel(this); + m_appFontPanel->setCheckable(true); + m_ui.stackedWidget_2->insertWidget(1, m_appFontPanel); + + m_ui.stackedWidget_2->setCurrentIndex(0); + + const QString customSettings(tr("Use custom settings")); + m_appFontPanel->setTitle(customSettings); + + QFont font = helpEngine.appFont(); + m_appFontPanel->setSelectedFont(font); + + QFontDatabase::WritingSystem system = helpEngine.appWritingSystem(); + m_appFontPanel->setWritingSystem(system); + + m_appFontPanel->setChecked(helpEngine.usesAppFont()); + + m_browserFontPanel->setTitle(customSettings); + + font = helpEngine.browserFont(); + m_browserFontPanel->setSelectedFont(font); + + system = helpEngine.browserWritingSystem(); + m_browserFontPanel->setWritingSystem(system); + + m_browserFontPanel->setChecked(helpEngine.usesBrowserFont()); + + connect(m_appFontPanel, SIGNAL(toggled(bool)), this, + SLOT(appFontSettingToggled(bool))); + connect(m_browserFontPanel, SIGNAL(toggled(bool)), this, + SLOT(browserFontSettingToggled(bool))); + + QList allCombos = m_appFontPanel->findChildren(); + foreach (QComboBox* box, allCombos) { + connect(box, SIGNAL(currentIndexChanged(int)), this, + SLOT(appFontSettingChanged(int))); + } + + allCombos = m_browserFontPanel->findChildren(); + foreach (QComboBox* box, allCombos) { + connect(box, SIGNAL(currentIndexChanged(int)), this, + SLOT(browserFontSettingChanged(int))); + } +} + +void PreferencesDialog::appFontSettingToggled(bool on) +{ + TRACE_OBJ + Q_UNUSED(on) + m_appFontChanged = true; +} + +void PreferencesDialog::appFontSettingChanged(int index) +{ + TRACE_OBJ + Q_UNUSED(index) + m_appFontChanged = true; +} + +void PreferencesDialog::browserFontSettingToggled(bool on) +{ + TRACE_OBJ + Q_UNUSED(on) + m_browserFontChanged = true; +} + +void PreferencesDialog::browserFontSettingChanged(int index) +{ + TRACE_OBJ + Q_UNUSED(index) + m_browserFontChanged = true; +} + +void PreferencesDialog::updateOptionsPage() +{ + TRACE_OBJ + m_ui.homePageLineEdit->setText(helpEngine.homePage()); + + int option = helpEngine.startOption(); + m_ui.helpStartComboBox->setCurrentIndex(option); + + m_showTabs = helpEngine.showTabs(); + m_ui.showTabs->setChecked(m_showTabs); + + connect(m_ui.blankPageButton, SIGNAL(clicked()), this, SLOT(setBlankPage())); + connect(m_ui.currentPageButton, SIGNAL(clicked()), this, SLOT(setCurrentPage())); + connect(m_ui.defaultPageButton, SIGNAL(clicked()), this, SLOT(setDefaultPage())); +} + +void PreferencesDialog::setBlankPage() +{ + TRACE_OBJ + m_ui.homePageLineEdit->setText(QLatin1String("about:blank")); +} + +void PreferencesDialog::setCurrentPage() +{ + TRACE_OBJ + QString homepage = CentralWidget::instance()->currentSource().toString(); + if (homepage.isEmpty()) + homepage = QLatin1String("help"); + + m_ui.homePageLineEdit->setText(homepage); +} + +void PreferencesDialog::setDefaultPage() +{ + TRACE_OBJ + m_ui.homePageLineEdit->setText(helpEngine.defaultHomePage()); +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/preferencesdialog.h b/src/assistant/tools/assistant/preferencesdialog.h new file mode 100644 index 000000000..f9b445e72 --- /dev/null +++ b/src/assistant/tools/assistant/preferencesdialog.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PREFERENCESDIALOG_H +#define PREFERENCESDIALOG_H + +#include +#include "ui_preferencesdialog.h" + +QT_BEGIN_NAMESPACE + +class FontPanel; +class HelpEngineWrapper; +class QFileSystemWatcher; + +class PreferencesDialog : public QDialog +{ + Q_OBJECT + +public: + PreferencesDialog(QWidget *parent = 0); + ~PreferencesDialog(); + + void showDialog(); + +private slots: + void updateAttributes(QListWidgetItem *item); + void updateFilterMap(); + void addFilter(); + void removeFilter(); + void addDocumentationLocal(); + void removeDocumentation(); + void applyChanges(); + void appFontSettingToggled(bool on); + void appFontSettingChanged(int index); + void browserFontSettingToggled(bool on); + void browserFontSettingChanged(int index); + + void setBlankPage(); + void setCurrentPage(); + void setDefaultPage(); + +signals: + void updateBrowserFont(); + void updateApplicationFont(); + void updateUserInterface(); + +private: + void updateFilterPage(); + void updateFontSettingsPage(); + void updateOptionsPage(); + + Ui::PreferencesDialogClass m_ui; + bool m_hideFiltersTab; + bool m_hideDocsTab; + QMap m_filterMapBackup; + QMap m_filterMap; + QStringList m_removedFilters; + QStringList m_docsBackup; + QStringList m_regDocs; + QStringList m_unregDocs; + FontPanel *m_appFontPanel; + FontPanel *m_browserFontPanel; + bool m_appFontChanged; + bool m_browserFontChanged; + HelpEngineWrapper &helpEngine; + bool m_showTabs; +}; + +QT_END_NAMESPACE + +#endif // SETTINGSDIALOG_H diff --git a/src/assistant/tools/assistant/preferencesdialog.ui b/src/assistant/tools/assistant/preferencesdialog.ui new file mode 100644 index 000000000..1c6833ad9 --- /dev/null +++ b/src/assistant/tools/assistant/preferencesdialog.ui @@ -0,0 +1,400 @@ + + + PreferencesDialogClass + + + + 0 + 0 + 375 + 275 + + + + Preferences + + + + + + 0 + + + + Fonts + + + + + + + + + 0 + 0 + + + + Font settings: + + + + + + + + Browser + + + + + Application + + + + + + + + + + 0 + + + + + + + + + Filters + + + + + + Filter: + + + + + + + QFrame::NoFrame + + + Attributes: + + + + + + + + + + + 1 + + + + + + + + Add + + + + + + + Remove + + + + + + + + Documentation + + + + + + Registered Documentation: + + + + + + + 6 + + + 0 + + + + + QAbstractItemView::ExtendedSelection + + + + + + + 6 + + + 0 + + + + + Add... + + + + + + + Remove + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + Options + + + + + + + + + + + + + 0 + 0 + + + + On help start: + + + + + + + + 0 + 0 + + + + + Show my home page + + + + + Show a blank page + + + + + Show my tabs from last session + + + + + + + + Qt::Horizontal + + + + 54 + 20 + + + + + + + + + + + + + + + + + + + Homepage + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Current Page + + + + + + + Blank Page + + + + + + + Restore to default + + + + + + + + + + + + Appearance + + + + + + Show tabs for each individual page + + + + + + + + + + Qt::Vertical + + + + 20 + 72 + + + + + + + + + + + + 6 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + + comboBox + currentIndexChanged(int) + stackedWidget_2 + setCurrentIndex(int) + + + 375 + 32 + + + 347 + 125 + + + + + diff --git a/src/assistant/tools/assistant/qtdocinstaller.cpp b/src/assistant/tools/assistant/qtdocinstaller.cpp new file mode 100644 index 000000000..ffe352c87 --- /dev/null +++ b/src/assistant/tools/assistant/qtdocinstaller.cpp @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "tracer.h" + +#include +#include +#include +#include +#include +#include "helpenginewrapper.h" +#include "qtdocinstaller.h" + +QT_BEGIN_NAMESPACE + +QtDocInstaller::QtDocInstaller(const QList &docInfos) + : m_abort(false), m_docInfos(docInfos) +{ + TRACE_OBJ +} + +QtDocInstaller::~QtDocInstaller() +{ + TRACE_OBJ + if (!isRunning()) + return; + m_mutex.lock(); + m_abort = true; + m_mutex.unlock(); + wait(); +} + +void QtDocInstaller::installDocs() +{ + TRACE_OBJ + start(LowPriority); +} + +void QtDocInstaller::run() +{ + TRACE_OBJ + m_qchDir = QLibraryInfo::location(QLibraryInfo::DocumentationPath) + + QDir::separator() + QLatin1String("qch"); + m_qchFiles = m_qchDir.entryList(QStringList() << QLatin1String("*.qch")); + + bool changes = false; + foreach (const DocInfo &docInfo, m_docInfos) { + changes |= installDoc(docInfo); + m_mutex.lock(); + if (m_abort) { + m_mutex.unlock(); + return; + } + m_mutex.unlock(); + } + emit docsInstalled(changes); +} + +bool QtDocInstaller::installDoc(const DocInfo &docInfo) +{ + TRACE_OBJ + const QString &component = docInfo.first; + const QStringList &info = docInfo.second; + QDateTime dt; + if (!info.isEmpty() && !info.first().isEmpty()) + dt = QDateTime::fromString(info.first(), Qt::ISODate); + + QString qchFile; + if (info.count() == 2) + qchFile = info.last(); + + if (m_qchFiles.isEmpty()) { + emit qchFileNotFound(component); + return false; + } + foreach (const QString &f, m_qchFiles) { + if (f.startsWith(component)) { + QFileInfo fi(m_qchDir.absolutePath() + QDir::separator() + f); + if (dt.isValid() && fi.lastModified().toTime_t() == dt.toTime_t() + && qchFile == fi.absoluteFilePath()) + return false; + emit registerDocumentation(component, fi.absoluteFilePath()); + return true; + } + } + + emit qchFileNotFound(component); + return false; +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/qtdocinstaller.h b/src/assistant/tools/assistant/qtdocinstaller.h new file mode 100644 index 000000000..909df10ce --- /dev/null +++ b/src/assistant/tools/assistant/qtdocinstaller.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTDOCINSTALLER +#define QTDOCINSTALLER + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class HelpEngineWrapper; + +class QtDocInstaller : public QThread +{ + Q_OBJECT + +public: + typedef QPair DocInfo; + QtDocInstaller(const QList &docInfos); + ~QtDocInstaller(); + void installDocs(); + +signals: + void qchFileNotFound(const QString &component); + void registerDocumentation(const QString &component, + const QString &absFileName); + void docsInstalled(bool newDocsInstalled); + +private: + void run(); + bool installDoc(const DocInfo &docInfo); + + bool m_abort; + QMutex m_mutex; + QStringList m_qchFiles; + QDir m_qchDir; + QList m_docInfos; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/assistant/tools/assistant/remotecontrol.cpp b/src/assistant/tools/assistant/remotecontrol.cpp new file mode 100644 index 000000000..5d93fbc2e --- /dev/null +++ b/src/assistant/tools/assistant/remotecontrol.cpp @@ -0,0 +1,388 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "remotecontrol.h" + +#include "centralwidget.h" +#include "helpenginewrapper.h" +#include "mainwindow.h" +#include "openpagesmanager.h" +#include "tracer.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#ifdef Q_OS_WIN +# include "remotecontrol_win.h" +#endif + +QT_BEGIN_NAMESPACE + +#ifdef Q_OS_WIN + +StdInListenerWin::StdInListenerWin(QObject *parent) + : QThread(parent) +{ + TRACE_OBJ +} + +StdInListenerWin::~StdInListenerWin() +{ + TRACE_OBJ + terminate(); + wait(); +} + +void StdInListenerWin::run() +{ + TRACE_OBJ + bool ok = true; + char chBuf[4096]; + DWORD dwRead; + +#ifndef Q_WS_WINCE + HANDLE hStdin, hStdinDup; + + hStdin = GetStdHandle(STD_INPUT_HANDLE); + if (hStdin == INVALID_HANDLE_VALUE) + return; + + DuplicateHandle(GetCurrentProcess(), hStdin, + GetCurrentProcess(), &hStdinDup, + 0, false, DUPLICATE_SAME_ACCESS); + + CloseHandle(hStdin); +#else + HANDLE hStdinDup; + hStdinDup = stdin; +#endif + + while (ok) { + ok = ReadFile(hStdinDup, chBuf, sizeof(chBuf), &dwRead, NULL); + if (ok && dwRead != 0) + emit receivedCommand(QString::fromLocal8Bit(chBuf, dwRead)); + } +} +#endif + +RemoteControl::RemoteControl(MainWindow *mainWindow) + : QObject(mainWindow) + , m_mainWindow(mainWindow) + , m_debug(false) + , m_caching(true) + , m_syncContents(false) + , m_expandTOC(-2) + , helpEngine(HelpEngineWrapper::instance()) + +{ + TRACE_OBJ + connect(m_mainWindow, SIGNAL(initDone()), this, SLOT(applyCache())); +#ifdef Q_OS_WIN + StdInListenerWin *l = new StdInListenerWin(this); + connect(l, SIGNAL(receivedCommand(QString)), + this, SLOT(handleCommandString(QString))); + l->start(); +#else + QSocketNotifier *notifier = new QSocketNotifier(fileno(stdin), + QSocketNotifier::Read, this); + connect(notifier, SIGNAL(activated(int)), this, SLOT(receivedData())); + notifier->setEnabled(true); +#endif +} + +void RemoteControl::receivedData() +{ + TRACE_OBJ + QByteArray ba; + while (true) { + char c = getc(stdin); + if (c == EOF || c == '\0') + break; + if (c) + ba.append(c); + if (c == '\n') + break; + } + handleCommandString(QString::fromLocal8Bit(ba)); +} + +void RemoteControl::handleCommandString(const QString &cmdString) +{ + TRACE_OBJ + QStringList cmds = cmdString.split(QLatin1Char(';')); + QStringList::const_iterator it = cmds.constBegin(); + while (it != cmds.constEnd()) { + QString cmd, arg; + splitInputString(*it, cmd, arg); + + if (m_debug) + QMessageBox::information(0, tr("Debugging Remote Control"), + tr("Received Command: %1 %2").arg(cmd).arg(arg)); + + if (cmd == QLatin1String("debug")) + handleDebugCommand(arg); + else if (cmd == QLatin1String("show")) + handleShowOrHideCommand(arg, true); + else if (cmd == QLatin1String("hide")) + handleShowOrHideCommand(arg, false); + else if (cmd == QLatin1String("setsource")) + handleSetSourceCommand(arg); + else if (cmd == QLatin1String("synccontents")) + handleSyncContentsCommand(); + else if (cmd == QLatin1String("activatekeyword")) + handleActivateKeywordCommand(arg); + else if (cmd == QLatin1String("activateidentifier")) + handleActivateIdentifierCommand(arg); + else if (cmd == QLatin1String("expandtoc")) + handleExpandTocCommand(arg); + else if (cmd == QLatin1String("setcurrentfilter")) + handleSetCurrentFilterCommand(arg); + else if (cmd == QLatin1String("register")) + handleRegisterCommand(arg); + else if (cmd == QLatin1String("unregister")) + handleUnregisterCommand(arg); + else + return; + + ++it; + } + m_mainWindow->raise(); + m_mainWindow->activateWindow(); +} + +void RemoteControl::splitInputString(const QString &input, QString &cmd, + QString &arg) +{ + TRACE_OBJ + QString cmdLine = input.trimmed(); + int i = cmdLine.indexOf(QLatin1Char(' ')); + cmd = cmdLine.left(i); + arg = cmdLine.mid(i+1); + cmd = cmd.toLower(); +} + +void RemoteControl::handleDebugCommand(const QString &arg) +{ + TRACE_OBJ + m_debug = arg == QLatin1String("on"); +} + +void RemoteControl::handleShowOrHideCommand(const QString &arg, bool show) +{ + TRACE_OBJ + if (arg.toLower() == QLatin1String("contents")) + m_mainWindow->setContentsVisible(show); + else if (arg.toLower() == QLatin1String("index")) + m_mainWindow->setIndexVisible(show); + else if (arg.toLower() == QLatin1String("bookmarks")) + m_mainWindow->setBookmarksVisible(show); + else if (arg.toLower() == QLatin1String("search")) + m_mainWindow->setSearchVisible(show); +} + +void RemoteControl::handleSetSourceCommand(const QString &arg) +{ + TRACE_OBJ + QUrl url(arg); + if (url.isValid()) { + if (url.isRelative()) + url = CentralWidget::instance()->currentSource().resolved(url); + if (m_caching) { + clearCache(); + m_setSource = url; + } else { + CentralWidget::instance()->setSource(url); + } + } +} + +void RemoteControl::handleSyncContentsCommand() +{ + TRACE_OBJ + if (m_caching) + m_syncContents = true; + else + m_mainWindow->syncContents(); +} + +void RemoteControl::handleActivateKeywordCommand(const QString &arg) +{ + TRACE_OBJ + if (m_caching) { + clearCache(); + m_activateKeyword = arg; + } else { + m_mainWindow->setIndexString(arg); + if (!arg.isEmpty()) { + if (!helpEngine.indexWidget()->currentIndex().isValid() + && helpEngine.fullTextSearchFallbackEnabled()) { + if (QHelpSearchEngine *se = helpEngine.searchEngine()) { + m_mainWindow->setSearchVisible(true); + if (QHelpSearchQueryWidget *w = se->queryWidget()) { + w->collapseExtendedSearch(); + QList queryList; + queryList << QHelpSearchQuery(QHelpSearchQuery::DEFAULT, + QStringList(arg)); + w->setQuery(queryList); + se->search(queryList); + } + } + } else { + m_mainWindow->setIndexVisible(true); + helpEngine.indexWidget()->activateCurrentItem(); + } + } + } +} + +void RemoteControl::handleActivateIdentifierCommand(const QString &arg) +{ + TRACE_OBJ + if (m_caching) { + clearCache(); + m_activateIdentifier = arg; + } else { + const QMap &links = helpEngine.linksForIdentifier(arg); + if (!links.isEmpty()) + CentralWidget::instance()->setSource(links.constBegin().value()); + } +} + +void RemoteControl::handleExpandTocCommand(const QString &arg) +{ + TRACE_OBJ + bool ok = false; + int depth = -2; + if (!arg.isEmpty()) + depth = arg.toInt(&ok); + if (!ok || depth < -2) + depth = -2; + + if (m_caching) + m_expandTOC = depth; + else if (depth != -2) + m_mainWindow->expandTOC(depth); +} + +void RemoteControl::handleSetCurrentFilterCommand(const QString &arg) +{ + TRACE_OBJ + if (helpEngine.customFilters().contains(arg)) { + if (m_caching) { + clearCache(); + m_currentFilter = arg; + } else { + helpEngine.setCurrentFilter(arg); + } + } +} + +void RemoteControl::handleRegisterCommand(const QString &arg) +{ + TRACE_OBJ + const QString &absFileName = QFileInfo(arg).absoluteFilePath(); + if (helpEngine.registeredDocumentations(). + contains(QHelpEngineCore::namespaceName(absFileName))) + return; + if (helpEngine.registerDocumentation(absFileName)) + helpEngine.setupData(); +} + +void RemoteControl::handleUnregisterCommand(const QString &arg) +{ + TRACE_OBJ + const QString &absFileName = QFileInfo(arg).absoluteFilePath(); + const QString &ns = QHelpEngineCore::namespaceName(absFileName); + if (helpEngine.registeredDocumentations().contains(ns)) { + OpenPagesManager::instance()->closePages(ns); + if (helpEngine.unregisterDocumentation(ns)) + helpEngine.setupData(); + } +} + +void RemoteControl::applyCache() +{ + TRACE_OBJ + if (m_setSource.isValid()) { + CentralWidget::instance()->setSource(m_setSource); + } else if (!m_activateKeyword.isEmpty()) { + m_mainWindow->setIndexString(m_activateKeyword); + helpEngine.indexWidget()->activateCurrentItem(); + } else if (!m_activateIdentifier.isEmpty()) { + QMap links = + helpEngine.linksForIdentifier(m_activateIdentifier); + if (!links.isEmpty()) + CentralWidget::instance()->setSource(links.constBegin().value()); + } else if (!m_currentFilter.isEmpty()) { + helpEngine.setCurrentFilter(m_currentFilter); + } + + if (m_syncContents) + m_mainWindow->syncContents(); + + Q_ASSERT(m_expandTOC >= -2); + if (m_expandTOC != -2) + m_mainWindow->expandTOC(m_expandTOC); + + m_caching = false; +} + +void RemoteControl::clearCache() +{ + TRACE_OBJ + m_currentFilter.clear(); + m_setSource.clear(); + m_syncContents = false; + m_activateKeyword.clear(); + m_activateIdentifier.clear(); +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/remotecontrol.h b/src/assistant/tools/assistant/remotecontrol.h new file mode 100644 index 000000000..4a185f050 --- /dev/null +++ b/src/assistant/tools/assistant/remotecontrol.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef REMOTECONTROL_H +#define REMOTECONTROL_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class HelpEngineWrapper; +class MainWindow; + +class RemoteControl : public QObject +{ + Q_OBJECT + +public: + RemoteControl(MainWindow *mainWindow); + +private slots: + void receivedData(); + void handleCommandString(const QString &cmdString); + void applyCache(); + +private: + void clearCache(); + void splitInputString(const QString &input, QString &cmd, QString &arg); + void handleDebugCommand(const QString &arg); + void handleShowOrHideCommand(const QString &arg, bool show); + void handleSetSourceCommand(const QString &arg); + void handleSyncContentsCommand(); + void handleActivateKeywordCommand(const QString &arg); + void handleActivateIdentifierCommand(const QString &arg); + void handleExpandTocCommand(const QString &arg); + void handleSetCurrentFilterCommand(const QString &arg); + void handleRegisterCommand(const QString &arg); + void handleUnregisterCommand(const QString &arg); + +private: + MainWindow *m_mainWindow; + bool m_debug; + + bool m_caching; + QUrl m_setSource; + bool m_syncContents; + QString m_activateKeyword; + QString m_activateIdentifier; + int m_expandTOC; + QString m_currentFilter; + HelpEngineWrapper &helpEngine; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/assistant/tools/assistant/remotecontrol_win.h b/src/assistant/tools/assistant/remotecontrol_win.h new file mode 100644 index 000000000..807815df1 --- /dev/null +++ b/src/assistant/tools/assistant/remotecontrol_win.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef REMOTECONTROL_WIN_H +#define REMOTECONTROL_WIN_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class StdInListenerWin : public QThread +{ + Q_OBJECT + +public: + StdInListenerWin(QObject *parent); + ~StdInListenerWin(); + +signals: + void receivedCommand(const QString &cmd); + +private: + void run(); + bool ok; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/assistant/tools/assistant/searchwidget.cpp b/src/assistant/tools/assistant/searchwidget.cpp new file mode 100644 index 000000000..627d9e745 --- /dev/null +++ b/src/assistant/tools/assistant/searchwidget.cpp @@ -0,0 +1,237 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "tracer.h" + +#include "mainwindow.h" +#include "searchwidget.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +SearchWidget::SearchWidget(QHelpSearchEngine *engine, QWidget *parent) + : QWidget(parent) + , zoomCount(0) + , searchEngine(engine) +{ + TRACE_OBJ + QVBoxLayout *vLayout = new QVBoxLayout(this); + + resultWidget = searchEngine->resultWidget(); + QHelpSearchQueryWidget *queryWidget = searchEngine->queryWidget(); + + vLayout->addWidget(queryWidget); + vLayout->addWidget(resultWidget); + + setFocusProxy(queryWidget); + + connect(queryWidget, SIGNAL(search()), this, SLOT(search())); + connect(resultWidget, SIGNAL(requestShowLink(QUrl)), this, + SIGNAL(requestShowLink(QUrl))); + + connect(searchEngine, SIGNAL(searchingStarted()), this, + SLOT(searchingStarted())); + connect(searchEngine, SIGNAL(searchingFinished(int)), this, + SLOT(searchingFinished(int))); + + QTextBrowser* browser = resultWidget->findChild(); + if (browser) // Will be null if lib was configured not to use CLucene. + browser->viewport()->installEventFilter(this); +} + +SearchWidget::~SearchWidget() +{ + TRACE_OBJ + // nothing todo +} + +void SearchWidget::zoomIn() +{ + TRACE_OBJ + QTextBrowser* browser = resultWidget->findChild(); + if (browser && zoomCount != 10) { + zoomCount++; + browser->zoomIn(); + } +} + +void SearchWidget::zoomOut() +{ + TRACE_OBJ + QTextBrowser* browser = resultWidget->findChild(); + if (browser && zoomCount != -5) { + zoomCount--; + browser->zoomOut(); + } +} + +void SearchWidget::resetZoom() +{ + TRACE_OBJ + if (zoomCount == 0) + return; + + QTextBrowser* browser = resultWidget->findChild(); + if (browser) { + browser->zoomOut(zoomCount); + zoomCount = 0; + } +} + +void SearchWidget::search() const +{ + TRACE_OBJ + QList query = searchEngine->queryWidget()->query(); + searchEngine->search(query); +} + +void SearchWidget::searchingStarted() +{ + TRACE_OBJ + qApp->setOverrideCursor(QCursor(Qt::WaitCursor)); +} + +void SearchWidget::searchingFinished(int hits) +{ + TRACE_OBJ + Q_UNUSED(hits) + qApp->restoreOverrideCursor(); +} + +bool SearchWidget::eventFilter(QObject* o, QEvent *e) +{ + TRACE_OBJ + QTextBrowser* browser = resultWidget->findChild(); + if (browser && o == browser->viewport() + && e->type() == QEvent::MouseButtonRelease){ + QMouseEvent *me = static_cast(e); + QUrl link = resultWidget->linkAt(me->pos()); + if (!link.isEmpty() || link.isValid()) { + bool controlPressed = me->modifiers() & Qt::ControlModifier; + if((me->button() == Qt::LeftButton && controlPressed) + || (me->button() == Qt::MidButton)) { + emit requestShowLinkInNewTab(link); + } + } + } + return QWidget::eventFilter(o,e); +} + +void SearchWidget::keyPressEvent(QKeyEvent *keyEvent) +{ + TRACE_OBJ + if (keyEvent->key() == Qt::Key_Escape) + MainWindow::activateCurrentBrowser(); + else + keyEvent->ignore(); +} + +void SearchWidget::contextMenuEvent(QContextMenuEvent *contextMenuEvent) +{ + TRACE_OBJ + QMenu menu; + QPoint point = contextMenuEvent->globalPos(); + + QTextBrowser* browser = resultWidget->findChild(); + if (!browser) + return; + + point = browser->mapFromGlobal(point); + if (!browser->rect().contains(point, true)) + return; + + QUrl link = browser->anchorAt(point); + + QKeySequence keySeq(QKeySequence::Copy); + QAction *copyAction = menu.addAction(tr("&Copy") + QLatin1String("\t") + + keySeq.toString(QKeySequence::NativeText)); + copyAction->setEnabled(QTextCursor(browser->textCursor()).hasSelection()); + + QAction *copyAnchorAction = menu.addAction(tr("Copy &Link Location")); + copyAnchorAction->setEnabled(!link.isEmpty() && link.isValid()); + + keySeq = QKeySequence(Qt::CTRL); + QAction *newTabAction = menu.addAction(tr("Open Link in New Tab") + + QLatin1String("\t") + keySeq.toString(QKeySequence::NativeText) + + QLatin1String("LMB")); + newTabAction->setEnabled(!link.isEmpty() && link.isValid()); + + menu.addSeparator(); + + keySeq = QKeySequence::SelectAll; + QAction *selectAllAction = menu.addAction(tr("Select All") + + QLatin1String("\t") + keySeq.toString(QKeySequence::NativeText)); + + QAction *usedAction = menu.exec(mapToGlobal(contextMenuEvent->pos())); + if (usedAction == copyAction) { + QTextCursor cursor = browser->textCursor(); + if (!cursor.isNull() && cursor.hasSelection()) { + QString selectedText = cursor.selectedText(); + QMimeData *data = new QMimeData(); + data->setText(selectedText); + QApplication::clipboard()->setMimeData(data); + } + } + else if (usedAction == copyAnchorAction) { + QApplication::clipboard()->setText(link.toString()); + } + else if (usedAction == newTabAction) { + emit requestShowLinkInNewTab(link); + } + else if (usedAction == selectAllAction) { + browser->selectAll(); + } +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/searchwidget.h b/src/assistant/tools/assistant/searchwidget.h new file mode 100644 index 000000000..077c78771 --- /dev/null +++ b/src/assistant/tools/assistant/searchwidget.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SEARCHWIDGET_H +#define SEARCHWIDGET_H + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QMouseEvent; +class QHelpSearchEngine; +class QHelpSearchResultWidget; + +class SearchWidget : public QWidget +{ + Q_OBJECT + +public: + explicit SearchWidget(QHelpSearchEngine *engine, QWidget *parent = 0); + ~SearchWidget(); + + void zoomIn(); + void zoomOut(); + void resetZoom(); + +signals: + void requestShowLink(const QUrl &url); + void requestShowLinkInNewTab(const QUrl &url); + +private slots: + void search() const; + void searchingStarted(); + void searchingFinished(int hits); + +private: + bool eventFilter(QObject* o, QEvent *e); + void keyPressEvent(QKeyEvent *keyEvent); + void contextMenuEvent(QContextMenuEvent *contextMenuEvent); + +private: + int zoomCount; + QHelpSearchEngine *searchEngine; + QHelpSearchResultWidget *resultWidget; +}; + +QT_END_NAMESPACE + +#endif // SEARCHWIDGET_H diff --git a/src/assistant/tools/assistant/topicchooser.cpp b/src/assistant/tools/assistant/topicchooser.cpp new file mode 100644 index 000000000..6f2810bf4 --- /dev/null +++ b/src/assistant/tools/assistant/topicchooser.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "tracer.h" + +#include "topicchooser.h" + +QT_BEGIN_NAMESPACE + +TopicChooser::TopicChooser(QWidget *parent, const QString &keyword, + const QMap &links) + : QDialog(parent) +{ + TRACE_OBJ + ui.setupUi(this); + ui.label->setText(tr("Choose a topic for %1:").arg(keyword)); + + QMap::const_iterator it = links.constBegin(); + for (; it != links.constEnd(); ++it) { + ui.listWidget->addItem(it.key()); + m_links.append(it.value()); + } + + if (ui.listWidget->count() != 0) + ui.listWidget->setCurrentRow(0); + ui.listWidget->setFocus(); + + connect(ui.buttonDisplay, SIGNAL(clicked()), this, SLOT(accept())); + connect(ui.buttonCancel, SIGNAL(clicked()), this, SLOT(reject())); + connect(ui.listWidget, SIGNAL(itemActivated(QListWidgetItem*)), this, + SLOT(accept())); +} + +QUrl TopicChooser::link() const +{ + TRACE_OBJ + QListWidgetItem *item = ui.listWidget->currentItem(); + if (!item) + return QUrl(); + + QString title = item->text(); + if (title.isEmpty()) + return QUrl(); + + const int row = ui.listWidget->row(item); + Q_ASSERT(row < m_links.count()); + return m_links.at(row); +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/topicchooser.h b/src/assistant/tools/assistant/topicchooser.h new file mode 100644 index 000000000..a80f1963d --- /dev/null +++ b/src/assistant/tools/assistant/topicchooser.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TOPICCHOOSER_H +#define TOPICCHOOSER_H + +#include "ui_topicchooser.h" + +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class TopicChooser : public QDialog +{ + Q_OBJECT + +public: + TopicChooser(QWidget *parent, const QString &keyword, + const QMap &links); + + QUrl link() const; + +private: + Ui::TopicChooser ui; + QList m_links; +}; + +QT_END_NAMESPACE + +#endif // TOPICCHOOSER_H diff --git a/src/assistant/tools/assistant/topicchooser.ui b/src/assistant/tools/assistant/topicchooser.ui new file mode 100644 index 000000000..d4c90bb4b --- /dev/null +++ b/src/assistant/tools/assistant/topicchooser.ui @@ -0,0 +1,116 @@ + + TopicChooser + + + TopicChooser + + + + 0 + 0 + 391 + 223 + + + + Choose Topic + + + true + + + + unnamed + + + 11 + + + 6 + + + + + label + + + &Topics + + + listWidget + + + + + + + listWidget + + + + + + + Layout16 + + + + unnamed + + + 0 + + + 6 + + + + + + 20 + 20 + + + + Expanding + + + Horizontal + + + + + + + buttonDisplay + + + &Display + + + true + + + true + + + + + + + buttonCancel + + + &Close + + + true + + + + + + + + + diff --git a/src/assistant/tools/assistant/tracer.h b/src/assistant/tools/assistant/tracer.h new file mode 100644 index 000000000..1ed609acb --- /dev/null +++ b/src/assistant/tools/assistant/tracer.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TRACER_H +#define TRACER_H + +#include + +QT_BEGIN_NAMESPACE + +class Tracer +{ +public: + Tracer(const char *func) : m_func(func) + { + qDebug("Entering function %s.", m_func); + } + + ~Tracer() + { + qDebug("Leaving function %s.", m_func); + } + +private: + const char * const m_func; +}; + +QT_END_NAMESPACE + +// #define TRACING_REQUESTED +#ifdef TRACING_REQUESTED +#define TRACE_OBJ Tracer traceObj__(Q_FUNC_INFO); +#else +#define TRACE_OBJ +#endif + +#endif // TRACER_H diff --git a/src/assistant/tools/assistant/xbelsupport.cpp b/src/assistant/tools/assistant/xbelsupport.cpp new file mode 100644 index 000000000..2979d10c1 --- /dev/null +++ b/src/assistant/tools/assistant/xbelsupport.cpp @@ -0,0 +1,233 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "tracer.h" + +#include "xbelsupport.h" + +#include "bookmarkitem.h" +#include "bookmarkmodel.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +struct Bookmark { + QString title; + QString url; + bool folded; +}; + +XbelWriter::XbelWriter(BookmarkModel *model) + : QXmlStreamWriter() + , bookmarkModel(model) +{ + TRACE_OBJ + setAutoFormatting(true); +} + +void XbelWriter::writeToFile(QIODevice *device) +{ + TRACE_OBJ + setDevice(device); + + writeStartDocument(); + writeDTD(QLatin1String("")); + writeStartElement(QLatin1String("xbel")); + writeAttribute(QLatin1String("version"), QLatin1String("1.0")); + + const QModelIndex &root = bookmarkModel->index(0,0, QModelIndex()); + for (int i = 0; i < bookmarkModel->rowCount(root); ++i) + writeData(bookmarkModel->index(i, 0, root)); + writeEndDocument(); +} + +void XbelWriter::writeData(const QModelIndex &index) +{ + TRACE_OBJ + if (index.isValid()) { + Bookmark entry; + entry.title = index.data().toString(); + entry.url = index.data(UserRoleUrl).toString(); + + if (index.data(UserRoleFolder).toBool()) { + writeStartElement(QLatin1String("folder")); + entry.folded = !index.data(UserRoleExpanded).toBool(); + writeAttribute(QLatin1String("folded"), entry.folded + ? QLatin1String("yes") : QLatin1String("no")); + writeTextElement(QLatin1String("title"), entry.title); + + for (int i = 0; i < bookmarkModel->rowCount(index); ++i) + writeData(bookmarkModel->index(i, 0 , index)); + writeEndElement(); + } else { + writeStartElement(QLatin1String("bookmark")); + writeAttribute(QLatin1String("href"), entry.url); + writeTextElement(QLatin1String("title"), entry.title); + writeEndElement(); + } + } +} + +// -- XbelReader + +XbelReader::XbelReader(BookmarkModel *model) + : QXmlStreamReader() + , bookmarkModel(model) +{ + TRACE_OBJ +} + +bool XbelReader::readFromFile(QIODevice *device) +{ + TRACE_OBJ + setDevice(device); + + while (!atEnd()) { + readNext(); + + if (isStartElement()) { + if (name() == QLatin1String("xbel") + && attributes().value(QLatin1String("version")) + == QLatin1String("1.0")) { + const QModelIndex &root = bookmarkModel->index(0,0, QModelIndex()); + parents.append(bookmarkModel->addItem(root, true)); + readXBEL(); + bookmarkModel->setData(parents.first(), + QDate::currentDate().toString(Qt::ISODate), Qt::EditRole); + } else { + raiseError(QLatin1String("The file is not an XBEL version 1.0 file.")); + } + } + } + + return !error(); +} + +void XbelReader::readXBEL() +{ + TRACE_OBJ + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + if (name() == QLatin1String("folder")) + readFolder(); + else if (name() == QLatin1String("bookmark")) + readBookmark(); + else + readUnknownElement(); + } + } +} + +void XbelReader::readFolder() +{ + TRACE_OBJ + parents.append(bookmarkModel->addItem(parents.last(), true)); + bookmarkModel->setData(parents.last(), + attributes().value(QLatin1String("folded")) == QLatin1String("no"), + UserRoleExpanded); + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + if (name() == QLatin1String("title")) { + bookmarkModel->setData(parents.last(), readElementText(), + Qt::EditRole); + } else if (name() == QLatin1String("folder")) + readFolder(); + else if (name() == QLatin1String("bookmark")) + readBookmark(); + else + readUnknownElement(); + } + } + + parents.removeLast(); +} + +void XbelReader::readBookmark() +{ + TRACE_OBJ + const QModelIndex &index = bookmarkModel->addItem(parents.last(), false); + if (BookmarkItem* item = bookmarkModel->itemFromIndex(index)) { + item->setData(UserRoleUrl, attributes().value(QLatin1String("href")) + .toString()); + } + + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) { + if (name() == QLatin1String("title")) + bookmarkModel->setData(index, readElementText(), Qt::EditRole); + else + readUnknownElement(); + } + } +} + +void XbelReader::readUnknownElement() +{ + TRACE_OBJ + while (!atEnd()) { + readNext(); + + if (isEndElement()) + break; + + if (isStartElement()) + readUnknownElement(); + } +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/assistant/xbelsupport.h b/src/assistant/tools/assistant/xbelsupport.h new file mode 100644 index 000000000..4c2a211ad --- /dev/null +++ b/src/assistant/tools/assistant/xbelsupport.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef XBELSUPPORT_H +#define XBELSUPPORT_H + +#include +#include + +QT_FORWARD_DECLARE_CLASS(QIODevice) +QT_FORWARD_DECLARE_CLASS(QModelIndex) + +QT_BEGIN_NAMESPACE + +class BookmarkModel; + +class XbelWriter : public QXmlStreamWriter +{ +public: + XbelWriter(BookmarkModel *model); + void writeToFile(QIODevice *device); + +private: + void writeData(const QModelIndex &index); + +private: + BookmarkModel *bookmarkModel; +}; + +class XbelReader : public QXmlStreamReader +{ +public: + XbelReader(BookmarkModel *model); + bool readFromFile(QIODevice *device); + +private: + void readXBEL(); + void readFolder(); + void readBookmark(); + void readUnknownElement(); + +private: + BookmarkModel *bookmarkModel; + QList parents; +}; + +QT_END_NAMESPACE + +#endif // XBELSUPPORT_H diff --git a/src/assistant/tools/qcollectiongenerator/main.cpp b/src/assistant/tools/qcollectiongenerator/main.cpp new file mode 100644 index 000000000..058d4281a --- /dev/null +++ b/src/assistant/tools/qcollectiongenerator/main.cpp @@ -0,0 +1,615 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../shared/collectionconfiguration.h" +#include "../shared/helpgenerator.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +QT_USE_NAMESPACE + +class QCG { + Q_DECLARE_TR_FUNCTIONS(QCollectionGenerator) +}; + +class CollectionConfigReader : public QXmlStreamReader +{ +public: + void readData(const QByteArray &contents); + + QString title() const { return m_title; } + QString homePage() const { return m_homePage; } + QString startPage() const { return m_startPage; } + QString applicationIcon() const { return m_applicationIcon; } + QString currentFilter() const { return m_currentFilter; } + bool enableFilterFunctionality() const + { return m_enableFilterFunctionality; } + bool hideFilterFunctionality() const + { return m_hideFilterFunctionality; } + bool enableAddressBar() const { return m_enableAddressBar; } + bool hideAddressBar() const { return m_hideAddressBar; } + bool enableDocumentationManager() const + { return m_enableDocumentationManager; } + + QMap aboutMenuTexts() const + { return m_aboutMenuTexts; } + QString aboutIcon() const { return m_aboutIcon; } + QMap aboutTextFiles() const + { return m_aboutTextFiles; } + + QMap filesToGenerate() const + { return m_filesToGenerate; } + + QStringList filesToRegister() const { return m_filesToRegister; } + + QString cacheDirectory() const { return m_cacheDirectory; } + bool cacheDirRelativeToCollection() const { return m_cacheDirRelativeToCollection; } + + bool fullTextSearchFallbackEnabled() const { + return m_enableFullTextSearchFallback; + } + +private: + void raiseErrorWithLine(); + void readConfig(); + void readAssistantSettings(); + void readMenuTexts(); + void readAboutDialog(); + void readDocFiles(); + void readGenerate(); + void readFiles(); + void readRegister(); + + QString m_title; + QString m_homePage; + QString m_startPage; + QString m_applicationIcon; + QString m_currentFilter; + bool m_enableFilterFunctionality; + bool m_hideFilterFunctionality; + bool m_enableAddressBar; + bool m_hideAddressBar; + bool m_enableDocumentationManager; + QMap m_aboutMenuTexts; + QString m_aboutIcon; + QMap m_aboutTextFiles; + QMap m_filesToGenerate; + QStringList m_filesToRegister; + QString m_cacheDirectory; + bool m_cacheDirRelativeToCollection; + bool m_enableFullTextSearchFallback; +}; + +void CollectionConfigReader::raiseErrorWithLine() +{ + raiseError(QCG::tr("Unknown token at line %1.").arg(lineNumber())); +} + +void CollectionConfigReader::readData(const QByteArray &contents) +{ + m_enableFilterFunctionality = true; + m_hideFilterFunctionality = true; + m_enableAddressBar = true; + m_hideAddressBar = true; + m_enableDocumentationManager = true; + m_enableFullTextSearchFallback = false; + + addData(contents); + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("QHelpCollectionProject") + && attributes().value(QLatin1String("version")) == QLatin1String("1.0")) + readConfig(); + else + raiseError(QCG::tr("Unknown token at line %1. " + "Expected \"QtHelpCollectionProject\".") + .arg(lineNumber())); + } + } +} + +void CollectionConfigReader::readConfig() +{ + bool ok = false; + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("assistant")) + readAssistantSettings(); + else if (name() == QLatin1String("docFiles")) + readDocFiles(); + else + raiseErrorWithLine(); + } else if (isEndElement() && name() == QLatin1String("QHelpCollectionProject")) { + ok = true; + } + } + if (!ok && !hasError()) + raiseError(QCG::tr("Missing end tags.")); +} + +void CollectionConfigReader::readAssistantSettings() +{ + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("title")) { + m_title = readElementText(); + } else if (name() == QLatin1String("homePage")) { + m_homePage = readElementText(); + } else if (name() == QLatin1String("startPage")) { + m_startPage = readElementText(); + } else if (name() == QLatin1String("currentFilter")) { + m_currentFilter = readElementText(); + } else if (name() == QLatin1String("applicationIcon")) { + m_applicationIcon = readElementText(); + } else if (name() == QLatin1String("enableFilterFunctionality")) { + if (attributes().value(QLatin1String("visible")) == QLatin1String("true")) + m_hideFilterFunctionality = false; + if (readElementText() == QLatin1String("false")) + m_enableFilterFunctionality = false; + } else if (name() == QLatin1String("enableDocumentationManager")) { + if (readElementText() == QLatin1String("false")) + m_enableDocumentationManager = false; + } else if (name() == QLatin1String("enableAddressBar")) { + if (attributes().value(QLatin1String("visible")) == QLatin1String("true")) + m_hideAddressBar = false; + if (readElementText() == QLatin1String("false")) + m_enableAddressBar = false; + } else if (name() == QLatin1String("aboutMenuText")) { + readMenuTexts(); + } else if (name() == QLatin1String("aboutDialog")) { + readAboutDialog(); + } else if (name() == "cacheDirectory") { + m_cacheDirRelativeToCollection = + attributes().value(QLatin1String("base")) + == QLatin1String("collection"); + m_cacheDirectory = readElementText(); + } else if (name() == QLatin1String("enableFullTextSearchFallback")) { + if (readElementText() == QLatin1String("true")) + m_enableFullTextSearchFallback = true; + } else { + raiseErrorWithLine(); + } + } else if (isEndElement() && name() == QLatin1String("assistant")) { + break; + } + } +} + +void CollectionConfigReader::readMenuTexts() +{ + while (!atEnd()) + { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("text")) { + QString lang = attributes().value(QLatin1String("language")).toString(); + if (lang.isEmpty()) + lang = QLatin1String("default"); + m_aboutMenuTexts.insert(lang, readElementText()); + } else { + raiseErrorWithLine(); + } + } else if (isEndElement() && name() == QLatin1String("aboutMenuText")) { + break; + } + } +} + +void CollectionConfigReader::readAboutDialog() +{ + while (!atEnd()) + { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("file")) { + QString lang = attributes().value(QLatin1String("language")).toString(); + if (lang.isEmpty()) + lang = QLatin1String("default"); + m_aboutTextFiles.insert(lang, readElementText()); + } else if (name() == QLatin1String("icon")) { + m_aboutIcon = readElementText(); + } else { + raiseErrorWithLine(); + } + } else if (isEndElement() && name() == QLatin1String("aboutDialog")) { + break; + } + } +} + +void CollectionConfigReader::readDocFiles() +{ + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("generate")) { + readGenerate(); + } else if (name() == QLatin1String("register")) { + readRegister(); + } else { + raiseErrorWithLine(); + } + } else if (isEndElement() && name() == QLatin1String("docFiles")) { + break; + } + } +} + +void CollectionConfigReader::readGenerate() +{ + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("file")) + readFiles(); + else + raiseErrorWithLine(); + } else if (isEndElement() && name() == QLatin1String("generate")) { + break; + } + } +} + +void CollectionConfigReader::readFiles() +{ + QString input; + QString output; + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("input")) + input = readElementText(); + else if (name() == QLatin1String("output")) + output = readElementText(); + else + raiseErrorWithLine(); + } else if (isEndElement() && name() == QLatin1String("file")) { + break; + } + } + if (input.isEmpty() || output.isEmpty()) { + raiseError(QCG::tr("Missing input or output file for help file generation.")); + return; + } + m_filesToGenerate.insert(input, output); +} + +void CollectionConfigReader::readRegister() +{ + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name() == QLatin1String("file")) + m_filesToRegister.append(readElementText()); + else + raiseErrorWithLine(); + } else if (isEndElement() && name() == QLatin1String("register")) { + break; + } + } +} + +namespace { + QString absoluteFileName(const QString &basePath, const QString &fileName) + { + return QFileInfo(fileName).isAbsolute() ? + fileName : basePath + QDir::separator() + fileName; + } +} + +int main(int argc, char *argv[]) +{ + QString error; + QString arg; + QString collectionFile; + QString configFile; + QString basePath; + bool showHelp = false; + bool showVersion = false; + + QCoreApplication app(argc, argv); +#ifndef Q_OS_WIN32 + QTranslator translator; + QTranslator qtTranslator; + QTranslator qt_helpTranslator; + QString sysLocale = QLocale::system().name(); + QString resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath); + if (translator.load(QLatin1String("assistant_") + sysLocale, resourceDir) + && qtTranslator.load(QLatin1String("qt_") + sysLocale, resourceDir) + && qt_helpTranslator.load(QLatin1String("qt_help_") + sysLocale, resourceDir)) { + app.installTranslator(&translator); + app.installTranslator(&qtTranslator); + app.installTranslator(&qt_helpTranslator); + } +#endif // Q_OS_WIN32 + + for (int i=1; i [options]\n\n" + " -o Generates a collection file\n" + " called . If\n" + " this option is not specified\n" + " a default name will be used.\n" + " -v Displays the version of\n" + " qcollectiongenerator.\n\n"); + + if (showHelp) { + fputs(qPrintable(help), stdout); + return 0; + }else if (!error.isEmpty()) { + fprintf(stderr, "%s\n\n%s", qPrintable(error), qPrintable(help)); + return -1; + } + + QFile file(configFile); + if (!file.open(QIODevice::ReadOnly)) { + fputs(qPrintable(QCG::tr("Could not open %1.\n").arg(configFile)), stderr); + return -1; + } + + if (collectionFile.isEmpty()) { + QFileInfo fi(configFile); + collectionFile = basePath + QDir::separator() + + fi.baseName() + QLatin1String(".qhc"); + } + + fputs(qPrintable(QCG::tr("Reading collection config file...\n")), stdout); + CollectionConfigReader config; + config.readData(file.readAll()); + if (config.hasError()) { + fputs(qPrintable(QCG::tr("Collection config file error: %1\n") + .arg(config.errorString())), stderr); + return -1; + } + + QMap::const_iterator it = config.filesToGenerate().constBegin(); + while (it != config.filesToGenerate().constEnd()) { + fputs(qPrintable(QCG::tr("Generating help for %1...\n").arg(it.key())), stdout); + QHelpProjectData helpData; + if (!helpData.readData(absoluteFileName(basePath, it.key()))) { + fprintf(stderr, "%s\n", qPrintable(helpData.errorMessage())); + return -1; + } + + HelpGenerator helpGenerator; + if (!helpGenerator.generate(&helpData, absoluteFileName(basePath, it.value()))) { + fprintf(stderr, "%s\n", qPrintable(helpGenerator.error())); + return -1; + } + ++it; + } + + fputs(qPrintable(QCG::tr("Creating collection file...\n")), stdout); + + QFileInfo colFi(collectionFile); + if (colFi.exists()) { + if (!colFi.dir().remove(colFi.fileName())) { + fputs(qPrintable(QCG::tr("The file %1 cannot be overwritten.\n") + .arg(collectionFile)), stderr); + return -1; + } + } + + QHelpEngineCore helpEngine(collectionFile); + if (!helpEngine.setupData()) { + fprintf(stderr, "%s\n", qPrintable(helpEngine.error())); + return -1; + } + + foreach (const QString &file, config.filesToRegister()) { + if (!helpEngine.registerDocumentation(absoluteFileName(basePath, file))) { + fprintf(stderr, "%s\n", qPrintable(helpEngine.error())); + return -1; + } + } + if (!config.filesToRegister().isEmpty()) + CollectionConfiguration::updateLastRegisterTime(helpEngine); + + if (!config.title().isEmpty()) + CollectionConfiguration::setWindowTitle(helpEngine, config.title()); + + if (!config.homePage().isEmpty()) { + CollectionConfiguration::setDefaultHomePage(helpEngine, + config.homePage()); + } + + if (!config.startPage().isEmpty()) { + CollectionConfiguration::setLastShownPages(helpEngine, + QStringList(config.startPage())); + } + + if (!config.currentFilter().isEmpty()) { + helpEngine.setCurrentFilter(config.currentFilter()); + } + + if (!config.cacheDirectory().isEmpty()) { + CollectionConfiguration::setCacheDir(helpEngine, config.cacheDirectory(), + config.cacheDirRelativeToCollection()); + } + + CollectionConfiguration::setFilterFunctionalityEnabled(helpEngine, + config.enableFilterFunctionality()); + CollectionConfiguration::setFilterToolbarVisible(helpEngine, + !config.hideFilterFunctionality()); + CollectionConfiguration::setDocumentationManagerEnabled(helpEngine, + config.enableDocumentationManager()); + CollectionConfiguration::setAddressBarEnabled(helpEngine, + config.enableAddressBar()); + CollectionConfiguration::setAddressBarVisible(helpEngine, + !config.hideAddressBar()); + CollectionConfiguration::setCreationTime(helpEngine, + QDateTime::currentDateTime().toTime_t()); + CollectionConfiguration::setFullTextSearchFallbackEnabled(helpEngine, + config.fullTextSearchFallbackEnabled()); + + if (!config.applicationIcon().isEmpty()) { + QFile icon(absoluteFileName(basePath, config.applicationIcon())); + if (!icon.open(QIODevice::ReadOnly)) { + fputs(qPrintable(QCG::tr("Cannot open %1.\n").arg(icon.fileName())), stderr); + return -1; + } + CollectionConfiguration::setApplicationIcon(helpEngine, icon.readAll()); + } + + if (config.aboutMenuTexts().count()) { + QByteArray ba; + QDataStream s(&ba, QIODevice::WriteOnly); + QMap::const_iterator it = config.aboutMenuTexts().constBegin(); + while (it != config.aboutMenuTexts().constEnd()) { + s << it.key(); + s << it.value(); + ++it; + } + CollectionConfiguration::setAboutMenuTexts(helpEngine, ba); + } + + if (!config.aboutIcon().isEmpty()) { + QFile icon(absoluteFileName(basePath, config.aboutIcon())); + if (!icon.open(QIODevice::ReadOnly)) { + fputs(qPrintable(QCG::tr("Cannot open %1.\n").arg(icon.fileName())), stderr); + return -1; + } + CollectionConfiguration::setAboutIcon(helpEngine, icon.readAll()); + } + + if (config.aboutTextFiles().count()) { + QByteArray ba; + QDataStream s(&ba, QIODevice::WriteOnly); + QMap::const_iterator it = config.aboutTextFiles().constBegin(); + QMap imgData; + + QRegExp srcRegExp(QLatin1String("src=(\"(.+)\"|([^\"\\s]+)).*>")); + srcRegExp.setMinimal(true); + QRegExp imgRegExp(QLatin1String("(]+>)")); + imgRegExp.setMinimal(true); + + while (it != config.aboutTextFiles().constEnd()) { + s << it.key(); + QFileInfo fi(absoluteFileName(basePath, it.value())); + QFile f(fi.absoluteFilePath()); + if (!f.open(QIODevice::ReadOnly)) { + fputs(qPrintable(QCG::tr("Cannot open %1.\n").arg(f.fileName())), stderr); + return -1; + } + QByteArray data = f.readAll(); + s << data; + + QString contents = QString::fromUtf8(data); + int pos = 0; + while ((pos = imgRegExp.indexIn(contents, pos)) != -1) { + QString imgTag = imgRegExp.cap(1); + pos += imgRegExp.matchedLength(); + + if (srcRegExp.indexIn(imgTag, 0) != -1) { + QString src = srcRegExp.cap(2); + if (src.isEmpty()) + src = srcRegExp.cap(3); + + QFile img(fi.absolutePath() + QDir::separator() + src); + if (img.open(QIODevice::ReadOnly)) { + if (!imgData.contains(src)) + imgData.insert(src, img.readAll()); + } else { + fputs(qPrintable(QCG::tr("Cannot open referenced image file %1.\n") + .arg(img.fileName())), stderr); + } + } + } + ++it; + } + CollectionConfiguration::setAboutTexts(helpEngine, ba); + if (imgData.count()) { + QByteArray imageData; + QBuffer buffer(&imageData); + buffer.open(QIODevice::WriteOnly); + QDataStream out(&buffer); + out << imgData; + CollectionConfiguration::setAboutImages(helpEngine, imageData); + } + } + + return 0; +} diff --git a/src/assistant/tools/qcollectiongenerator/qcollectiongenerator.pro b/src/assistant/tools/qcollectiongenerator/qcollectiongenerator.pro new file mode 100644 index 000000000..98e6a3193 --- /dev/null +++ b/src/assistant/tools/qcollectiongenerator/qcollectiongenerator.pro @@ -0,0 +1,17 @@ +QT += xml \ + network +TEMPLATE = app +DESTDIR = ../../../../bin +TARGET = qcollectiongenerator +CONFIG += qt \ + warn_on \ + help \ + console +CONFIG -= app_bundle +target.path = $$[QT_INSTALL_BINS] +INSTALLS += target +SOURCES += ../shared/helpgenerator.cpp \ + main.cpp \ + ../shared/collectionconfiguration.cpp +HEADERS += ../shared/helpgenerator.h \ + ../shared/collectionconfiguration.h diff --git a/src/assistant/tools/qhelpconverter/adpreader.cpp b/src/assistant/tools/qhelpconverter/adpreader.cpp new file mode 100644 index 000000000..a0983755e --- /dev/null +++ b/src/assistant/tools/qhelpconverter/adpreader.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "adpreader.h" + +static bool versionIsAtLeast320(const QString &version) +{ + return QRegExp("\\d.\\d\\.\\d").exactMatch(version) + && (version[0] > '3' || (version[0] == '3' && version[2] >= '2')); +} + +QT_BEGIN_NAMESPACE + +void AdpReader::readData(const QByteArray &contents) +{ + clear(); + m_contents.clear(); + m_keywords.clear(); + m_properties.clear(); + m_files.clear(); + addData(contents); + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name().toString().toLower() == QLatin1String("assistantconfig") + && versionIsAtLeast320(attributes().value(QLatin1String("version")).toString())) { + readProject(); + } else if (name().toString().toLower() == QLatin1String("dcf")) { + QString ref = attributes().value(QLatin1String("ref")).toString(); + addFile(ref); + m_contents.append(ContentItem(attributes().value(QLatin1String("title")).toString(), + ref, 0)); + readDCF(); + } else { + raiseError(); + } + } + } +} + +QList AdpReader::contents() const +{ + return m_contents; +} + +QList AdpReader::keywords() const +{ + return m_keywords; +} + +QSet AdpReader::files() const +{ + return m_files; +} + +QMap AdpReader::properties() const +{ + return m_properties; +} + +void AdpReader::readProject() +{ + while (!atEnd()) { + readNext(); + if (isStartElement()) { + QString s = name().toString().toLower(); + if (s == QLatin1String("profile")) { + readProfile(); + } else if (s == QLatin1String("dcf")) { + QString ref = attributes().value(QLatin1String("ref")).toString(); + addFile(ref); + m_contents.append(ContentItem(attributes().value(QLatin1String("title")).toString(), + ref, 0)); + readDCF(); + } else { + raiseError(); + } + } + } +} + +void AdpReader::readProfile() +{ + while (!atEnd()) { + readNext(); + if (isStartElement()) { + if (name().toString().toLower() == QLatin1String("property")) { + QString prop = attributes().value(QLatin1String("name")).toString().toLower(); + m_properties[prop] = readElementText(); + } else { + raiseError(); + } + } else if (isEndElement()) { + break; + } + } +} + +void AdpReader::readDCF() +{ + int depth = 0; + while (!atEnd()) { + readNext(); + QString str = name().toString().toLower(); + if (isStartElement()) { + if (str == QLatin1String("section")) { + QString ref = attributes().value(QLatin1String("ref")).toString(); + addFile(ref); + m_contents.append(ContentItem(attributes().value(QLatin1String("title")).toString(), + ref, ++depth)); + } else if (str == QLatin1String("keyword")) { + QString ref = attributes().value(QLatin1String("ref")).toString(); + addFile(ref); + m_keywords.append(KeywordItem(readElementText(), ref)); + } else { + raiseError(); + } + } else if (isEndElement()) { + if (str == QLatin1String("section")) + --depth; + else if (str == QLatin1String("dcf")) + break; + } + } +} + +void AdpReader::addFile(const QString &file) +{ + QString s = file; + if (s.startsWith(QLatin1String("./"))) + s = s.mid(2); + int i = s.indexOf(QLatin1Char('#')); + if (i > -1) + s = s.left(i); + if (!m_files.contains(s)) + m_files.insert(s); +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/qhelpconverter/adpreader.h b/src/assistant/tools/qhelpconverter/adpreader.h new file mode 100644 index 000000000..f0b6ae214 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/adpreader.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ADPREADER_H +#define ADPREADER_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +struct ContentItem { + ContentItem(const QString &t, const QString &r, int d) + : title(t), reference(r), depth(d) {} + QString title; + QString reference; + int depth; +}; + +struct KeywordItem { + KeywordItem(const QString &k, const QString &r) + : keyword(k), reference(r) {} + QString keyword; + QString reference; +}; + +class AdpReader : public QXmlStreamReader +{ +public: + void readData(const QByteArray &contents); + QList contents() const; + QList keywords() const; + QSet files() const; + + QMap properties() const; + +private: + void readProject(); + void readProfile(); + void readDCF(); + void addFile(const QString &file); + + QMap m_properties; + QList m_contents; + QList m_keywords; + QSet m_files; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/assistant/tools/qhelpconverter/assistant-128.png b/src/assistant/tools/qhelpconverter/assistant-128.png new file mode 100644 index 000000000..f05949f6d Binary files /dev/null and b/src/assistant/tools/qhelpconverter/assistant-128.png differ diff --git a/src/assistant/tools/qhelpconverter/assistant.png b/src/assistant/tools/qhelpconverter/assistant.png new file mode 100644 index 000000000..ea4d1e70c Binary files /dev/null and b/src/assistant/tools/qhelpconverter/assistant.png differ diff --git a/src/assistant/tools/qhelpconverter/conversionwizard.cpp b/src/assistant/tools/qhelpconverter/conversionwizard.cpp new file mode 100644 index 000000000..1df9facc5 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/conversionwizard.cpp @@ -0,0 +1,265 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "conversionwizard.h" +#include "inputpage.h" +#include "generalpage.h" +#include "filterpage.h" +#include "identifierpage.h" +#include "pathpage.h" +#include "filespage.h" +#include "outputpage.h" +#include "finishpage.h" +#include "qhpwriter.h" +#include "qhcpwriter.h" +#include "helpwindow.h" + +QT_BEGIN_NAMESPACE + +ConversionWizard::ConversionWizard() +{ + setWindowIcon(QIcon(QLatin1String(":/trolltech/qhelpconverter/assistant.png"))); + setWindowTitle(tr("Help Conversion Wizard")); + setPixmap(QWizard::WatermarkPixmap, + QPixmap(QLatin1String(":/trolltech/qhelpconverter/assistant-128.png"))) ; + setOptions(QWizard::IndependentPages|QWizard::NoBackButtonOnLastPage + |QWizard::HaveHelpButton); + + m_inputPage = new InputPage(&m_adpReader); + setPage(Input_Page, m_inputPage); + + m_generalPage = new GeneralPage(); + setPage(General_Page, m_generalPage); + + m_filterPage = new FilterPage(); + setPage(Filter_Page, m_filterPage); + m_filterPage->setMaximumHeight(240); + + m_identifierPage = new IdentifierPage(); + setPage(Identifier_Page, m_identifierPage); + + m_pathPage = new PathPage(); + setPage(Path_Page, m_pathPage); + m_pathPage->setMaximumHeight(240); + + m_filesPage = new FilesPage(); + setPage(Files_Page, m_filesPage); + m_filesPage->setMaximumHeight(240); + + m_outputPage = new OutputPage(); + setPage(Output_Page, m_outputPage); + m_outputPage->setMaximumHeight(240); + + m_finishPage = new FinishPage(); + setPage(Finish_Page, m_finishPage); + m_finishPage->setMaximumHeight(240); + + connect(this, SIGNAL(currentIdChanged(int)), + this, SLOT(pageChanged(int))); + + m_helpWindow = 0; + qApp->installEventFilter(this); + + QAbstractButton *btn = button(QWizard::HelpButton); + btn->setCheckable(true); + connect(btn, SIGNAL(toggled(bool)), this, SLOT(showHelp(bool))); +} + +void ConversionWizard::setAdpFileName(const QString &fileName) +{ + setField(QLatin1String("adpFileName"), fileName); +} + +void ConversionWizard::initializePage(int id) +{ + switch (id) { + case Path_Page: { + QFileInfo fi(field(QLatin1String("adpFileName")).toString()); + m_pathPage->setPath(fi.absolutePath()); + break; + } + case Output_Page: { + QFileInfo fi(field(QLatin1String("adpFileName")).toString()); + m_outputPage->setPath(fi.absolutePath()); + setField(QLatin1String("ProjectFileName"), fi.baseName() + + QLatin1String(".qhp")); + setField(QLatin1String("CollectionFileName"), fi.baseName() + + QLatin1String(".qhcp")); + break; + } + } +} + +void ConversionWizard::pageChanged(int id) +{ + if (id == Files_Page) { + QApplication::setOverrideCursor(Qt::WaitCursor); + m_files.clear(); + QFileInfo fi(field(QLatin1String("adpFileName")).toString()); + QDir rootDir = fi.absolutePath(); + foreach (const QString &p, m_pathPage->paths()) { + QDir dir(p); + QString rel = rootDir.relativeFilePath(dir.absolutePath()); + if (!rel.isEmpty()) + rel.append(QLatin1Char('/')); + foreach (const QString &f, dir.entryList(m_pathPage->filters())) + m_files.append(rel + f); + } + m_filesPage->setFilesToRemove(getUnreferencedFiles(m_files)); + QApplication::restoreOverrideCursor(); + } else if (id == Output_Page) { + m_outputPage->setCollectionComponentEnabled( + !m_adpReader.properties().isEmpty()); + } else if (id == Finish_Page) { + QTimer::singleShot(300, this, SLOT(convert())); + } +} + +void ConversionWizard::showHelp(bool toggle) +{ + int w = 180; + int h = 180; + if (!m_helpWindow) { + m_helpWindow = new HelpWindow(this); + m_helpWindow->setMaximumWidth(w); + m_helpWindow->setMaximumHeight(h); + m_helpWindow->setMinimumHeight(h); + } + + if (toggle) { + m_helpWindow->setHelp(currentPage()->objectName()); + QAbstractButton *btn = button(QWizard::HelpButton); + QPoint p = btn->pos(); + int x = p.x(); + if (btn->pos().x() > w) + x = p.x() + btn->width() - w; + m_helpWindow->move(x, p.y()-h); + m_helpWindow->show(); + } else { + m_helpWindow->hide(); + } +} + +bool ConversionWizard::eventFilter(QObject *obj, QEvent *e) +{ + if (m_helpWindow && m_helpWindow->isVisible()) { + if (obj != button(QWizard::HelpButton) + && e->type() == QEvent::MouseButtonRelease) { + QMouseEvent *me = static_cast(e); + if (!m_helpWindow->geometry().contains(mapFromParent(me->globalPos()))) { + m_helpWindow->hide(); + button(QWizard::HelpButton)->setChecked(false); + } + } else if (e->type() == QEvent::KeyPress) { + m_helpWindow->hide(); + button(QWizard::HelpButton)->setChecked(false); + } + } + return QWizard::eventFilter(obj, e); +} + +QStringList ConversionWizard::getUnreferencedFiles(const QStringList &files) +{ + QStringList lst; + QSet adpFiles = m_adpReader.files(); + foreach (const QString &s, files) { + if (!adpFiles.contains(s)) + lst.append(s); + } + return lst; +} + +void ConversionWizard::convert() +{ + QFileInfo fi(field(QLatin1String("adpFileName")).toString()); + m_finishPage->appendMessage(tr("Converting %1...") + .arg(fi.fileName())); + QApplication::setOverrideCursor(Qt::WaitCursor); + QString qhpFileName = field(QLatin1String("ProjectFileName")).toString(); + QhpWriter qhpWriter(field(QLatin1String("namespaceName")).toString(), + field(QLatin1String("virtualFolder")).toString()); + qhpWriter.setAdpReader(&m_adpReader); + qhpWriter.setFilterAttributes(m_filterPage->filterAttributes()); + qhpWriter.setCustomFilters(m_filterPage->customFilters()); + + foreach (const QString &f, m_filesPage->filesToRemove()) + m_files.removeAll(f); + qhpWriter.setFiles(m_files); + + if (field(QLatin1String("createIdentifier")).toBool()) { + if (field(QLatin1String("fileNamePrefix")).toBool()) + qhpWriter.generateIdentifiers(QhpWriter::FilePrefix); + else + qhpWriter.generateIdentifiers(QhpWriter::GlobalPrefix, + field(QLatin1String("globalPrefix")).toString()); + } else { + qhpWriter.generateIdentifiers(QhpWriter::SkipAll); + } + + qhpWriter.writeFile(fi.absolutePath() + QDir::separator() + + qhpFileName); + + m_finishPage->appendMessage(tr("Writing help collection file...")); + + if (!m_adpReader.properties().isEmpty()) { + QhcpWriter qhcpWriter; + qhcpWriter.setHelpProjectFile(qhpFileName); + qhcpWriter.setProperties(m_adpReader.properties()); + qhcpWriter.setTitlePath(QLatin1String("qthelp://") + + field(QLatin1String("namespaceName")).toString() + + QLatin1String("/") + +field(QLatin1String("virtualFolder")).toString()); + qhcpWriter.writeFile(fi.absolutePath() + QDir::separator() + + field(QLatin1String("CollectionFileName")).toString()); + } + + m_finishPage->appendMessage(tr("Done.")); + QApplication::restoreOverrideCursor(); +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/qhelpconverter/conversionwizard.h b/src/assistant/tools/qhelpconverter/conversionwizard.h new file mode 100644 index 000000000..eb9b3f556 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/conversionwizard.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CONVERSIONWIZARD_H +#define CONVERSIONWIZARD_H + +#include +#include "adpreader.h" + +QT_BEGIN_NAMESPACE + +class InputPage; +class GeneralPage; +class FilterPage; +class IdentifierPage; +class PathPage; +class FilesPage; +class OutputPage; +class FinishPage; +class HelpWindow; + +class ConversionWizard : public QWizard +{ + Q_OBJECT + +public: + ConversionWizard(); + void setAdpFileName(const QString &fileName); + +private slots: + void pageChanged(int id); + void showHelp(bool toggle); + void convert(); + +private: + enum Pages {Input_Page, General_Page, Filter_Page, + Identifier_Page, Path_Page, Files_Page, Output_Page, + Finish_Page}; + void initializePage(int id); + QStringList getUnreferencedFiles(const QStringList &files); + bool eventFilter(QObject *obj, QEvent *e); + + AdpReader m_adpReader; + InputPage *m_inputPage; + GeneralPage *m_generalPage; + FilterPage *m_filterPage; + IdentifierPage *m_identifierPage; + PathPage *m_pathPage; + FilesPage *m_filesPage; + OutputPage *m_outputPage; + FinishPage *m_finishPage; + QStringList m_files; + HelpWindow *m_helpWindow; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/assistant/tools/qhelpconverter/doc/filespage.html b/src/assistant/tools/qhelpconverter/doc/filespage.html new file mode 100644 index 000000000..a7aac18da --- /dev/null +++ b/src/assistant/tools/qhelpconverter/doc/filespage.html @@ -0,0 +1,8 @@ + + +

Sometimes it can happen that the previously specified paths contain +more or other files than actually needed for the documentation.

+

This page lists all files which are likely to be unused because they +are neither referenced by any keyword nor be the TOC.

+ + diff --git a/src/assistant/tools/qhelpconverter/doc/filterpage.html b/src/assistant/tools/qhelpconverter/doc/filterpage.html new file mode 100644 index 000000000..7b3781bd5 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/doc/filterpage.html @@ -0,0 +1,13 @@ + + +

The help system offers the possibility to filter all installed documentations +for certain attributes. Commonly specified attributes are e.g. the company +and product name as well as the product version.

+

The help engine and Assistant use custom filters to do the actual +documentation filtering. A custom filter is basically just a alias name for a +list of filter attributes. So, if e.g. the custom filter "MyFilter" lists +the attributes "mycompany, myproduct" then only the documentation with those +attributes will be shown.

+

Warning: The filter attributes are case sensitive!

+ + diff --git a/src/assistant/tools/qhelpconverter/doc/generalpage.html b/src/assistant/tools/qhelpconverter/doc/generalpage.html new file mode 100644 index 000000000..8d106bec1 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/doc/generalpage.html @@ -0,0 +1,10 @@ + + +

The namespace is needed to identify this documentation when having +several documentation sets installed in a collection.

+

Virtual folders are used to enable file references between all +documents. Thereby, the virtual folder acts as the root path of all +documents, even if those are part of different documentation sets, +meaning listed under different namespaces.

+ + diff --git a/src/assistant/tools/qhelpconverter/doc/identifierpage.html b/src/assistant/tools/qhelpconverter/doc/identifierpage.html new file mode 100644 index 000000000..952b88de8 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/doc/identifierpage.html @@ -0,0 +1,17 @@ + + +

Identifiers are mostly used to make keywords unique, but they can also +be used to specify keywords which should not be shown in the index. Identifiers +are especially help full when using context sensitive help and one keyword has +more links assigned to it.

+

E.g. consider the keyword "replace" in Qt. It is +included, among others, in QString and QList. To be able to retrieve the proper +documentation, there is an identifier "QString::replace" and one +"QList::replace".

+

A global prefix, e.g. "MyApp::" is set for all keywords independent +where they are located. When inheriting the prefix from the file name, +the keywords get the prefix "[filename]::" where the file name is taken from the +reference of the keyword. The file name is just the base name, i.e. without any +directory or extension.

+ + diff --git a/src/assistant/tools/qhelpconverter/doc/inputpage.html b/src/assistant/tools/qhelpconverter/doc/inputpage.html new file mode 100644 index 000000000..4054c5472 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/doc/inputpage.html @@ -0,0 +1,7 @@ + + +

Both, a .adp or .dcf file can be specified. If an .adp file is detected, +the wizard generates a Qt help collection file in addition to the help +project file.

+ + diff --git a/src/assistant/tools/qhelpconverter/doc/outputpage.html b/src/assistant/tools/qhelpconverter/doc/outputpage.html new file mode 100644 index 000000000..332ef69fc --- /dev/null +++ b/src/assistant/tools/qhelpconverter/doc/outputpage.html @@ -0,0 +1,7 @@ + + +

The specified output files will be located in the same directory as the +.adp or .dcf file. The collection file will only be generated if the input +file was an .adp file.

+ + diff --git a/src/assistant/tools/qhelpconverter/doc/pathpage.html b/src/assistant/tools/qhelpconverter/doc/pathpage.html new file mode 100644 index 000000000..95449b3c3 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/doc/pathpage.html @@ -0,0 +1,8 @@ + + +

The new help system uses, in contrast to the old Qt Assistant, compressed +help files containing all files (html files, images, stylesheets, ...) +necessary to display the documentation correctly.

+

To be able to find all those files, the source paths have to be given.

+ + diff --git a/src/assistant/tools/qhelpconverter/filespage.cpp b/src/assistant/tools/qhelpconverter/filespage.cpp new file mode 100644 index 000000000..e30ec42ef --- /dev/null +++ b/src/assistant/tools/qhelpconverter/filespage.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "filespage.h" + +QT_BEGIN_NAMESPACE + +FilesPage::FilesPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Unreferenced Files")); + setSubTitle(tr("Remove files which are neither referenced " + "by a keyword nor by the TOC.")); + + m_ui.setupUi(this); + m_ui.fileListWidget->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_ui.fileListWidget->installEventFilter(this); + connect(m_ui.removeButton, SIGNAL(clicked()), + this, SLOT(removeFile())); + connect(m_ui.removeAllButton, SIGNAL(clicked()), + this, SLOT(removeAllFiles())); + + m_ui.fileLabel->setText(tr("

Warning: " + "When removing images or stylesheets, be aware that those files " + "are not directly referenced by the .adp or .dcf " + "file.

")); +} + +void FilesPage::setFilesToRemove(const QStringList &files) +{ + m_files = files; + m_ui.fileListWidget->clear(); + m_ui.fileListWidget->addItems(files); +} + +QStringList FilesPage::filesToRemove() const +{ + return m_filesToRemove; +} + +void FilesPage::removeFile() +{ + int row = m_ui.fileListWidget->currentRow() + - m_ui.fileListWidget->selectedItems().count() + 1; + foreach (const QListWidgetItem *item, m_ui.fileListWidget->selectedItems()) { + m_filesToRemove.append(item->text()); + delete item; + } + if (m_ui.fileListWidget->count() > row && row >= 0) + m_ui.fileListWidget->setCurrentRow(row); + else + m_ui.fileListWidget->setCurrentRow(m_ui.fileListWidget->count()); +} + +void FilesPage::removeAllFiles() +{ + m_ui.fileListWidget->clear(); + m_filesToRemove = m_files; +} + +bool FilesPage::eventFilter(QObject *obj, QEvent *event) +{ + if (obj == m_ui.fileListWidget && event->type() == QEvent::KeyPress) { + QKeyEvent *ke = static_cast(event); + if (ke->key() == Qt::Key_Delete) { + removeFile(); + return true; + } + } + return QWizardPage::eventFilter(obj, event); +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/qhelpconverter/filespage.h b/src/assistant/tools/qhelpconverter/filespage.h new file mode 100644 index 000000000..393c3d5e1 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/filespage.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FILESPAGE_H +#define FILESPAGE_H + +#include +#include "ui_filespage.h" + +QT_BEGIN_NAMESPACE + +class FilesPage : public QWizardPage +{ + Q_OBJECT + +public: + FilesPage(QWidget *parent = 0); + void setFilesToRemove(const QStringList &files); + QStringList filesToRemove() const; + +private slots: + void removeFile(); + void removeAllFiles(); + +private: + bool eventFilter(QObject *obj, QEvent *event); + + Ui::FilesPage m_ui; + QStringList m_files; + QStringList m_filesToRemove; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/assistant/tools/qhelpconverter/filespage.ui b/src/assistant/tools/qhelpconverter/filespage.ui new file mode 100644 index 000000000..d308b9664 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/filespage.ui @@ -0,0 +1,79 @@ + + FilesPage + + + + 0 + 0 + 417 + 242 + + + + Form + + + + + + Files: + + + true + + + + + + + + + + + 0 + 0 + + + + Remove + + + + + + + Remove All + + + + + + + Qt::Vertical + + + + 75 + 16 + + + + + + + + Qt::Vertical + + + + 20 + 31 + + + + + + + + + diff --git a/src/assistant/tools/qhelpconverter/filterpage.cpp b/src/assistant/tools/qhelpconverter/filterpage.cpp new file mode 100644 index 000000000..3b22ca0d1 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/filterpage.cpp @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "filterpage.h" + +QT_BEGIN_NAMESPACE + +FilterPage::FilterPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Filter Settings")); + setSubTitle(tr("Specify the filter attributes for the " + "documentation. If filter attributes are used, " + "also define a custom filter for it. Both the " + "filter attributes and the custom filters are " + "optional.")); + + m_ui.setupUi(this); + m_ui.customFilterWidget->headerItem()->setText(0, tr("Filter Name")); + m_ui.customFilterWidget->headerItem()->setText(1, tr("Filter Attributes")); + m_ui.customFilterWidget->setRootIsDecorated(false); + m_ui.removeButton->setDisabled(true); + connect(m_ui.addButton, SIGNAL(clicked()), + this, SLOT(addFilter())); + connect(m_ui.removeButton, SIGNAL(clicked()), + this, SLOT(removeFilter())); +} + +bool FilterPage::validatePage() +{ + m_filterAttributes.clear(); + foreach (const QString &f, m_ui.filterLineEdit->text().split(QLatin1Char(','))) { + if (!f.trimmed().isEmpty()) + m_filterAttributes.append(f.trimmed()); + } + + m_customFilters.clear(); + QSet names; + QSet atts; + QString str; + CustomFilter customFilter; + QTreeWidgetItem *item = 0; + for (int i=0; itopLevelItemCount(); ++i) { + item = m_ui.customFilterWidget->topLevelItem(i); + str = item->text(0); + if (str.isEmpty() || names.contains(str)) { + QMessageBox::critical(this, tr("Custom Filters"), + tr("The custom filter \'%1\' is defined multiple times.") + .arg(str)); + return false; + } + names.insert(str); + customFilter.name = str; + + str.clear(); + QStringList lst; + foreach (const QString &s, item->text(1).split(QLatin1Char(','))) { + const QString st = s.trimmed(); + if (!st.isEmpty()) { + str += QLatin1Char(',') + st; + lst.append(st); + } + } + if (atts.contains(str)) { + QMessageBox::critical(this, tr("Custom Filters"), + tr("The attributes for custom filter \'%1\' are defined multiple times.") + .arg(customFilter.name)); + return false; + } + atts.insert(str); + customFilter.filterAttributes = lst; + m_customFilters.append(customFilter); + } + return true; +} + +QStringList FilterPage::filterAttributes() const +{ + return m_filterAttributes; +} + +QList FilterPage::customFilters() const +{ + return m_customFilters; +} + +void FilterPage::addFilter() +{ + QTreeWidgetItem *item = new QTreeWidgetItem(m_ui.customFilterWidget); + item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsEditable|Qt::ItemIsSelectable); + item->setText(0, tr("unfiltered", "list of available documentation")); + item->setText(1, QLatin1String("")); + m_ui.customFilterWidget->editItem(item, 0); + m_ui.removeButton->setDisabled(false); +} + +void FilterPage::removeFilter() +{ + QModelIndex idx = m_ui.customFilterWidget->currentIndex(); + if (!idx.isValid()) + return; + QTreeWidgetItem *item = m_ui.customFilterWidget->takeTopLevelItem(idx.row()); + delete item; + if (!m_ui.customFilterWidget->topLevelItemCount()) + m_ui.removeButton->setDisabled(true); +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/qhelpconverter/filterpage.h b/src/assistant/tools/qhelpconverter/filterpage.h new file mode 100644 index 000000000..0281a1ed3 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/filterpage.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FILTERPAGE_H +#define FILTERPAGE_H + +#include +#include "ui_filterpage.h" + +QT_BEGIN_NAMESPACE + +struct CustomFilter +{ + QString name; + QStringList filterAttributes; +}; + +class FilterPage : public QWizardPage +{ + Q_OBJECT + +public: + FilterPage(QWidget *parent = 0); + QStringList filterAttributes() const; + QList customFilters() const; + +private slots: + void addFilter(); + void removeFilter(); + +private: + bool validatePage(); + + Ui::FilterPage m_ui; + QStringList m_filterAttributes; + QList m_customFilters; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/assistant/tools/qhelpconverter/filterpage.ui b/src/assistant/tools/qhelpconverter/filterpage.ui new file mode 100644 index 000000000..7cda3d9be --- /dev/null +++ b/src/assistant/tools/qhelpconverter/filterpage.ui @@ -0,0 +1,125 @@ + + FilterPage + + + + 0 + 0 + 419 + 243 + + + + Form + + + + + + Filter attributes for current documentation (comma separated list): + + + + + + + + + + Custom Filters + + + + + + 2 + + + + 1 + + + + + 2 + + + + + + + + Add + + + + + + + Remove + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + + diff --git a/src/assistant/tools/qhelpconverter/finishpage.cpp b/src/assistant/tools/qhelpconverter/finishpage.cpp new file mode 100644 index 000000000..a7fa89e2e --- /dev/null +++ b/src/assistant/tools/qhelpconverter/finishpage.cpp @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +#include "finishpage.h" + +QT_BEGIN_NAMESPACE + +FinishPage::FinishPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Converting File")); + setSubTitle(tr("Creating the new Qt help files from the old ADP file.")); + setFinalPage(true); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, + QSizePolicy::Fixed)); + + m_textEdit = new QTextEdit(); + layout->addWidget(m_textEdit); + + layout->addItem(new QSpacerItem(20, 40, QSizePolicy::Minimum, + QSizePolicy::Expanding)); +} + +void FinishPage::appendMessage(const QString &msg) +{ + m_textEdit->append(msg); + qApp->processEvents(); +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/qhelpconverter/finishpage.h b/src/assistant/tools/qhelpconverter/finishpage.h new file mode 100644 index 000000000..15b0c4a55 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/finishpage.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FINISHPAGE_H +#define FINISHPAGE_H + +#include + +QT_BEGIN_NAMESPACE + +class QTextEdit; + +class FinishPage : public QWizardPage +{ + Q_OBJECT + +public: + FinishPage(QWidget *parent = 0); + void appendMessage(const QString &msg); + +private: + QTextEdit *m_textEdit; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/assistant/tools/qhelpconverter/generalpage.cpp b/src/assistant/tools/qhelpconverter/generalpage.cpp new file mode 100644 index 000000000..4b32cbbf9 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/generalpage.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "generalpage.h" + +QT_BEGIN_NAMESPACE + +GeneralPage::GeneralPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("General Settings")); + setSubTitle(tr("Specify the namespace and the virtual " + "folder for the documentation.")); + + m_ui.setupUi(this); + connect(m_ui.namespaceLineEdit, SIGNAL(textChanged(QString)), + this, SIGNAL(completeChanged())); + connect(m_ui.folderLineEdit, SIGNAL(textChanged(QString)), + this, SIGNAL(completeChanged())); + + m_ui.namespaceLineEdit->setText(QLatin1String("mycompany.com")); + m_ui.folderLineEdit->setText(QLatin1String("product_1.0")); + + registerField(QLatin1String("namespaceName"), m_ui.namespaceLineEdit); + registerField(QLatin1String("virtualFolder"), m_ui.folderLineEdit); +} + +bool GeneralPage::isComplete() const +{ + if (m_ui.namespaceLineEdit->text().isEmpty() + || m_ui.folderLineEdit->text().isEmpty()) + return false; + return true; +} + +bool GeneralPage::validatePage() +{ + QString s = m_ui.namespaceLineEdit->text(); + if (s.contains(QLatin1Char('/')) || s.contains(QLatin1Char('\\'))) { + QMessageBox::critical(this, tr("Namespace Error"), + tr("The namespace contains some invalid characters.")); + return false; + } + s = m_ui.folderLineEdit->text(); + if (s.contains(QLatin1Char('/')) || s.contains(QLatin1Char('\\'))) { + QMessageBox::critical(this, tr("Virtual Folder Error"), + tr("The virtual folder contains some invalid characters.")); + return false; + } + return true; +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/qhelpconverter/generalpage.h b/src/assistant/tools/qhelpconverter/generalpage.h new file mode 100644 index 000000000..413a798df --- /dev/null +++ b/src/assistant/tools/qhelpconverter/generalpage.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef GENERALPAGE_H +#define GENERALPAGE_H + +#include +#include "ui_generalpage.h" + +QT_BEGIN_NAMESPACE + +class GeneralPage : public QWizardPage +{ + Q_OBJECT + +public: + GeneralPage(QWidget *parent = 0); + +private: + bool validatePage(); + bool isComplete() const; + + Ui::GeneralPage m_ui; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/assistant/tools/qhelpconverter/generalpage.ui b/src/assistant/tools/qhelpconverter/generalpage.ui new file mode 100644 index 000000000..9c2babb0a --- /dev/null +++ b/src/assistant/tools/qhelpconverter/generalpage.ui @@ -0,0 +1,69 @@ + + GeneralPage + + + + 0 + 0 + 417 + 243 + + + + Form + + + + + + Namespace: + + + + + + + + + + Virtual Folder: + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/src/assistant/tools/qhelpconverter/helpwindow.cpp b/src/assistant/tools/qhelpconverter/helpwindow.cpp new file mode 100644 index 000000000..9fa33585e --- /dev/null +++ b/src/assistant/tools/qhelpconverter/helpwindow.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "helpwindow.h" + +QT_BEGIN_NAMESPACE + +HelpWindow::HelpWindow(QWidget *parent) + : QWidget(parent, 0) +{ + setAutoFillBackground(true); + QVBoxLayout *layout = new QVBoxLayout(this); + layout->setMargin(0); + QFrame *frame = new QFrame(this); + QPalette p = palette(); + p.setColor(QPalette::Background, Qt::white); + setPalette(p); + frame->setFrameStyle(QFrame::Box | QFrame::Plain); + layout->addWidget(frame); + + layout = new QVBoxLayout(frame); + layout->setMargin(2); + QLabel *l = new QLabel(tr("
Wizard Assistant
")); + layout->addWidget(l); + m_textEdit = new QTextEdit(); + m_textEdit->setFrameStyle(QFrame::NoFrame); + m_textEdit->setReadOnly(true); + layout->addWidget(m_textEdit); +} + +void HelpWindow::setHelp(const QString &topic) +{ + QLatin1String fileStr(":/trolltech/qhelpconverter/doc/%1.html"); + QFile f(QString(fileStr).arg(topic.toLower())); + f.open(QIODevice::ReadOnly); + QTextStream s(&f); + m_textEdit->setText(s.readAll()); +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/qhelpconverter/helpwindow.h b/src/assistant/tools/qhelpconverter/helpwindow.h new file mode 100644 index 000000000..ba176ed72 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/helpwindow.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef HELPWINDOW_H +#define HELPWINDOW_H + +#include + +QT_BEGIN_NAMESPACE + +class QTextEdit; + +class HelpWindow : public QWidget +{ + Q_OBJECT + +public: + HelpWindow(QWidget *parent = 0); + void setHelp(const QString &topic); + +private: + QTextEdit *m_textEdit; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/assistant/tools/qhelpconverter/identifierpage.cpp b/src/assistant/tools/qhelpconverter/identifierpage.cpp new file mode 100644 index 000000000..fb8310a61 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/identifierpage.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "identifierpage.h" + +QT_BEGIN_NAMESPACE + +IdentifierPage::IdentifierPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Identifiers")); + setSubTitle(tr("This page allows you to create identifiers from " + "the keywords found in the .adp or .dcf file.")); + + m_ui.setupUi(this); + + connect(m_ui.identifierCheckBox, SIGNAL(toggled(bool)), + this, SLOT(setupButtons(bool))); + + registerField(QLatin1String("createIdentifier"), m_ui.identifierCheckBox); + registerField(QLatin1String("globalPrefix"), m_ui.prefixLineEdit); + registerField(QLatin1String("fileNamePrefix"), m_ui.fileNameButton); +} + +void IdentifierPage::setupButtons(bool checked) +{ + m_ui.globalButton->setEnabled(checked); + m_ui.fileNameButton->setEnabled(checked); + m_ui.prefixLineEdit->setEnabled(checked + && m_ui.globalButton->isChecked()); +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/qhelpconverter/identifierpage.h b/src/assistant/tools/qhelpconverter/identifierpage.h new file mode 100644 index 000000000..c05eb8f72 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/identifierpage.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef IDENTIFIERPAGE_H +#define IDENTIFIERPAGE_H + +#include +#include "ui_identifierpage.h" + +QT_BEGIN_NAMESPACE + +class IdentifierPage : public QWizardPage +{ + Q_OBJECT + +public: + IdentifierPage(QWidget *parent = 0); + +private slots: + void setupButtons(bool checked); + +private: + Ui::IdentifierPage m_ui; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/assistant/tools/qhelpconverter/identifierpage.ui b/src/assistant/tools/qhelpconverter/identifierpage.ui new file mode 100644 index 000000000..cd0df7563 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/identifierpage.ui @@ -0,0 +1,132 @@ + + IdentifierPage + + + + 0 + 0 + 417 + 242 + + + + Form + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + Create identifiers + + + + + + + Qt::Horizontal + + + + 161 + 20 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 30 + 20 + + + + + + + + false + + + Global prefix: + + + true + + + + + + + false + + + + + + + false + + + Inherit prefix from file names + + + + + + + Qt::Vertical + + + + 20 + 31 + + + + + + + + + + globalButton + toggled(bool) + prefixLineEdit + setEnabled(bool) + + + 122 + 72 + + + 161 + 71 + + + + + diff --git a/src/assistant/tools/qhelpconverter/inputpage.cpp b/src/assistant/tools/qhelpconverter/inputpage.cpp new file mode 100644 index 000000000..aa180b90e --- /dev/null +++ b/src/assistant/tools/qhelpconverter/inputpage.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "inputpage.h" +#include "adpreader.h" + +QT_BEGIN_NAMESPACE + +InputPage::InputPage(AdpReader *reader, QWidget *parent) + : QWizardPage(parent) +{ + m_adpReader = reader; + setTitle(tr("Input File")); + setSubTitle(tr("Specify the .adp or .dcf file you want " + "to convert to the new Qt help project format and/or " + "collection format.")); + + m_ui.setupUi(this); + connect(m_ui.browseButton, SIGNAL(clicked()), + this, SLOT(getFileName())); + + registerField(QLatin1String("adpFileName"), m_ui.fileLineEdit); +} + +void InputPage::getFileName() +{ + QString f = QFileDialog::getOpenFileName(this, tr("Open file"), QString(), + tr("Qt Help Files (*.adp *.dcf)")); + if (!f.isEmpty()) + m_ui.fileLineEdit->setText(f); +} + +bool InputPage::validatePage() +{ + QFile f(m_ui.fileLineEdit->text().trimmed()); + if (!f.exists() || !f.open(QIODevice::ReadOnly)) { + QMessageBox::critical(this, tr("File Open Error"), + tr("The specified file could not be opened!")); + return false; + } + + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + m_adpReader->readData(f.readAll()); + QApplication::restoreOverrideCursor(); + if (m_adpReader->hasError()) { + QMessageBox::critical(this, tr("File Parsing Error"), + tr("Parsing error in line %1!").arg(m_adpReader->lineNumber())); + return false; + } + + return true; +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/qhelpconverter/inputpage.h b/src/assistant/tools/qhelpconverter/inputpage.h new file mode 100644 index 000000000..4489dc781 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/inputpage.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef INPUTPAGE_H +#define INPUTPAGE_H + +#include +#include "ui_inputpage.h" + +QT_BEGIN_NAMESPACE + +class AdpReader; + +class InputPage : public QWizardPage +{ + Q_OBJECT + +public: + explicit InputPage(AdpReader *reader, QWidget *parent = 0); + +private slots: + void getFileName(); + +private: + bool validatePage(); + + Ui::InputPage m_ui; + AdpReader *m_adpReader; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/assistant/tools/qhelpconverter/inputpage.ui b/src/assistant/tools/qhelpconverter/inputpage.ui new file mode 100644 index 000000000..e7cd3a0fa --- /dev/null +++ b/src/assistant/tools/qhelpconverter/inputpage.ui @@ -0,0 +1,79 @@ + + InputPage + + + + 0 + 0 + 417 + 242 + + + + Form + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 0 + 0 + + + + File name: + + + + + + + 0 + + + + + + + + ... + + + + + + + + + Qt::Vertical + + + + 20 + 31 + + + + + + + + + diff --git a/src/assistant/tools/qhelpconverter/main.cpp b/src/assistant/tools/qhelpconverter/main.cpp new file mode 100644 index 000000000..38f6ffc4e --- /dev/null +++ b/src/assistant/tools/qhelpconverter/main.cpp @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include + +#include "conversionwizard.h" + +QT_USE_NAMESPACE + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + QTranslator translator; + QTranslator qtTranslator; + QTranslator qt_helpTranslator; + QString sysLocale = QLocale::system().name(); + QString resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath); + if (translator.load(QLatin1String("assistant_") + sysLocale, resourceDir) + && qtTranslator.load(QLatin1String("qt_") + sysLocale, resourceDir) + && qt_helpTranslator.load(QLatin1String("qt_help_") + sysLocale, resourceDir)) { + app.installTranslator(&translator); + app.installTranslator(&qtTranslator); + app.installTranslator(&qt_helpTranslator); + } + + ConversionWizard w; + if (argc == 2) { + QFileInfo fi(QString::fromLocal8Bit(argv[1])); + if (fi.exists()) + w.setAdpFileName(fi.absoluteFilePath()); + } + w.show(); + return app.exec(); +} + diff --git a/src/assistant/tools/qhelpconverter/outputpage.cpp b/src/assistant/tools/qhelpconverter/outputpage.cpp new file mode 100644 index 000000000..d8a6bd13f --- /dev/null +++ b/src/assistant/tools/qhelpconverter/outputpage.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include + +#include "outputpage.h" + +QT_BEGIN_NAMESPACE + +OutputPage::OutputPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Output File Names")); + setSubTitle(tr("Specify the file names for the output files.")); + setButtonText(QWizard::NextButton, tr("Convert...")); + + m_ui.setupUi(this); + connect(m_ui.projectLineEdit, SIGNAL(textChanged(QString)), + this, SIGNAL(completeChanged())); + connect(m_ui.collectionLineEdit, SIGNAL(textChanged(QString)), + this, SIGNAL(completeChanged())); + + registerField(QLatin1String("ProjectFileName"), + m_ui.projectLineEdit); + registerField(QLatin1String("CollectionFileName"), + m_ui.collectionLineEdit); +} + +void OutputPage::setPath(const QString &path) +{ + m_path = path; +} + +void OutputPage::setCollectionComponentEnabled(bool enabled) +{ + m_ui.collectionLineEdit->setEnabled(enabled); + m_ui.label_2->setEnabled(enabled); +} + +bool OutputPage::isComplete() const +{ + if (m_ui.projectLineEdit->text().isEmpty() + || m_ui.collectionLineEdit->text().isEmpty()) + return false; + return true; +} + +bool OutputPage::validatePage() +{ + return checkFile(m_ui.projectLineEdit->text(), + tr("Qt Help Project File")) + && checkFile(m_ui.collectionLineEdit->text(), + tr("Qt Help Collection Project File")); +} + +bool OutputPage::checkFile(const QString &fileName, const QString &title) +{ + QFile fi(m_path + QDir::separator() + fileName); + if (!fi.exists()) + return true; + + if (QMessageBox::warning(this, title, + tr("The specified file %1 already exist.\n\nDo you want to remove it?") + .arg(fileName), tr("Remove"), tr("Cancel")) == 0) { + return fi.remove(); + } + return false; +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/qhelpconverter/outputpage.h b/src/assistant/tools/qhelpconverter/outputpage.h new file mode 100644 index 000000000..535729bf8 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/outputpage.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef OUTPUTPAGE_H +#define OUTPUTPAGE_H + +#include +#include "ui_outputpage.h" + +QT_BEGIN_NAMESPACE + +class OutputPage : public QWizardPage +{ + Q_OBJECT + +public: + OutputPage(QWidget *parent = 0); + void setPath(const QString &path); + void setCollectionComponentEnabled(bool enabled); + +private: + bool isComplete() const; + bool validatePage(); + bool checkFile(const QString &fileName, + const QString &title); + + Ui::OutputPage m_ui; + QString m_path; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/assistant/tools/qhelpconverter/outputpage.ui b/src/assistant/tools/qhelpconverter/outputpage.ui new file mode 100644 index 000000000..755f81808 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/outputpage.ui @@ -0,0 +1,95 @@ + + OutputPage + + + + 0 + 0 + 417 + 242 + + + + Form + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 0 + 0 + + + + Project file name: + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Collection file name: + + + + + + + + 0 + 0 + + + + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + diff --git a/src/assistant/tools/qhelpconverter/pathpage.cpp b/src/assistant/tools/qhelpconverter/pathpage.cpp new file mode 100644 index 000000000..e5391eb80 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/pathpage.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "pathpage.h" + +QT_BEGIN_NAMESPACE + +PathPage::PathPage(QWidget *parent) + : QWizardPage(parent) +{ + setTitle(tr("Source File Paths")); + setSubTitle(tr("Specify the paths where the sources files " + "are located. By default, all files in those directories " + "matched by the file filter will be included.")); + + m_ui.setupUi(this); + connect(m_ui.addButton, SIGNAL(clicked()), + this, SLOT(addPath())); + connect(m_ui.removeButton, SIGNAL(clicked()), + this, SLOT(removePath())); + + m_ui.filterLineEdit->setText(QLatin1String("*.html, *.htm, *.png, *.jpg, *.css")); + + registerField(QLatin1String("sourcePathList"), m_ui.pathListWidget); + m_firstTime = true; +} + +void PathPage::setPath(const QString &path) +{ + if (!m_firstTime) + return; + + m_ui.pathListWidget->addItem(path); + m_firstTime = false; + m_ui.pathListWidget->setCurrentRow(0); +} + +QStringList PathPage::paths() const +{ + QStringList lst; + for (int i = 0; icount(); ++i) + lst.append(m_ui.pathListWidget->item(i)->text()); + return lst; +} + +QStringList PathPage::filters() const +{ + QStringList lst; + foreach (const QString &s, m_ui.filterLineEdit->text().split(QLatin1Char(','))) { + lst.append(s.trimmed()); + } + return lst; +} + +void PathPage::addPath() +{ + QString dir = QFileDialog::getExistingDirectory(this, + tr("Source File Path")); + if (!dir.isEmpty()) + m_ui.pathListWidget->addItem(dir); +} + +void PathPage::removePath() +{ + QListWidgetItem *i = m_ui.pathListWidget + ->takeItem(m_ui.pathListWidget->currentRow()); + delete i; + if (!m_ui.pathListWidget->count()) + m_ui.removeButton->setEnabled(false); +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/qhelpconverter/pathpage.h b/src/assistant/tools/qhelpconverter/pathpage.h new file mode 100644 index 000000000..aad387976 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/pathpage.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PATHPAGE_H +#define PATHPAGE_H + +#include +#include "ui_pathpage.h" + +QT_BEGIN_NAMESPACE + +class PathPage : public QWizardPage +{ + Q_OBJECT + +public: + PathPage(QWidget *parent = 0); + void setPath(const QString &path); + QStringList paths() const; + QStringList filters() const; + +private slots: + void addPath(); + void removePath(); + +private: + Ui::PathPage m_ui; + bool m_firstTime; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/assistant/tools/qhelpconverter/pathpage.ui b/src/assistant/tools/qhelpconverter/pathpage.ui new file mode 100644 index 000000000..89083915d --- /dev/null +++ b/src/assistant/tools/qhelpconverter/pathpage.ui @@ -0,0 +1,114 @@ + + PathPage + + + + 0 + 0 + 417 + 243 + + + + Form + + + + + + + 0 + 0 + + + + File filters: + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + Documentation source file paths: + + + + + + + + + + + 0 + 0 + + + + Add + + + + + + + + 0 + 0 + + + + Remove + + + + + + + Qt::Vertical + + + + 20 + 51 + + + + + + + + Qt::Vertical + + + + 20 + 31 + + + + + + + + + diff --git a/src/assistant/tools/qhelpconverter/qhcpwriter.cpp b/src/assistant/tools/qhelpconverter/qhcpwriter.cpp new file mode 100644 index 000000000..cdf9f0b3c --- /dev/null +++ b/src/assistant/tools/qhelpconverter/qhcpwriter.cpp @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "qhcpwriter.h" + +QT_BEGIN_NAMESPACE + +QhcpWriter::QhcpWriter() +{ + setAutoFormatting(true); +} + +void QhcpWriter::setHelpProjectFile(const QString &qhpFile) +{ + m_qhpFile = qhpFile; +} + +void QhcpWriter::setProperties(const QMap props) +{ + m_properties = props; +} + +void QhcpWriter::setTitlePath(const QString &path) +{ + m_titlePath = path; +} + +bool QhcpWriter::writeFile(const QString &fileName) +{ + QFile out(fileName); + if (!out.open(QIODevice::WriteOnly)) + return false; + + setDevice(&out); + writeStartDocument(); + writeStartElement(QLatin1String("QHelpCollectionProject")); + writeAttribute(QLatin1String("version"), QLatin1String("1.0")); + writeAssistantSettings(); + writeDocuments(); + writeEndDocument(); + return true; +} + +void QhcpWriter::writeAssistantSettings() +{ + if (m_properties.isEmpty()) + return; + + writeStartElement(QLatin1String("assistant")); + + if (m_properties.contains(QLatin1String("title"))) + writeTextElement(QLatin1String("title"), m_properties.value(QLatin1String("title"))); + if (m_properties.contains(QLatin1String("applicationicon"))) + writeTextElement(QLatin1String("applicationIcon"), + m_properties.value(QLatin1String("applicationicon"))); + if (m_properties.contains(QLatin1String("startpage"))) + writeTextElement(QLatin1String("startPage"), m_titlePath + QLatin1String("/") + + m_properties.value(QLatin1String("startpage"))); + if (m_properties.contains(QLatin1String("aboutmenutext"))) { + writeStartElement(QLatin1String("aboutMenuText")); + writeTextElement(QLatin1String("text"), + m_properties.value(QLatin1String("aboutmenutext"))); + writeEndElement(); + } + if (m_properties.contains(QLatin1String("abouturl"))) { + writeStartElement(QLatin1String("aboutDialog")); + writeTextElement(QLatin1String("file"), m_properties.value(QLatin1String("abouturl"))); + writeEndElement(); + } + if (m_properties.contains(QLatin1String("name"))) { + writeTextElement(QLatin1String("cacheDirectory"), + QLatin1String(".") + m_properties.value(QLatin1String("name"))); + } + + writeEndElement(); +} + +void QhcpWriter::writeDocuments() +{ + if (m_qhpFile.isEmpty()) + return; + + QString out = m_qhpFile; + int i = out.indexOf(QLatin1Char('.')); + if (i > -1) + out = out.left(i); + out.append(QLatin1String(".qch")); + + writeStartElement(QLatin1String("docFiles")); + + writeStartElement(QLatin1String("generate")); + writeStartElement(QLatin1String("file")); + writeTextElement(QLatin1String("input"), m_qhpFile); + writeTextElement(QLatin1String("output"), out); + writeEndElement(); + writeEndElement(); + + writeStartElement(QLatin1String("register")); + writeTextElement(QLatin1String("file"), out); + writeEndElement(); + + writeEndElement(); +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/qhelpconverter/qhcpwriter.h b/src/assistant/tools/qhelpconverter/qhcpwriter.h new file mode 100644 index 000000000..de0c6f8e1 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/qhcpwriter.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHCPWRITER_H +#define QHCPWRITER_H + +#include +#include "adpreader.h" + +QT_BEGIN_NAMESPACE + +class QhcpWriter : public QXmlStreamWriter +{ +public: + QhcpWriter(); + bool writeFile(const QString &fileName); + void setHelpProjectFile(const QString &qhpFile); + void setProperties(const QMap props); + void setTitlePath(const QString &path); + +private: + void writeAssistantSettings(); + void writeDocuments(); + + QString m_qhpFile; + QMap m_properties; + QString m_titlePath; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/assistant/tools/qhelpconverter/qhelpconverter.pro b/src/assistant/tools/qhelpconverter/qhelpconverter.pro new file mode 100644 index 000000000..341faf346 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/qhelpconverter.pro @@ -0,0 +1,47 @@ +QT += xml +TEMPLATE = app +TARGET = qhelpconverter +DESTDIR = ../../../../bin +CONFIG += qt warn_on help + +target.path=$$[QT_INSTALL_BINS] +INSTALLS += target + +SOURCES += conversionwizard.cpp \ + inputpage.cpp \ + generalpage.cpp \ + filterpage.cpp \ + identifierpage.cpp \ + pathpage.cpp \ + filespage.cpp \ + outputpage.cpp \ + finishpage.cpp \ + adpreader.cpp \ + qhpwriter.cpp \ + qhcpwriter.cpp \ + helpwindow.cpp \ + main.cpp + +HEADERS += conversionwizard.h \ + inputpage.h \ + generalpage.h \ + filterpage.h \ + identifierpage.h \ + pathpage.h \ + filespage.h \ + outputpage.h \ + finishpage.h \ + adpreader.h \ + qhcpwriter.h \ + qhpwriter.h \ + helpwindow.h + +FORMS += inputpage.ui \ + generalpage.ui \ + filterpage.ui \ + identifierpage.ui \ + pathpage.ui \ + filespage.ui \ + outputpage.ui + +RESOURCES += qhelpconverter.qrc diff --git a/src/assistant/tools/qhelpconverter/qhelpconverter.qrc b/src/assistant/tools/qhelpconverter/qhelpconverter.qrc new file mode 100644 index 000000000..e2a68ab43 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/qhelpconverter.qrc @@ -0,0 +1,13 @@ + + + assistant-128.png + assistant.png + doc/inputpage.html + doc/generalpage.html + doc/filterpage.html + doc/identifierpage.html + doc/pathpage.html + doc/filespage.html + doc/outputpage.html + + diff --git a/src/assistant/tools/qhelpconverter/qhpwriter.cpp b/src/assistant/tools/qhelpconverter/qhpwriter.cpp new file mode 100644 index 000000000..51d392d32 --- /dev/null +++ b/src/assistant/tools/qhelpconverter/qhpwriter.cpp @@ -0,0 +1,184 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "qhpwriter.h" +#include "adpreader.h" + +QT_BEGIN_NAMESPACE + +QhpWriter::QhpWriter(const QString &namespaceName, + const QString &virtualFolder) +{ + m_namespaceName = namespaceName; + m_virtualFolder = virtualFolder; + setAutoFormatting(true); +} + +void QhpWriter::setAdpReader(AdpReader *reader) +{ + m_adpReader = reader; +} + +void QhpWriter::setFilterAttributes(const QStringList &attributes) +{ + m_filterAttributes = attributes; +} + +void QhpWriter::setCustomFilters(const QList filters) +{ + m_customFilters = filters; +} + +void QhpWriter::setFiles(const QStringList &files) +{ + m_files = files; +} + +void QhpWriter::generateIdentifiers(IdentifierPrefix prefix, + const QString prefixString) +{ + m_prefix = prefix; + m_prefixString = prefixString; +} + +bool QhpWriter::writeFile(const QString &fileName) +{ + QFile out(fileName); + if (!out.open(QIODevice::WriteOnly)) + return false; + + setDevice(&out); + writeStartDocument(); + writeStartElement(QLatin1String("QtHelpProject")); + writeAttribute(QLatin1String("version"), QLatin1String("1.0")); + writeTextElement(QLatin1String("namespace"), m_namespaceName); + writeTextElement(QLatin1String("virtualFolder"), m_virtualFolder); + writeCustomFilters(); + writeFilterSection(); + writeEndDocument(); + + out.close(); + return true; +} + +void QhpWriter::writeCustomFilters() +{ + if (!m_customFilters.count()) + return; + + foreach (const CustomFilter &f, m_customFilters) { + writeStartElement(QLatin1String("customFilter")); + writeAttribute(QLatin1String("name"), f.name); + foreach (const QString &a, f.filterAttributes) + writeTextElement(QLatin1String("filterAttribute"), a); + writeEndElement(); + } +} + +void QhpWriter::writeFilterSection() +{ + writeStartElement(QLatin1String("filterSection")); + foreach (const QString &a, m_filterAttributes) + writeTextElement(QLatin1String("filterAttribute"), a); + + writeToc(); + writeKeywords(); + writeFiles(); + writeEndElement(); +} + +void QhpWriter::writeToc() +{ + QList lst = m_adpReader->contents(); + if (lst.isEmpty()) + return; + + int depth = -1; + writeStartElement(QLatin1String("toc")); + foreach (const ContentItem &i, lst) { + while (depth-- >= i.depth) + writeEndElement(); + writeStartElement(QLatin1String("section")); + writeAttribute(QLatin1String("title"), i.title); + writeAttribute(QLatin1String("ref"), i.reference); + depth = i.depth; + } + while (depth-- >= -1) + writeEndElement(); +} + +void QhpWriter::writeKeywords() +{ + QList lst = m_adpReader->keywords(); + if (lst.isEmpty()) + return; + + writeStartElement(QLatin1String("keywords")); + foreach (const KeywordItem &i, lst) { + writeEmptyElement(QLatin1String("keyword")); + writeAttribute(QLatin1String("name"), i.keyword); + writeAttribute(QLatin1String("ref"), i.reference); + if (m_prefix == FilePrefix) { + QString str = i.reference.mid( + i.reference.lastIndexOf(QLatin1Char('/'))+1); + str = str.left(str.lastIndexOf(QLatin1Char('.'))); + writeAttribute(QLatin1String("id"), str + QLatin1String("::") + i.keyword); + } else if (m_prefix == GlobalPrefix) { + writeAttribute(QLatin1String("id"), m_prefixString + i.keyword); + } + } + writeEndElement(); +} + +void QhpWriter::writeFiles() +{ + if (m_files.isEmpty()) + return; + + writeStartElement(QLatin1String("files")); + foreach (const QString &f, m_files) + writeTextElement(QLatin1String("file"), f); + writeEndElement(); +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/qhelpconverter/qhpwriter.h b/src/assistant/tools/qhelpconverter/qhpwriter.h new file mode 100644 index 000000000..70fd04aca --- /dev/null +++ b/src/assistant/tools/qhelpconverter/qhpwriter.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHPWRITER_H +#define QHPWRITER_H + +#include +#include "filterpage.h" + +QT_BEGIN_NAMESPACE + +class AdpReader; + +class QhpWriter : public QXmlStreamWriter +{ +public: + enum IdentifierPrefix {SkipAll, FilePrefix, GlobalPrefix}; + QhpWriter(const QString &namespaceName, + const QString &virtualFolder); + void setAdpReader(AdpReader *reader); + void setFilterAttributes(const QStringList &attributes); + void setCustomFilters(const QList filters); + void setFiles(const QStringList &files); + void generateIdentifiers(IdentifierPrefix prefix, + const QString prefixString = QString()); + bool writeFile(const QString &fileName); + +private: + void writeCustomFilters(); + void writeFilterSection(); + void writeToc(); + void writeKeywords(); + void writeFiles(); + + QString m_namespaceName; + QString m_virtualFolder; + AdpReader *m_adpReader; + QStringList m_filterAttributes; + QList m_customFilters; + QStringList m_files; + IdentifierPrefix m_prefix; + QString m_prefixString; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/assistant/tools/qhelpgenerator/main.cpp b/src/assistant/tools/qhelpgenerator/main.cpp new file mode 100644 index 000000000..386e84c41 --- /dev/null +++ b/src/assistant/tools/qhelpgenerator/main.cpp @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../shared/helpgenerator.h" + +#include +#include +#include +#include +#include +#include + +#include + +QT_USE_NAMESPACE + +class QHG { + Q_DECLARE_TR_FUNCTIONS(QHelpGenerator) +}; + +int main(int argc, char *argv[]) +{ + QString error; + QString arg; + QString compressedFile; + QString projectFile; + QString basePath; + bool showHelp = false; + bool showVersion = false; + bool checkLinks = false; + + QCoreApplication app(argc, argv); +#ifndef Q_OS_WIN32 + QTranslator translator; + QTranslator qtTranslator; + QTranslator qt_helpTranslator; + QString sysLocale = QLocale::system().name(); + QString resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath); + if (translator.load(QLatin1String("assistant_") + sysLocale, resourceDir) + && qtTranslator.load(QLatin1String("qt_") + sysLocale, resourceDir) + && qt_helpTranslator.load(QLatin1String("qt_help_") + sysLocale, resourceDir)) { + app.installTranslator(&translator); + app.installTranslator(&qtTranslator); + app.installTranslator(&qt_helpTranslator); + } +#endif // Q_OS_WIN32 + + for (int i = 1; i < argc; ++i) { + arg = QString::fromLocal8Bit(argv[i]); + if (arg == QLatin1String("-o")) { + if (++i < argc) { + QFileInfo fi(QString::fromLocal8Bit(argv[i])); + compressedFile = fi.absoluteFilePath(); + } else { + error = QHG::tr("Missing output file name."); + } + } else if (arg == QLatin1String("-v")) { + showVersion = true; + } else if (arg == QLatin1String("-h")) { + showHelp = true; + } else if (arg == QLatin1String("-c")) { + checkLinks = true; + } else { + QFileInfo fi(arg); + projectFile = fi.absoluteFilePath(); + basePath = fi.absolutePath(); + } + } + + if (showVersion) { + fputs(qPrintable(QHG::tr("Qt Help Generator version 1.0 (Qt %1)\n") + .arg(QT_VERSION_STR)), stdout); + return 0; + } + + if (projectFile.isEmpty() && !showHelp) + error = QHG::tr("Missing Qt help project file."); + + QString help = QHG::tr("\nUsage:\n\n" + "qhelpgenerator [options]\n\n" + " -o Generates a Qt compressed help\n" + " file called .\n" + " If this option is not specified\n" + " a default name will be used.\n" + " -c Checks whether all links in HTML files\n" + " point to files in this help project.\n" + " -v Displays the version of \n" + " qhelpgenerator.\n\n"); + + if (showHelp) { + fputs(qPrintable(help), stdout); + return 0; + }else if (!error.isEmpty()) { + fprintf(stderr, "%s\n\n%s", qPrintable(error), qPrintable(help)); + return -1; + } + + QFile file(projectFile); + if (!file.open(QIODevice::ReadOnly)) { + fputs(qPrintable(QHG::tr("Could not open %1.\n").arg(projectFile)), stderr); + return -1; + } + + if (compressedFile.isEmpty()) { + if (!checkLinks) { + QFileInfo fi(projectFile); + compressedFile = basePath + QDir::separator() + + fi.baseName() + QLatin1String(".qch"); + } + } else { + // check if the output dir exists -- create if it doesn't + QFileInfo fi(compressedFile); + QDir parentDir = fi.dir(); + if (!parentDir.exists()) { + if (!parentDir.mkpath(QLatin1String("."))) { + fputs(qPrintable(QHG::tr("Could not create output directory: %1\n") + .arg(parentDir.path())), stderr); + } + } + } + + QHelpProjectData *helpData = new QHelpProjectData(); + if (!helpData->readData(projectFile)) { + fprintf(stderr, "%s\n", qPrintable(helpData->errorMessage())); + return -1; + } + + HelpGenerator generator; + bool success = true; + if (checkLinks) + success = generator.checkLinks(*helpData); + if (success && !compressedFile.isEmpty()) + success = generator.generate(helpData, compressedFile); + delete helpData; + if (!success) { + fprintf(stderr, "%s\n", qPrintable(generator.error())); + return -1; + } + return 0; +} diff --git a/src/assistant/tools/qhelpgenerator/qhelpgenerator.pro b/src/assistant/tools/qhelpgenerator/qhelpgenerator.pro new file mode 100644 index 000000000..68efcf593 --- /dev/null +++ b/src/assistant/tools/qhelpgenerator/qhelpgenerator.pro @@ -0,0 +1,14 @@ +TEMPLATE = app +TARGET = qhelpgenerator +DESTDIR = ../../../../bin +CONFIG += qt warn_on help console +CONFIG -= app_bundle +QT += network + +target.path=$$[QT_INSTALL_BINS] +INSTALLS += target + +SOURCES += ../shared/helpgenerator.cpp \ + main.cpp + +HEADERS += ../shared/helpgenerator.h diff --git a/src/assistant/tools/shared/collectionconfiguration.cpp b/src/assistant/tools/shared/collectionconfiguration.cpp new file mode 100644 index 000000000..35d5b66df --- /dev/null +++ b/src/assistant/tools/shared/collectionconfiguration.cpp @@ -0,0 +1,327 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "collectionconfiguration.h" + +#include + +QT_BEGIN_NAMESPACE + +namespace { + const QString AboutIconKey(QLatin1String("AboutIcon")); + const QString AboutImagesKey(QLatin1String("AboutImages")); + const QString AboutMenuTextsKey(QLatin1String("AboutMenuTexts")); + const QString AboutTextsKey(QLatin1String("AboutTexts")); + const QString ApplicationIconKey(QLatin1String("ApplicationIcon")); + const QString CacheDirKey(QLatin1String("CacheDirectory")); + const QString CacheDirRelativeToCollectionKey(QLatin1String("CacheDirRelativeToCollection")); + const QString CreationTimeKey(QLatin1String("CreationTime")); + const QString DefaultHomePageKey(QLatin1String("defaultHomepage")); + const QString EnableAddressBarKey(QLatin1String("EnableAddressBar")); + const QString EnableDocManagerKey(QLatin1String("EnableDocumentationManager")); + const QString EnableFilterKey(QLatin1String("EnableFilterFunctionality")); + const QString HideAddressBarKey(QLatin1String("HideAddressBar")); + const QString FilterToolbarHiddenKey(QLatin1String("HideFilterFunctionality")); + const QString LastPageKey(QLatin1String("LastTabPage")); + const QString LastRegisterTime(QLatin1String("LastRegisterTime")); + const QString LastShownPagesKey(QLatin1String("LastShownPages")); + const QString LastZoomFactorsKey(QLatin1String( +#if !defined(QT_NO_WEBKIT) + "LastPagesZoomWebView" +#else + "LastPagesZoomTextBrowser" +#endif + )); + const QString WindowTitleKey(QLatin1String("WindowTitle")); + const QString FullTextSearchFallbackKey(QLatin1String("FullTextSearchFallback")); +} // anonymous namespace + +const QString CollectionConfiguration::DefaultZoomFactor(QLatin1String("0.0")); +const QString CollectionConfiguration::ListSeparator(QLatin1String("|")); + +uint CollectionConfiguration::creationTime(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(CreationTimeKey, 0).toUInt(); +} + +void CollectionConfiguration::setCreationTime(QHelpEngineCore &helpEngine, uint time) +{ + helpEngine.setCustomValue(CreationTimeKey, time); +} + +const QString CollectionConfiguration::windowTitle(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(WindowTitleKey).toString(); +} + +void CollectionConfiguration::setWindowTitle(QHelpEngineCore &helpEngine, + const QString &windowTitle) +{ + helpEngine.setCustomValue(WindowTitleKey, windowTitle); +} + +bool CollectionConfiguration::filterFunctionalityEnabled(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(EnableFilterKey, true).toBool(); +} + +void CollectionConfiguration::setFilterFunctionalityEnabled(QHelpEngineCore &helpEngine, + bool enabled) +{ + helpEngine.setCustomValue(EnableFilterKey, enabled); +} + +bool CollectionConfiguration::filterToolbarVisible(const QHelpEngineCore &helpEngine) +{ + return !helpEngine.customValue(FilterToolbarHiddenKey, true).toBool(); +} + +void CollectionConfiguration::setFilterToolbarVisible(QHelpEngineCore &helpEngine, + bool visible) +{ + helpEngine.setCustomValue(FilterToolbarHiddenKey, !visible); +} + +bool CollectionConfiguration::addressBarEnabled(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(EnableAddressBarKey, true).toBool(); +} + +void CollectionConfiguration::setAddressBarEnabled(QHelpEngineCore &helpEngine, + bool enabled) +{ + helpEngine.setCustomValue(EnableAddressBarKey, enabled); +} + +bool CollectionConfiguration::addressBarVisible(const QHelpEngineCore &helpEngine) +{ + return !helpEngine.customValue(HideAddressBarKey, true).toBool(); +} + +void CollectionConfiguration::setAddressBarVisible(QHelpEngineCore &helpEngine, + bool visible) +{ + helpEngine.setCustomValue(HideAddressBarKey, !visible); +} + +const QString CollectionConfiguration::cacheDir(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(CacheDirKey).toString(); +} + +bool CollectionConfiguration::cacheDirIsRelativeToCollection(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(CacheDirRelativeToCollectionKey).toBool(); +} + +void CollectionConfiguration::setCacheDir(QHelpEngineCore &helpEngine, + const QString &cacheDir, bool relativeToCollection) +{ + helpEngine.setCustomValue(CacheDirKey, cacheDir); + helpEngine.setCustomValue(CacheDirRelativeToCollectionKey, + relativeToCollection); +} + +bool CollectionConfiguration::documentationManagerEnabled(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(EnableDocManagerKey, true).toBool(); +} + +void CollectionConfiguration::setDocumentationManagerEnabled(QHelpEngineCore &helpEngine, + bool enabled) +{ + helpEngine.setCustomValue(EnableDocManagerKey, enabled); +} + +const QByteArray CollectionConfiguration::applicationIcon(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(ApplicationIconKey).toByteArray(); +} + +void CollectionConfiguration::setApplicationIcon(QHelpEngineCore &helpEngine, + const QByteArray &icon) +{ + helpEngine.setCustomValue(ApplicationIconKey, icon); +} + +const QByteArray CollectionConfiguration::aboutMenuTexts(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(AboutMenuTextsKey).toByteArray(); +} + +void CollectionConfiguration::setAboutMenuTexts(QHelpEngineCore &helpEngine, + const QByteArray &texts) +{ + helpEngine.setCustomValue(AboutMenuTextsKey, texts); +} + +const QByteArray CollectionConfiguration::aboutIcon(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(AboutIconKey).toByteArray(); +} + +void CollectionConfiguration::setAboutIcon(QHelpEngineCore &helpEngine, + const QByteArray &icon) +{ + helpEngine.setCustomValue(AboutIconKey, icon); +} + +const QByteArray CollectionConfiguration::aboutTexts(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(AboutTextsKey).toByteArray(); +} + +void CollectionConfiguration::setAboutTexts(QHelpEngineCore &helpEngine, + const QByteArray &texts) +{ + helpEngine.setCustomValue(AboutTextsKey, texts); +} + +const QByteArray CollectionConfiguration::aboutImages(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(AboutImagesKey).toByteArray(); +} + +void CollectionConfiguration::setAboutImages(QHelpEngineCore &helpEngine, + const QByteArray &images) +{ + helpEngine.setCustomValue(AboutImagesKey, images); +} + +const QString CollectionConfiguration::defaultHomePage(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(DefaultHomePageKey, QLatin1String("help")). + toString(); +} + +void CollectionConfiguration::setDefaultHomePage(QHelpEngineCore &helpEngine, + const QString &page) +{ + helpEngine.setCustomValue(DefaultHomePageKey, page); +} + +const QStringList CollectionConfiguration::lastShownPages(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(LastShownPagesKey).toString(). + split(ListSeparator, QString::SkipEmptyParts); +} + +void CollectionConfiguration::setLastShownPages(QHelpEngineCore &helpEngine, + const QStringList &lastShownPages) +{ + helpEngine.setCustomValue(LastShownPagesKey, + lastShownPages.join(ListSeparator)); +} + +const QStringList CollectionConfiguration::lastZoomFactors(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(LastZoomFactorsKey).toString(). + split(ListSeparator, QString::SkipEmptyParts); +} + +void CollectionConfiguration::setLastZoomFactors(QHelpEngineCore &helpEngine, + const QStringList &lastZoomFactors) +{ + helpEngine.setCustomValue(LastZoomFactorsKey, + lastZoomFactors.join(ListSeparator)); +} + +int CollectionConfiguration::lastTabPage(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(LastPageKey, 1).toInt(); +} + +void CollectionConfiguration::setLastTabPage(QHelpEngineCore &helpEngine, + int lastPage) +{ + helpEngine.setCustomValue(LastPageKey, lastPage); +} + +const QDateTime CollectionConfiguration::lastRegisterTime(const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(LastRegisterTime, QDateTime()).toDateTime(); +} + +void CollectionConfiguration::updateLastRegisterTime(QHelpEngineCore &helpEngine) +{ + helpEngine.setCustomValue(LastRegisterTime, QDateTime::currentDateTime()); +} + +bool CollectionConfiguration::isNewer(const QHelpEngineCore &newer, + const QHelpEngineCore &older) +{ + return creationTime(newer) > creationTime(older); +} + +void CollectionConfiguration::copyConfiguration(const QHelpEngineCore &source, + QHelpEngineCore &target) +{ + setCreationTime(target, creationTime(source)); + setWindowTitle(target, windowTitle(source)); + target.setCurrentFilter(source.currentFilter()); + setCacheDir(target, cacheDir(source), cacheDirIsRelativeToCollection(source)); + setFilterFunctionalityEnabled(target, filterFunctionalityEnabled(source)); + setFilterToolbarVisible(target, filterToolbarVisible(source)); + setAddressBarEnabled(target, addressBarEnabled(source)); + setAddressBarVisible(target, addressBarVisible(source)); + setDocumentationManagerEnabled(target, documentationManagerEnabled(source)); + setApplicationIcon(target, applicationIcon(source)); + setAboutMenuTexts(target, aboutMenuTexts(source)); + setAboutIcon(target, aboutIcon(source)); + setAboutTexts(target, aboutTexts(source)); + setAboutImages(target, aboutImages(source)); + setDefaultHomePage(target, defaultHomePage(source)); + setFullTextSearchFallbackEnabled(target, fullTextSearchFallbackEnabled(source)); +} + +bool CollectionConfiguration:: fullTextSearchFallbackEnabled( + const QHelpEngineCore &helpEngine) +{ + return helpEngine.customValue(FullTextSearchFallbackKey, false).toBool(); +} + +void CollectionConfiguration::setFullTextSearchFallbackEnabled( + QHelpEngineCore &helpEngine, bool on) +{ + helpEngine.setCustomValue(FullTextSearchFallbackKey, on); +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/shared/collectionconfiguration.h b/src/assistant/tools/shared/collectionconfiguration.h new file mode 100644 index 000000000..226460ef3 --- /dev/null +++ b/src/assistant/tools/shared/collectionconfiguration.h @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef COLLECTIONCONFIGURATION_H +#define COLLECTIONCONFIGURATION_H + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QHelpEngineCore; + +class CollectionConfiguration +{ +public: + static const QString windowTitle(const QHelpEngineCore &helpEngine); + static void setWindowTitle(QHelpEngineCore &helpEngine, + const QString &windowTitle); + + static const QString cacheDir(const QHelpEngineCore &helpEngine); + static bool cacheDirIsRelativeToCollection(const QHelpEngineCore &helpEngine); + static void setCacheDir(QHelpEngineCore &helpEngine, + const QString &cacheDir, bool relativeToCollection); + + static uint creationTime(const QHelpEngineCore &helpEngine); + static void setCreationTime(QHelpEngineCore &helpEngine, uint time); + + static bool filterFunctionalityEnabled(const QHelpEngineCore &helpEngine); + static void setFilterFunctionalityEnabled(QHelpEngineCore &helpEngine, + bool enabled); + + static bool filterToolbarVisible(const QHelpEngineCore &helpEngine); + static void setFilterToolbarVisible(QHelpEngineCore &helpEngine, + bool visible); + + static bool addressBarEnabled(const QHelpEngineCore &helpEngine); + static void setAddressBarEnabled(QHelpEngineCore &helpEngine, bool enabled); + + static bool addressBarVisible(const QHelpEngineCore &helpEngine); + static void setAddressBarVisible(QHelpEngineCore &helpEngine, bool visible); + + + static bool documentationManagerEnabled(const QHelpEngineCore &helpEngine); + static void setDocumentationManagerEnabled(QHelpEngineCore &helpEngine, + bool enabled); + + static const QByteArray applicationIcon(const QHelpEngineCore &helpEngine); + static void setApplicationIcon(QHelpEngineCore &helpEngine, + const QByteArray &icon); + + // TODO: Encapsulate encoding from/to QByteArray here + static const QByteArray aboutMenuTexts(const QHelpEngineCore &helpEngine); + static void setAboutMenuTexts(QHelpEngineCore &helpEngine, + const QByteArray &texts); + + static const QByteArray aboutIcon(const QHelpEngineCore &helpEngine); + static void setAboutIcon(QHelpEngineCore &helpEngine, + const QByteArray &icon); + + // TODO: Encapsulate encoding from/to QByteArray here + static const QByteArray aboutTexts(const QHelpEngineCore &helpEngine); + static void setAboutTexts(QHelpEngineCore &helpEngine, + const QByteArray &texts); + + static const QByteArray aboutImages(const QHelpEngineCore &helpEngine); + static void setAboutImages(QHelpEngineCore &helpEngine, + const QByteArray &images); + + static const QString defaultHomePage(const QHelpEngineCore &helpEngine); + static void setDefaultHomePage(QHelpEngineCore &helpEngine, + const QString &page); + + // TODO: Don't allow last pages and zoom factors to be set in isolation + // Perhaps also fill up missing elements automatically or assert. + static const QStringList lastShownPages(const QHelpEngineCore &helpEngine); + static void setLastShownPages(QHelpEngineCore &helpEngine, + const QStringList &lastShownPages); + static const QStringList lastZoomFactors(const QHelpEngineCore &helpEngine); + static void setLastZoomFactors(QHelpEngineCore &helPEngine, + const QStringList &lastZoomFactors); + + static int lastTabPage(const QHelpEngineCore &helpEngine); + static void setLastTabPage(QHelpEngineCore &helpEngine, int lastPage); + + static bool isNewer(const QHelpEngineCore &newer, + const QHelpEngineCore &older); + static void copyConfiguration(const QHelpEngineCore &source, + QHelpEngineCore &target); + + /* + * Note that this only reflects register actions caused by the + * "-register" command line switch, not GUI or remote control actions. + */ + static const QDateTime lastRegisterTime(const QHelpEngineCore &helpEngine); + static void updateLastRegisterTime(QHelpEngineCore &helpEngine); + + static bool fullTextSearchFallbackEnabled(const QHelpEngineCore &helpEngine); + static void setFullTextSearchFallbackEnabled(QHelpEngineCore &helpEngine, + bool on); + + static const QString DefaultZoomFactor; + static const QString ListSeparator; +}; + +QT_END_NAMESPACE + +#endif // COLLECTIONCONFIGURATION_H diff --git a/src/assistant/tools/shared/helpgenerator.cpp b/src/assistant/tools/shared/helpgenerator.cpp new file mode 100644 index 000000000..d551548fb --- /dev/null +++ b/src/assistant/tools/shared/helpgenerator.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "helpgenerator.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +HelpGenerator::HelpGenerator() +{ + generator = new QHelpGenerator(this); + connect(generator, SIGNAL(statusChanged(QString)), + this, SLOT(printStatus(QString))); + connect(generator, SIGNAL(warning(QString)), + this, SLOT(printWarning(QString))); +} + +bool HelpGenerator::generate(QHelpDataInterface *helpData, + const QString &outputFileName) +{ + return generator->generate(helpData, outputFileName); +} + +bool HelpGenerator::checkLinks(const QHelpDataInterface &helpData) +{ + return generator->checkLinks(helpData); +} + +QString HelpGenerator::error() const +{ + return generator->error(); +} + +void HelpGenerator::printStatus(const QString &msg) +{ + puts(qPrintable(msg)); +} + +void HelpGenerator::printWarning(const QString &msg) +{ + puts(qPrintable(tr("Warning: %1").arg(msg))); +} + +QT_END_NAMESPACE diff --git a/src/assistant/tools/shared/helpgenerator.h b/src/assistant/tools/shared/helpgenerator.h new file mode 100644 index 000000000..e220a2b68 --- /dev/null +++ b/src/assistant/tools/shared/helpgenerator.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Assistant of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef HELPGENERATOR_H +#define HELPGENERATOR_H + +#include + +QT_BEGIN_NAMESPACE + +class QHelpDataInterface; +class QHelpGenerator; + +class HelpGenerator : public QObject +{ + Q_OBJECT + +public: + HelpGenerator(); + bool generate(QHelpDataInterface *helpData, + const QString &outputFileName); + bool checkLinks(const QHelpDataInterface &helpData); + QString error() const; + +private slots: + void printStatus(const QString &msg); + void printWarning(const QString &msg); + +private: + QHelpGenerator *generator; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/assistant/tools/tools.pro b/src/assistant/tools/tools.pro new file mode 100644 index 000000000..8bb8cd700 --- /dev/null +++ b/src/assistant/tools/tools.pro @@ -0,0 +1,8 @@ +TEMPLATE = subdirs +CONFIG += ordered + +SUBDIRS += assistant \ + qhelpgenerator \ + qcollectiongenerator \ + qhelpconverter + diff --git a/src/checksdk/README b/src/checksdk/README new file mode 100644 index 000000000..7eba1db48 --- /dev/null +++ b/src/checksdk/README @@ -0,0 +1,3 @@ +checkSDK is used to build Qt/WinCE successfully. It parses the Visual +Studio configuration and sets up the environment for cross-compilation. + diff --git a/src/checksdk/cesdkhandler.cpp b/src/checksdk/cesdkhandler.cpp new file mode 100644 index 000000000..ad58f42dd --- /dev/null +++ b/src/checksdk/cesdkhandler.cpp @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "cesdkhandler.h" +#include +#include +#include + +CeSdkInfo::CeSdkInfo() : m_major(0) , m_minor(0) +{ +} + +QStringList CeSdkInfo::environment() +{ + QStringList result; + QString argument = QLatin1String("PATH="); + argument += m_bin; + result.append(argument); + argument = QLatin1String("INCLUDE="); + argument += m_include; + result.append(argument); + argument = QLatin1String("LIB="); + argument += m_lib; + result.append(argument); + return result; +} + +CeSdkHandler::CeSdkHandler() +{ +} + +bool CeSdkHandler::parse() +{ + // look at the file at %VCInstallDir%/vcpackages/WCE.VCPlatform.config + // and scan through all installed sdks... + m_list.clear(); + VCInstallDir = QString::fromLatin1(qgetenv("VCInstallDir")); + VCInstallDir += QLatin1String("\\"); + VSInstallDir = QString::fromLatin1(qgetenv("VSInstallDir")); + VSInstallDir += QLatin1String("\\"); + if (VCInstallDir.isEmpty() || VSInstallDir.isEmpty()) + return false; + + QDir vStudioDir(VCInstallDir); + if (!vStudioDir.cd(QLatin1String("vcpackages"))) + return false; + + QFile configFile(vStudioDir.absoluteFilePath(QLatin1String("WCE.VCPlatform.config"))); + if (!configFile.exists() || !configFile.open(QIODevice::ReadOnly)) + return false; + + QString currentElement; + CeSdkInfo currentItem; + QXmlStreamReader xml(&configFile); + while (!xml.atEnd()) { + xml.readNext(); + if (xml.isStartElement()) { + currentElement = xml.name().toString(); + if (currentElement == QLatin1String("Platform")) + currentItem = CeSdkInfo(); + else if (currentElement == QLatin1String("Directories")) { + QXmlStreamAttributes attr = xml.attributes(); + currentItem.m_include = fixPaths(attr.value(QLatin1String("Include")).toString()); + currentItem.m_lib = fixPaths(attr.value(QLatin1String("Library")).toString()); + currentItem.m_bin = fixPaths(attr.value(QLatin1String("Path")).toString()); + } + } else if (xml.isEndElement()) { + if (xml.name().toString() == QLatin1String("Platform")) + m_list.append(currentItem); + } else if (xml.isCharacters() && !xml.isWhitespace()) { + if (currentElement == QLatin1String("PlatformName")) + currentItem.m_name = xml.text().toString(); + else if (currentElement == QLatin1String("OSMajorVersion")) + currentItem.m_major = xml.text().toString().toInt(); + else if (currentElement == QLatin1String("OSMinorVersion")) + currentItem.m_minor = xml.text().toString().toInt(); + } + } + + if (xml.error() && xml.error() != QXmlStreamReader::PrematureEndOfDocumentError) { + qWarning() << "XML ERROR:" << xml.lineNumber() << ": " << xml.errorString(); + return false; + } + + return m_list.size() > 0 ? true : false; +} + +CeSdkInfo CeSdkHandler::find(const QString &name) +{ + for (QList::iterator it = m_list.begin(); it != m_list.end(); ++it) { + if (it->name() == name) + return *it; + } + return CeSdkInfo(); +} diff --git a/src/checksdk/cesdkhandler.h b/src/checksdk/cesdkhandler.h new file mode 100644 index 000000000..5ece4fdbb --- /dev/null +++ b/src/checksdk/cesdkhandler.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef CE_SDK_HANDLER_INCL +#define CE_SDK_HANDLER_INCL + +#include +#include + +QT_USE_NAMESPACE + +#define VCINSTALL_MACRO "$(VCInstallDir)" +#define VSINSTALL_MACRO "$(VSInstallDir)" + +class CeSdkInfo +{ +public: + CeSdkInfo(); + inline QString name(); + inline QString binPath(); + inline QString includePath(); + inline QString libPath(); + QStringList environment(); + inline bool isValid(); + inline int majorVersion(); + inline int minorVersion(); + inline bool isSupported(); +private: + friend class CeSdkHandler; + QString m_name; + QString m_bin; + QString m_include; + QString m_lib; + int m_major; + int m_minor; +}; + +inline QString CeSdkInfo::name(){ return m_name; } +inline QString CeSdkInfo::binPath(){ return m_bin; } +inline QString CeSdkInfo::includePath(){ return m_include; } +inline QString CeSdkInfo::libPath(){ return m_lib; } +inline bool CeSdkInfo::isValid(){ return !m_name.isEmpty() && !m_bin.isEmpty() && !m_include.isEmpty() && !m_lib.isEmpty(); } +inline int CeSdkInfo::majorVersion(){ return m_major; } +inline int CeSdkInfo::minorVersion(){ return m_minor; } +inline bool CeSdkInfo::isSupported() { return m_major >= 5; } + +class CeSdkHandler +{ +public: + CeSdkHandler(); + bool parse(); + inline QList listAll() const; + CeSdkInfo find(const QString &name); +private: + inline QString fixPaths(QString path) const; + QList m_list; + QString VCInstallDir; + QString VSInstallDir; +}; + +inline QList CeSdkHandler::listAll() const +{ + return m_list; +} + +inline QString CeSdkHandler::fixPaths(QString path) const +{ + QString str = QDir::toNativeSeparators(QDir::cleanPath(path.replace(QLatin1String(VCINSTALL_MACRO), VCInstallDir).replace(QLatin1String(VSINSTALL_MACRO), VSInstallDir).replace(QLatin1String("$(PATH)"), QLatin1String("%PATH%")))); + if (str.endsWith(QLatin1Char(';'))) + str.truncate(str.length() - 1); + return str; +} + +#endif diff --git a/src/checksdk/checksdk.pro b/src/checksdk/checksdk.pro new file mode 100644 index 000000000..a513981af --- /dev/null +++ b/src/checksdk/checksdk.pro @@ -0,0 +1,36 @@ +TEMPLATE = app +DESTDIR = ../../bin +TARGET = checksdk +DEPENDPATH += . +INCLUDEPATH += . +QT = +CONFIG += console + +build_all:!build_pass { + CONFIG -= build_all + CONFIG += release +} + +DEFINES += QT_BOOTSTRAPPED QT_NO_CODECS QT_LITE_UNICODE QT_NO_LIBRARY \ + QT_NO_STL QT_NO_COMPRESS QT_NO_DATASTREAM \ + QT_NO_TEXTCODEC QT_NO_UNICODETABLES QT_NO_THREAD \ + QT_NO_SYSTEMLOCALE QT_NO_GEOM_VARIANT \ + QT_NODLL QT_NO_QOBJECT + +INCLUDEPATH = \ + $$QT_BUILD_TREE/src/corelib/arch \ + $$QT_BUILD_TREE/include \ + $$QT_BUILD_TREE/include/QtCore + +DEPENDPATH += $$INCLUDEPATH $$QT_BUILD_TREE/src/corelib/base $$QT_BUILD_TREE/src/corelib/tools $$QT_BUILD_TREE/src/corelib/io + +# Input +SOURCES += \ + main.cpp \ + cesdkhandler.cpp + +HEADERS += \ + cesdkhandler.h + +include(../../src/tools/bootstrap/bootstrap.pri) + diff --git a/src/checksdk/main.cpp b/src/checksdk/main.cpp new file mode 100644 index 000000000..a5ff61d56 --- /dev/null +++ b/src/checksdk/main.cpp @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "cesdkhandler.h" +#include +#include +#include +#include + +void usage() +{ + printf("SDK Scanner - Convenience Tool to setup your environment\n"); + printf(" for crosscompilation to Windows CE\n"); + printf("Options:\n"); + printf("-help This output\n"); + printf("-list List all available SDKs\n"); + printf("-sdk Select specified SDK.\n"); + printf(" Note: SDK names with spaces need to be\n"); + printf(" specified in parenthesis\n"); + printf(" default: Windows Mobile 5.0 Pocket PC SDK (ARMV4I)\n"); + printf("-script Create a script file which can be launched\n"); + printf(" to setup your environment for specified SDK\n"); +} + +int main(int argc, char **argv) +{ + if (argc == 1) { + usage(); + return 0; + } + QString sdkName; + bool operationList = false; + QString scriptFile; + + QStringList arguments; + for (int i=0; i < argc; ++i) + arguments.append(QLatin1String(argv[i])); + for (int i=1; i < arguments.size(); ++i) { + if (arguments[i].toLower() == QLatin1String("-help")) { + usage(); + return 0; + } else if (arguments[i].toLower() == QLatin1String("-list")) { + operationList = true; + } else if (arguments[i].toLower() == QLatin1String("-sdk")) { + if (i+1 >= arguments.size()) { + qWarning("No SDK specified."); + return -1; + } + sdkName = arguments[++i]; + } else if (arguments[i].toLower() == QLatin1String("-script")) { + if (i+1 >= arguments.size()) { + qWarning("No scriptfile specified."); + return -1; + } + scriptFile = arguments[++i]; + } else { + qWarning("Unknown option:%s", qPrintable(arguments[i])); + usage(); + return -1; + } + } + + CeSdkHandler handler; + if (!handler.parse()) { + qWarning("Could not find any installed SDK, aborting!"); + return -1; + } + + QList list = handler.listAll(); + + if (operationList) { + printf("Available SDKs:\n"); + for (QList::iterator it = list.begin(); it != list.end(); ++it) { + printf("SDK Name: "); + printf(qPrintable(it->name())); + printf("\n"); + } + return 0; + } + + // Check for SDK Name, otherwise use Windows Mobile as default + if (sdkName.isEmpty()) { + qWarning("No SDK specified: Defaulting to Windows Mobile 5.0 Pocket PC SDK"); + sdkName = QString::fromLatin1("Windows Mobile 5.0 Pocket PC SDK (ARMV4I)"); + } + + // finally find the given SDK and prompt out the environment to be set + for (QList::iterator it = list.begin(); it != list.end(); ++it ) { + if (sdkName == it->name()) { + if (!it->isValid()) { + qWarning("Selected SDK is not valid!"); + return -1; + } else if (!it->isSupported()) { + qWarning("Selected SDK is not officially supported and might not work"); + } + QString binPath, includePath, libPath; + binPath = QString::fromLatin1("PATH=") + it->binPath(); + includePath = QString::fromLatin1("INCLUDE=") + it->includePath(); + libPath = QString::fromLatin1("LIB=") + it->libPath(); + if (scriptFile.isEmpty()) { + printf("Please set up your environment with the following paths:\n"); + printf(qPrintable(binPath)); + printf("\n"); + printf(qPrintable(includePath)); + printf("\n"); + printf(qPrintable(libPath)); + printf("\n"); + return 0; + } else { + QFile file(scriptFile); + if (!file.open(QIODevice::WriteOnly)) { + qWarning("Could not open target script file"); + return -1; + } + QString content; + content += QLatin1String("@echo off\n"); + content += QLatin1String("echo Environment Selection:") + sdkName + QLatin1String("\n"); + content += QLatin1String("set ") + binPath + QLatin1String("\n"); + content += QLatin1String("set ") + includePath + QLatin1String("\n"); + content += QLatin1String("set ") + libPath + QLatin1String("\n"); + file.write(content.toLatin1()); + return 0; + } + } + } + qWarning("Could not find specified SDK: %s" , qPrintable(sdkName)); + return -1; +} diff --git a/src/designer/data/generate_header.xsl b/src/designer/data/generate_header.xsl new file mode 100644 index 000000000..127f00557 --- /dev/null +++ b/src/designer/data/generate_header.xsl @@ -0,0 +1,465 @@ + +]> + + + + + + + + + + + + + class + + ;&endl; + + + + + + + + + + + enum Kind { Unknown = 0 + + + + + + + + + + + + + , + + + };&endl; + inline Kind kind() const { return m_kind; }&endl;&endl; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + inline + + element + + () const { return m_ + + ; }&endl; + + + + + takeElement + + ();&endl; + + + void setElement + + ( + + a);&endl; + + + inline bool hasElement + + () const { return m_children & + + ; }&endl; + void clearElement + + ();&endl; + + &endl; + + + + + + + + + + + + + + + + + + + + + + + + + + m_ + + ;&endl; + + + + enum Child {&endl; + + + + + + + + + + + + = + + + + + , + + &endl; + + + };&endl; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + inline bool hasAttribute + + () const { return m_has_attr_ + + ; }&endl; + + inline + + attribute + + () const { return m_attr_ + + ; }&endl; + + inline void setAttribute + + ( + + a) { m_attr_ + + = a; m_has_attr_ + + = true; }&endl; + + inline void clearAttribute + + () { m_has_attr_ + + = false; }&endl;&endl; + + + + + + + + + + + + class QDESIGNER_UILIB_EXPORT + + {&endl; + public:&endl; + + + ();&endl; + ~ + + ();&endl;&endl; + + void read(QXmlStreamReader &reader);&endl; + #ifdef QUILOADER_QDOM_READ&endl; + void read(const QDomElement &node);&endl; + #endif&endl; + void write(QXmlStreamWriter &writer, const QString &tagName = QString()) const;&endl; + + + inline QString text() const { return m_text; }&endl; + inline void setText(const QString &s) { m_text = s; }&endl; + + + &endl; + + // attribute accessors&endl; + + + + + // child element accessors&endl; + + + + + + + + private:&endl; + + + QString m_text;&endl; + + + void clear(bool clear_all = true);&endl;&endl; + + // attribute data&endl; + + + + + + + + + + + + + + m_attr_ + + ;&endl; + bool m_has_attr_ + + ;&endl;&endl; + + + // child element data&endl; + + Kind m_kind;&endl; + + + + uint m_children;&endl; + + + + + + + + &endl; + + + (const + + &other);&endl; + void operator = (const + + &other);&endl; + + };&endl;&endl; + + + + + + +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +// THIS FILE IS AUTOMATICALLY GENERATED + +#ifndef UI4_H +#define UI4_H + +#include <QtCore/QList> +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QXmlStreamReader> +#include <QtCore/QXmlStreamWriter> +#include <QtCore/qglobal.h> + +#if defined(QT_UIC3) + #define QUILOADER_QDOM_READ +#endif + +QT_BEGIN_NAMESPACE + +#ifdef QUILOADER_QDOM_READ + class QDomElement; +#endif + + +#define QDESIGNER_UILIB_EXTERN Q_DECL_EXPORT +#define QDESIGNER_UILIB_IMPORT Q_DECL_IMPORT + +#if defined(QT_DESIGNER_STATIC) || defined(QT_UIC) || defined(QT_UIC3) +# define QDESIGNER_UILIB_EXPORT +#elif defined(QDESIGNER_UILIB_LIBRARY) +# define QDESIGNER_UILIB_EXPORT QDESIGNER_UILIB_EXTERN +#else +# define QDESIGNER_UILIB_EXPORT QDESIGNER_UILIB_IMPORT +#endif + +#ifndef QDESIGNER_UILIB_EXPORT +# define QDESIGNER_UILIB_EXPORT +#endif + +#ifdef QFORMINTERNAL_NAMESPACE +namespace QFormInternal +{ +#endif + + + + &endl; + /*******************************************************************************&endl; + ** Forward declarations&endl; + */&endl;&endl; + + + + + + + + &endl; + /*******************************************************************************&endl; + ** Declarations&endl; + */&endl;&endl; + + + + + + + +#ifdef QFORMINTERNAL_NAMESPACE +} +#endif + +QT_END_NAMESPACE + +#endif // UI4_H + + + diff --git a/src/designer/data/generate_impl.xsl b/src/designer/data/generate_impl.xsl new file mode 100644 index 000000000..a22862e0c --- /dev/null +++ b/src/designer/data/generate_impl.xsl @@ -0,0 +1,1161 @@ + +]> + + + + + + + + + + + + + + + + + m_has_attr_ + + = false;&endl; + + + m_attr_ + + = 0;&endl; + + + m_attr_ + + = 0.0;&endl; + + + m_attr_ + + = 0.0;&endl; + + + m_attr_ + + = false;&endl; + + + + + + + + + + + + + + + + + + + + + + + + m_ + + = 0;&endl; + + + m_ + + = 0.0;&endl; + + + m_ + + = false;&endl; + + + + m_ + + = 0;&endl; + + + + + + + + + + + m_kind = Unknown;&endl;&endl; + + + + m_children = 0;&endl; + + + + + + + + m_text = QLatin1String("");&endl; + + + + + + + + + + + + + + + :: + + ()&endl; + {&endl; + + + + }&endl;&endl; + + + + + + + + + + + + + + + + + + + + + + qDeleteAll(m_ + + );&endl; + + m_ + + .clear();&endl; + + + + delete m_ + + ;&endl; + + + + + + + + + + + + ::~ + + ()&endl; + {&endl; + + + + + + + + }&endl;&endl; + + + + + + + + + void + ::clear(bool clear_all)&endl; + {&endl; + + + + + + + + &endl; if (clear_all) {&endl; + + + + m_text = QLatin1String("");&endl; + + + m_text.clear();&endl; + + + + + + + }&endl;&endl; + + + m_kind = Unknown;&endl;&endl; + + + + m_children = 0;&endl; + + + + + + + + + }&endl;&endl; + + + + + + + + + QString(QLatin1Char(' + + ')) + + + QLatin1String(" + + ") + + + + + + + + + + + &endl; + foreach (const QXmlStreamAttribute &attribute, reader.attributes()) {&endl; + QStringRef name = attribute.name();&endl; + + + + + + + + + + + + + + + + + attribute.value().toString() + + + + + if (name == + + + + ) {&endl; + setAttribute + + ( + + );&endl; + continue;&endl; + }&endl; + + + reader.raiseError(QLatin1String("Unexpected attribute ") + name.toString());&endl; + }&endl; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + if (tag == + + + + ) {&endl; + + + + + + + + + + + setElement + + ( + + );&endl; + + + + + + + + + + m_ + + .append( + + );&endl; + + + Dom + + *v = new Dom + + ();&endl; + v->read(reader);&endl; + setElement + + (v);&endl; + + + Dom + + *v = new Dom + + ();&endl; + v->read(reader);&endl; + m_ + + .append(v);&endl; + + + continue;&endl; + }&endl; + + + + + + + + void + + ::read(QXmlStreamReader &reader)&endl; + + {&endl; + + + + + + &endl; + + for (bool finished = false; !finished && !reader.hasError();) {&endl; + switch (reader.readNext()) {&endl; + case QXmlStreamReader::StartElement : {&endl; + const QString tag = reader.name().toString().toLower();&endl; + + + + + + + + reader.raiseError(QLatin1String("Unexpected element ") + tag);&endl; + }&endl; + break;&endl; + case QXmlStreamReader::EndElement :&endl; + finished = true;&endl; + break;&endl; + case QXmlStreamReader::Characters :&endl; + if (!reader.isWhitespace())&endl; + m_text.append(reader.text().toString());&endl; + break;&endl; + default :&endl; + break;&endl; + + }&endl; + }&endl; + }&endl;&endl; + + + + + + + + + &endl; + + + + + + + + + + + + + + + + + node.attribute( + + + + ) + + + + + if (node.hasAttribute( + + + + ))&endl; + setAttribute + + ( + + );&endl; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + if (tag == + + + + ) {&endl; + + + + + + + + + + + setElement + + ( + + );&endl; + + + + + + + + + + m_ + + .append( + + );&endl; + + + Dom + + *v = new Dom + + ();&endl; + v->read(e);&endl; + setElement + + (v);&endl; + + + Dom + + *v = new Dom + + ();&endl; + v->read(e);&endl; + m_ + + .append(v);&endl; + + + continue;&endl; + }&endl; + + + + + + + + #ifdef QUILOADER_QDOM_READ&endl; + + void + + ::read(const QDomElement &node)&endl; + + { + + + + + + &endl; + + for (QDomNode n = node.firstChild(); !n.isNull(); n = n.nextSibling()) {&endl; + if (!n.isElement())&endl; + continue;&endl; + QDomElement e = n.toElement();&endl; + QString tag = e.tagName().toLower();&endl; + + + + + + + + }&endl; + + + + m_text = QLatin1String("");&endl; + + + m_text.clear();&endl; + + + + for (QDomNode child = node.firstChild(); !child.isNull(); child = child.nextSibling()) {&endl; + if (child.isText())&endl; + m_text.append(child.nodeValue());&endl; + }&endl; + + }&endl; + #endif&endl; + &endl; + + + + + + + + + + + + + + + + + + + + + + + + if (hasAttribute + + ())&endl; + writer.writeAttribute( + + + + + , + + + + + + + );&endl;&endl; + + + + + + + + switch (kind()) {&endl; + + + + + + + + + + + + + + + + + + + + + + + + case + + : {&endl; + + + + + + + + + + writer.writeTextElement( + + + + , + + );&endl; + + + + + + + + + + + v = element + + ();&endl; + if (v != 0) {&endl; + v->write(writer, + + + + );&endl; + }&endl; + + + break;&endl; + }&endl; + + + default:&endl; + break;&endl; + }&endl; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + for (int i = 0; i < m_ + + .size(); ++i) {&endl; + + + v = m_ + + [i];&endl; + + + v->write(writer, + + + + );&endl; + + + + + + + + + + writer.writeTextElement( + + + + , + + );&endl; + + + }&endl; + + + if (m_children & + + ) {&endl; + + + m_ + + ->write(writer, + + + + );&endl; + + + + + + + + + writer.writeTextElement( + + + + , + + );&endl; + + + }&endl;&endl; + + + + + + + + + + + + + + + void + + ::write(QXmlStreamWriter &writer, const QString &tagName) const&endl; + {&endl; + + writer.writeStartElement(tagName.isEmpty() ? QString::fromUtf8(" + + ") : tagName.toLower());&endl;&endl; + + + + + + + + + + + + + + + + + + if (!m_text.isEmpty())&endl; + writer.writeCharacters(m_text);&endl;&endl; + + writer.writeEndElement();&endl; + }&endl;&endl; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ::takeElement + + () &endl;{&endl; + + + a = m_ + + ;&endl; + m_ + + = 0;&endl; + + m_children ^= + + ;&endl; + + return a;&endl; + }&endl;&endl; + + + void + + ::setElement + + ( + + a)&endl; + {&endl; + + + clear(false);&endl; + m_kind = + + ;&endl; + + + delete + m_ + + ;&endl; + + + + m_children |= + + ;&endl; + + m_ + + = a;&endl; + }&endl;&endl; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + void + + ::clearElement + + ()&endl; + {&endl; + + delete m_ + + ;&endl; + m_ + + = 0;&endl; + + m_children &= ~ + + ;&endl; + }&endl;&endl; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + #include "ui4_p.h"&endl; + &endl; + #ifdef QUILOADER_QDOM_READ&endl; + #include <QtXml/QDomElement>&endl; + #endif&endl; + &endl; + QT_BEGIN_NAMESPACE&endl; + + #ifdef QFORMINTERNAL_NAMESPACE&endl; + using namespace QFormInternal;&endl; + #endif&endl; + &endl; + + /*******************************************************************************&endl; + ** Implementations&endl; + */&endl;&endl; + + + + + + + QT_END_NAMESPACE&endl; + + &endl; + + + diff --git a/src/designer/data/generate_shared.xsl b/src/designer/data/generate_shared.xsl new file mode 100644 index 000000000..ec95fe2b8 --- /dev/null +++ b/src/designer/data/generate_shared.xsl @@ -0,0 +1,331 @@ + +]> + + + + + + + exportMacro + layoutDefault + layoutFunction + pixmapFunction + customWidgets + tabStops + tabStop + buttonGroups + exportMacro + actionGroup + buttonGroup + customWidget + sizeHint + addPageMethod + sizePolicy + horData + verData + rowSpan + colSpan + addAction + zOrder + startX + startY + endX + endY + centralX + centralY + focalX + focalY + widgetData + coordinateMode + brushStyle + colorRole + pointSize + strikeOut + styleStrategy + hSizeType + vSizeType + horStretch + verStretch + normalOff + normalOn + disabledOff + disabledOn + activeOff + activeOn + selectedOff + selectedOn + cursorShape + iconSet + stringList + dateTime + pointF + rectF + sizeF + longLong + UInt + uLongLong + rowStretch + columnStretch + rowMinimumHeight + columnMinimumWidth + extraComment + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + + + + + + + + + + + + + + + .toInt() + + + + .toFloat() + + + + .toDouble() + + + ( + + == QLatin1String("true") ? true : false) + + + + .toLongLong() + + + + .toUInt() + + + + .toULongLong() + + ### BZZZZT! ### + + + + + + + + + + + + QString::number( + + ) + + + QString::number( + + ) + + + QString::number( + + ) + + + QString::number( + + ) + + + QString::number( + + , 'f', 8) + + + QString::number( + + , 'f', 15) + + + ( + + ? QLatin1String("true") : QLatin1String("false")) + + ### BZZZZT! ### + + + + + + + + value + + + value + value + value + value + value + value + value + value + pointer + + + + + + + + + + + + QStringList + QList<int> + QList<float> + QList<double> + QList<bool> + QList<qlonglong> + QList<uint> + QList<qulonglong> + QList<Dom*> + + + + + QString + int + float + double + bool + qlonglong + uint + qulonglong + Dom + + + + + + + + + + + + QStringList + QList<int> + QList<float> + QList<double> + QList<bool> + QList<qlonglong> + QList<uint> + QList<qulonglong> + QList<Dom*> + + + + + QString + int + float + double + bool + qlonglong + uint + qulonglong + Dom* + + + + + + + + + + + + const QStringList& + const QList<int>& + const QList<float>& + const QList<double>& + const QList<bool>& + const QList<qlonglong>& + const QList<uint>& + const QList<qulonglong>& + const QList<Dom*>& + + + + + const QString& + int + float + double + bool + qlonglong + uint + qulonglong + Dom* + + + + + + + diff --git a/src/designer/data/ui3.xsd b/src/designer/data/ui3.xsd new file mode 100644 index 000000000..06f325ef3 --- /dev/null +++ b/src/designer/data/ui3.xsd @@ -0,0 +1,353 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/designer/data/ui4.xsd b/src/designer/data/ui4.xsd new file mode 100644 index 000000000..53bae62e2 --- /dev/null +++ b/src/designer/data/ui4.xsd @@ -0,0 +1,589 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/designer/designer.pro b/src/designer/designer.pro new file mode 100644 index 000000000..721c4fc42 --- /dev/null +++ b/src/designer/designer.pro @@ -0,0 +1,5 @@ +TEMPLATE = subdirs + +CONFIG += qt + +SUBDIRS = src diff --git a/src/designer/src/components/buddyeditor/buddyeditor.cpp b/src/designer/src/components/buddyeditor/buddyeditor.cpp new file mode 100644 index 000000000..34e1681ef --- /dev/null +++ b/src/designer/src/components/buddyeditor/buddyeditor.cpp @@ -0,0 +1,446 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "buddyeditor.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static const char *buddyPropertyC = "buddy"; + +static bool canBeBuddy(QWidget *w, QDesignerFormWindowInterface *form) +{ + if (qobject_cast(w) || qobject_cast(w)) + return false; + if (w == form->mainContainer() || w->isHidden() ) + return false; + + QExtensionManager *ext = form->core()->extensionManager(); + if (QDesignerPropertySheetExtension *sheet = qt_extension(ext, w)) { + const int index = sheet->indexOf(QLatin1String("focusPolicy")); + if (index != -1) { + bool ok = false; + const Qt::FocusPolicy q = static_cast(qdesigner_internal::Utils::valueOf(sheet->property(index), &ok)); + // Refuse No-focus unless the widget is promoted. + return (ok && q != Qt::NoFocus) || qdesigner_internal::isPromoted(form->core(), w); + } + } + return false; +} + +static QString buddy(QLabel *label, QDesignerFormEditorInterface *core) +{ + QDesignerPropertySheetExtension *sheet = qt_extension(core->extensionManager(), label); + if (sheet == 0) + return QString(); + const int prop_idx = sheet->indexOf(QLatin1String(buddyPropertyC)); + if (prop_idx == -1) + return QString(); + return sheet->property(prop_idx).toString(); +} + +typedef QList LabelList; + +namespace qdesigner_internal { + +/******************************************************************************* +** BuddyEditor +*/ + +BuddyEditor::BuddyEditor(QDesignerFormWindowInterface *form, QWidget *parent) : + ConnectionEdit(parent, form), + m_formWindow(form), + m_updating(false) +{ +} + + +QWidget *BuddyEditor::widgetAt(const QPoint &pos) const +{ + QWidget *w = ConnectionEdit::widgetAt(pos); + + while (w != 0 && !m_formWindow->isManaged(w)) + w = w->parentWidget(); + if (!w) + return w; + + if (state() == Editing) { + QLabel *label = qobject_cast(w); + if (label == 0) + return 0; + const int cnt = connectionCount(); + for (int i = 0; i < cnt; ++i) { + Connection *con = connection(i); + if (con->widget(EndPoint::Source) == w) + return 0; + } + } else { + if (!canBeBuddy(w, m_formWindow)) + return 0; + } + + return w; +} + +Connection *BuddyEditor::createConnection(QWidget *source, QWidget *destination) +{ + return new Connection(this, source, destination); +} + +QDesignerFormWindowInterface *BuddyEditor::formWindow() const +{ + return m_formWindow; +} + +void BuddyEditor::updateBackground() +{ + if (m_updating || background() == 0) + return; + ConnectionEdit::updateBackground(); + + m_updating = true; + QList newList; + const LabelList label_list = background()->findChildren(); + foreach (QLabel *label, label_list) { + const QString buddy_name = buddy(label, m_formWindow->core()); + if (buddy_name.isEmpty()) + continue; + + const QList targets = background()->findChildren(buddy_name); + if (targets.isEmpty()) + continue; + + QWidget *target = 0; + + QListIterator it(targets); + while (it.hasNext()) { + QWidget *widget = it.next(); + if (widget && !widget->isHidden()) { + target = widget; + break; + } + } + + if (target == 0) + continue; + + Connection *con = new Connection(this); + con->setEndPoint(EndPoint::Source, label, widgetRect(label).center()); + con->setEndPoint(EndPoint::Target, target, widgetRect(target).center()); + newList.append(con); + } + + QList toRemove; + + const int c = connectionCount(); + for (int i = 0; i < c; i++) { + Connection *con = connection(i); + QObject *source = con->object(EndPoint::Source); + QObject *target = con->object(EndPoint::Target); + bool found = false; + QListIterator it(newList); + while (it.hasNext()) { + Connection *newConn = it.next(); + if (newConn->object(EndPoint::Source) == source && newConn->object(EndPoint::Target) == target) { + found = true; + break; + } + } + if (found == false) + toRemove.append(con); + } + if (!toRemove.isEmpty()) { + DeleteConnectionsCommand command(this, toRemove); + command.redo(); + foreach (Connection *con, toRemove) + delete takeConnection(con); + } + + QListIterator it(newList); + while (it.hasNext()) { + Connection *newConn = it.next(); + + bool found = false; + const int c = connectionCount(); + for (int i = 0; i < c; i++) { + Connection *con = connection(i); + if (con->object(EndPoint::Source) == newConn->object(EndPoint::Source) && + con->object(EndPoint::Target) == newConn->object(EndPoint::Target)) { + found = true; + break; + } + } + if (found == false) { + AddConnectionCommand command(this, newConn); + command.redo(); + } else { + delete newConn; + } + } + m_updating = false; +} + +void BuddyEditor::setBackground(QWidget *background) +{ + clear(); + ConnectionEdit::setBackground(background); + + const LabelList label_list = background->findChildren(); + foreach (QLabel *label, label_list) { + const QString buddy_name = buddy(label, m_formWindow->core()); + if (buddy_name.isEmpty()) + continue; + QWidget *target = background->findChild(buddy_name); + if (target == 0) + continue; + + Connection *con = new Connection(this); + con->setEndPoint(EndPoint::Source, label, widgetRect(label).center()); + con->setEndPoint(EndPoint::Target, target, widgetRect(target).center()); + addConnection(con); + } +} + +static QUndoCommand *createBuddyCommand(QDesignerFormWindowInterface *fw, QLabel *label, QWidget *buddy) +{ + SetPropertyCommand *command = new SetPropertyCommand(fw); + command->init(label, QLatin1String(buddyPropertyC), buddy->objectName()); + command->setText(BuddyEditor::tr("Add buddy")); + return command; +} + +void BuddyEditor::endConnection(QWidget *target, const QPoint &pos) +{ + Connection *tmp_con = newlyAddedConnection(); + Q_ASSERT(tmp_con != 0); + + tmp_con->setEndPoint(EndPoint::Target, target, pos); + + QWidget *source = tmp_con->widget(EndPoint::Source); + Q_ASSERT(source != 0); + Q_ASSERT(target != 0); + setEnabled(false); + Connection *new_con = createConnection(source, target); + setEnabled(true); + if (new_con != 0) { + new_con->setEndPoint(EndPoint::Source, source, tmp_con->endPointPos(EndPoint::Source)); + new_con->setEndPoint(EndPoint::Target, target, tmp_con->endPointPos(EndPoint::Target)); + + selectNone(); + addConnection(new_con); + QLabel *source = qobject_cast(new_con->widget(EndPoint::Source)); + QWidget *target = new_con->widget(EndPoint::Target); + if (source) { + undoStack()->push(createBuddyCommand(m_formWindow, source, target)); + } else { + qDebug("BuddyEditor::endConnection(): not a label"); + } + setSelected(new_con, true); + } + + clearNewlyAddedConnection(); + findObjectsUnderMouse(mapFromGlobal(QCursor::pos())); +} + +void BuddyEditor::widgetRemoved(QWidget *widget) +{ + QList child_list = widget->findChildren(); + child_list.prepend(widget); + + ConnectionSet remove_set; + foreach (QWidget *w, child_list) { + const ConnectionList &cl = connectionList(); + foreach (Connection *con, cl) { + if (con->widget(EndPoint::Source) == w || con->widget(EndPoint::Target) == w) + remove_set.insert(con, con); + } + } + + if (!remove_set.isEmpty()) { + undoStack()->beginMacro(tr("Remove buddies")); + foreach (Connection *con, remove_set) { + setSelected(con, false); + con->update(); + QWidget *source = con->widget(EndPoint::Source); + if (qobject_cast(source) == 0) { + qDebug("BuddyConnection::widgetRemoved(): not a label"); + } else { + ResetPropertyCommand *command = new ResetPropertyCommand(formWindow()); + command->init(source, QLatin1String(buddyPropertyC)); + undoStack()->push(command); + } + delete takeConnection(con); + } + undoStack()->endMacro(); + } +} + +void BuddyEditor::deleteSelected() +{ + const ConnectionSet selectedConnections = selection(); // want copy for unselect + if (selectedConnections.isEmpty()) + return; + + undoStack()->beginMacro(tr("Remove %n buddies", 0, selectedConnections.size())); + foreach (Connection *con, selectedConnections) { + setSelected(con, false); + con->update(); + QWidget *source = con->widget(EndPoint::Source); + if (qobject_cast(source) == 0) { + qDebug("BuddyConnection::deleteSelected(): not a label"); + } else { + ResetPropertyCommand *command = new ResetPropertyCommand(formWindow()); + command->init(source, QLatin1String(buddyPropertyC)); + undoStack()->push(command); + } + delete takeConnection(con); + } + undoStack()->endMacro(); +} + +void BuddyEditor::autoBuddy() +{ + // Any labels? + LabelList labelList = background()->findChildren(); + if (labelList.empty()) + return; + // Find already used buddies + QWidgetList usedBuddies; + const ConnectionList &beforeConnections = connectionList(); + foreach (const Connection *c, beforeConnections) + usedBuddies.push_back(c->widget(EndPoint::Target)); + // Find potential new buddies, keep lists in sync + QWidgetList buddies; + for (LabelList::iterator it = labelList.begin(); it != labelList.end(); ) { + QLabel *label = *it; + QWidget *newBuddy = 0; + if (m_formWindow->isManaged(label)) { + const QString buddy_name = buddy(label, m_formWindow->core()); + if (buddy_name.isEmpty()) + newBuddy = findBuddy(label, usedBuddies); + } + if (newBuddy) { + buddies.push_back(newBuddy); + usedBuddies.push_back(newBuddy); + ++it; + } else { + it = labelList.erase(it); + } + } + // Add the list in one go. + if (labelList.empty()) + return; + const int count = labelList.size(); + Q_ASSERT(count == buddies.size()); + undoStack()->beginMacro(tr("Add %n buddies", 0, count)); + for (int i = 0; i < count; i++) + undoStack()->push(createBuddyCommand(m_formWindow, labelList.at(i), buddies.at(i))); + undoStack()->endMacro(); + // Now select all new ones + const ConnectionList &connections = connectionList(); + foreach (Connection *con, connections) + setSelected(con, buddies.contains(con->widget(EndPoint::Target))); +} + +// Geometrically find a potential buddy for label by checking neighbouring children of parent +QWidget *BuddyEditor::findBuddy(QLabel *l, const QWidgetList &existingBuddies) const +{ + enum { DeltaX = 5 }; + const QWidget *parent = l->parentWidget(); + // Try to find next managed neighbour on horizontal line + const QRect geom = l->geometry(); + const int y = geom.center().y(); + QWidget *neighbour = 0; + switch (l->layoutDirection()) { + case Qt::LayoutDirectionAuto: + case Qt::LeftToRight: { // Walk right to find next managed neighbour + const int xEnd = parent->size().width(); + for (int x = geom.right() + 1; x < xEnd; x += DeltaX) + if (QWidget *c = parent->childAt (x, y)) + if (m_formWindow->isManaged(c)) { + neighbour = c; + break; + } + } + break; + case Qt::RightToLeft: // Walk left to find next managed neighbour + for (int x = geom.x() - 1; x >= 0; x -= DeltaX) + if (QWidget *c = parent->childAt (x, y)) + if (m_formWindow->isManaged(c)) { + neighbour = c; + break; + } + break; + } + if (neighbour && !existingBuddies.contains(neighbour) && canBeBuddy(neighbour, m_formWindow)) + return neighbour; + + return 0; +} + +void BuddyEditor::createContextMenu(QMenu &menu) +{ + QAction *autoAction = menu.addAction(tr("Set automatically")); + connect(autoAction, SIGNAL(triggered()), this, SLOT(autoBuddy())); + menu.addSeparator(); + ConnectionEdit::createContextMenu(menu); +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/buddyeditor/buddyeditor.h b/src/designer/src/components/buddyeditor/buddyeditor.h new file mode 100644 index 000000000..2cd60071e --- /dev/null +++ b/src/designer/src/components/buddyeditor/buddyeditor.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BUDDYEDITOR_H +#define BUDDYEDITOR_H + +#include "buddyeditor_global.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +class QLabel; + +namespace qdesigner_internal { + +class QT_BUDDYEDITOR_EXPORT BuddyEditor : public ConnectionEdit +{ + Q_OBJECT + +public: + BuddyEditor(QDesignerFormWindowInterface *form, QWidget *parent); + + QDesignerFormWindowInterface *formWindow() const; + virtual void setBackground(QWidget *background); + virtual void deleteSelected(); + +public slots: + virtual void updateBackground(); + virtual void widgetRemoved(QWidget *w); + void autoBuddy(); + +protected: + virtual QWidget *widgetAt(const QPoint &pos) const; + virtual Connection *createConnection(QWidget *source, QWidget *destination); + virtual void endConnection(QWidget *target, const QPoint &pos); + virtual void createContextMenu(QMenu &menu); + +private: + QWidget *findBuddy(QLabel *l, const QWidgetList &existingBuddies) const; + + QPointer m_formWindow; + bool m_updating; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif diff --git a/src/designer/src/components/buddyeditor/buddyeditor.pri b/src/designer/src/components/buddyeditor/buddyeditor.pri new file mode 100644 index 000000000..c507aa01d --- /dev/null +++ b/src/designer/src/components/buddyeditor/buddyeditor.pri @@ -0,0 +1,16 @@ + +QT += xml + +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/buddyeditor.h \ + $$PWD/buddyeditor_plugin.h \ + $$PWD/buddyeditor_tool.h \ + $$PWD/buddyeditor_global.h + +SOURCES += \ + $$PWD/buddyeditor.cpp \ + $$PWD/buddyeditor_tool.cpp \ + $$PWD/buddyeditor_plugin.cpp \ + $$PWD/buddyeditor_instance.cpp diff --git a/src/designer/src/components/buddyeditor/buddyeditor_global.h b/src/designer/src/components/buddyeditor/buddyeditor_global.h new file mode 100644 index 000000000..00b216b67 --- /dev/null +++ b/src/designer/src/components/buddyeditor/buddyeditor_global.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BUDDYEDITOR_GLOBAL_H +#define BUDDYEDITOR_GLOBAL_H + +#include + +#ifdef Q_OS_WIN +#ifdef QT_BUDDYEDITOR_LIBRARY +# define QT_BUDDYEDITOR_EXPORT +#else +# define QT_BUDDYEDITOR_EXPORT +#endif +#else +#define QT_BUDDYEDITOR_EXPORT +#endif + +#endif // BUDDYEDITOR_GLOBAL_H diff --git a/src/designer/src/components/buddyeditor/buddyeditor_instance.cpp b/src/designer/src/components/buddyeditor/buddyeditor_instance.cpp new file mode 100644 index 000000000..ef71ec32c --- /dev/null +++ b/src/designer/src/components/buddyeditor/buddyeditor_instance.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "buddyeditor_plugin.h" + +QT_USE_NAMESPACE + +using namespace qdesigner_internal; + +Q_EXPORT_PLUGIN(BuddyEditorPlugin) diff --git a/src/designer/src/components/buddyeditor/buddyeditor_plugin.cpp b/src/designer/src/components/buddyeditor/buddyeditor_plugin.cpp new file mode 100644 index 000000000..17b93e1b5 --- /dev/null +++ b/src/designer/src/components/buddyeditor/buddyeditor_plugin.cpp @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "buddyeditor_plugin.h" +#include "buddyeditor_tool.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +BuddyEditorPlugin::BuddyEditorPlugin() + : m_initialized(false) +{ +} + +BuddyEditorPlugin::~BuddyEditorPlugin() +{ +} + +bool BuddyEditorPlugin::isInitialized() const +{ + return m_initialized; +} + +void BuddyEditorPlugin::initialize(QDesignerFormEditorInterface *core) +{ + Q_ASSERT(!isInitialized()); + + m_action = new QAction(tr("Edit Buddies"), this); + m_action->setObjectName(QLatin1String("__qt_edit_buddies_action")); + QIcon buddyIcon = QIcon::fromTheme("designer-edit-buddy", + QIcon(core->resourceLocation() + QLatin1String("/buddytool.png"))); + m_action->setIcon(buddyIcon); + m_action->setEnabled(false); + + setParent(core); + m_core = core; + m_initialized = true; + + connect(core->formWindowManager(), SIGNAL(formWindowAdded(QDesignerFormWindowInterface*)), + this, SLOT(addFormWindow(QDesignerFormWindowInterface*))); + + connect(core->formWindowManager(), SIGNAL(formWindowRemoved(QDesignerFormWindowInterface*)), + this, SLOT(removeFormWindow(QDesignerFormWindowInterface*))); + + connect(core->formWindowManager(), SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)), + this, SLOT(activeFormWindowChanged(QDesignerFormWindowInterface*))); +} + +QDesignerFormEditorInterface *BuddyEditorPlugin::core() const +{ + return m_core; +} + +void BuddyEditorPlugin::addFormWindow(QDesignerFormWindowInterface *formWindow) +{ + Q_ASSERT(formWindow != 0); + Q_ASSERT(m_tools.contains(formWindow) == false); + + BuddyEditorTool *tool = new BuddyEditorTool(formWindow, this); + m_tools[formWindow] = tool; + connect(m_action, SIGNAL(triggered()), tool->action(), SLOT(trigger())); + formWindow->registerTool(tool); +} + +void BuddyEditorPlugin::removeFormWindow(QDesignerFormWindowInterface *formWindow) +{ + Q_ASSERT(formWindow != 0); + Q_ASSERT(m_tools.contains(formWindow) == true); + + BuddyEditorTool *tool = m_tools.value(formWindow); + m_tools.remove(formWindow); + disconnect(m_action, SIGNAL(triggered()), tool->action(), SLOT(trigger())); + // ### FIXME disable the tool + + delete tool; +} + +QAction *BuddyEditorPlugin::action() const +{ + return m_action; +} + +void BuddyEditorPlugin::activeFormWindowChanged(QDesignerFormWindowInterface *formWindow) +{ + m_action->setEnabled(formWindow != 0); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/buddyeditor/buddyeditor_plugin.h b/src/designer/src/components/buddyeditor/buddyeditor_plugin.h new file mode 100644 index 000000000..7e6e51550 --- /dev/null +++ b/src/designer/src/components/buddyeditor/buddyeditor_plugin.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BUDDYEDITOR_PLUGIN_H +#define BUDDYEDITOR_PLUGIN_H + +#include "buddyeditor_global.h" + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QAction; + +namespace qdesigner_internal { + +class BuddyEditorTool; + +class QT_BUDDYEDITOR_EXPORT BuddyEditorPlugin: public QObject, public QDesignerFormEditorPluginInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerFormEditorPluginInterface) +public: + BuddyEditorPlugin(); + virtual ~BuddyEditorPlugin(); + + virtual bool isInitialized() const; + virtual void initialize(QDesignerFormEditorInterface *core); + QAction *action() const; + + virtual QDesignerFormEditorInterface *core() const; + +public slots: + void activeFormWindowChanged(QDesignerFormWindowInterface *formWindow); + +private slots: + void addFormWindow(QDesignerFormWindowInterface *formWindow); + void removeFormWindow(QDesignerFormWindowInterface *formWindow); + +private: + QPointer m_core; + QHash m_tools; + bool m_initialized; + QAction *m_action; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // BUDDYEDITOR_PLUGIN_H diff --git a/src/designer/src/components/buddyeditor/buddyeditor_tool.cpp b/src/designer/src/components/buddyeditor/buddyeditor_tool.cpp new file mode 100644 index 000000000..3779789fa --- /dev/null +++ b/src/designer/src/components/buddyeditor/buddyeditor_tool.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "buddyeditor_tool.h" +#include "buddyeditor.h" + +#include + +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +BuddyEditorTool::BuddyEditorTool(QDesignerFormWindowInterface *formWindow, QObject *parent) + : QDesignerFormWindowToolInterface(parent), + m_formWindow(formWindow), + m_action(new QAction(tr("Edit Buddies"), this)) +{ +} + +BuddyEditorTool::~BuddyEditorTool() +{ +} + +QDesignerFormEditorInterface *BuddyEditorTool::core() const +{ + return m_formWindow->core(); +} + +QDesignerFormWindowInterface *BuddyEditorTool::formWindow() const +{ + return m_formWindow; +} + +bool BuddyEditorTool::handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event) +{ + Q_UNUSED(widget); + Q_UNUSED(managedWidget); + Q_UNUSED(event); + + return false; +} + +QWidget *BuddyEditorTool::editor() const +{ + if (!m_editor) { + Q_ASSERT(formWindow() != 0); + m_editor = new BuddyEditor(formWindow(), 0); + connect(formWindow(), SIGNAL(mainContainerChanged(QWidget*)), m_editor, SLOT(setBackground(QWidget*))); + connect(formWindow(), SIGNAL(changed()), + m_editor, SLOT(updateBackground())); + } + + return m_editor; +} + +void BuddyEditorTool::activated() +{ + m_editor->enableUpdateBackground(true); +} + +void BuddyEditorTool::deactivated() +{ + m_editor->enableUpdateBackground(false); +} + +QAction *BuddyEditorTool::action() const +{ + return m_action; +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/buddyeditor/buddyeditor_tool.h b/src/designer/src/components/buddyeditor/buddyeditor_tool.h new file mode 100644 index 000000000..dabb4654d --- /dev/null +++ b/src/designer/src/components/buddyeditor/buddyeditor_tool.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BUDDYEDITOR_TOOL_H +#define BUDDYEDITOR_TOOL_H + +#include "buddyeditor_global.h" + +#include + +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; +class QAction; + +namespace qdesigner_internal { + +class BuddyEditor; + +class QT_BUDDYEDITOR_EXPORT BuddyEditorTool: public QDesignerFormWindowToolInterface +{ + Q_OBJECT +public: + explicit BuddyEditorTool(QDesignerFormWindowInterface *formWindow, QObject *parent = 0); + virtual ~BuddyEditorTool(); + + virtual QDesignerFormEditorInterface *core() const; + virtual QDesignerFormWindowInterface *formWindow() const; + + virtual QWidget *editor() const; + virtual QAction *action() const; + + virtual void activated(); + virtual void deactivated(); + + virtual bool handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event); + +private: + QDesignerFormWindowInterface *m_formWindow; + mutable QPointer m_editor; + QAction *m_action; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // BUDDYEDITOR_TOOL_H diff --git a/src/designer/src/components/component.pri b/src/designer/src/components/component.pri new file mode 100644 index 000000000..c2fc10d9e --- /dev/null +++ b/src/designer/src/components/component.pri @@ -0,0 +1,2 @@ + +TARGET = $$qtLibraryTarget($$TARGET$$QT_LIBINFIX) #do this towards the end diff --git a/src/designer/src/components/components.pro b/src/designer/src/components/components.pro new file mode 100644 index 000000000..97d79b4bb --- /dev/null +++ b/src/designer/src/components/components.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +CONFIG += ordered +SUBDIRS = lib diff --git a/src/designer/src/components/formeditor/brushmanagerproxy.cpp b/src/designer/src/components/formeditor/brushmanagerproxy.cpp new file mode 100644 index 000000000..59803336e --- /dev/null +++ b/src/designer/src/components/formeditor/brushmanagerproxy.cpp @@ -0,0 +1,303 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtbrushmanager.h" +#include "brushmanagerproxy.h" +#include "qsimpleresource_p.h" +#include "qdesigner_utils_p.h" +#include "ui4_p.h" + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class BrushManagerProxyPrivate +{ + BrushManagerProxy *q_ptr; + Q_DECLARE_PUBLIC(BrushManagerProxy) + +public: + BrushManagerProxyPrivate(BrushManagerProxy *bp, QDesignerFormEditorInterface *core); + void brushAdded(const QString &name, const QBrush &brush); + void brushRemoved(const QString &name); + QString uniqueBrushFileName(const QString &brushName) const; + + QtBrushManager *m_Manager; + QString m_designerFolder; + const QString m_BrushFolder; + QString m_BrushPath; + QDesignerFormEditorInterface *m_Core; + QMap m_FileToBrush; + QMap m_BrushToFile; +}; + +BrushManagerProxyPrivate::BrushManagerProxyPrivate(BrushManagerProxy *bp, QDesignerFormEditorInterface *core) : + q_ptr(bp), + m_Manager(0), + m_BrushFolder(QLatin1String("brushes")), + m_Core(core) +{ + m_designerFolder = QDir::homePath(); + m_designerFolder += QDir::separator(); + m_designerFolder += QLatin1String(".designer"); + m_BrushPath = m_designerFolder; + m_BrushPath += QDir::separator(); + m_BrushPath += m_BrushFolder; +} +} // namespace qdesigner_internal + +using namespace qdesigner_internal; + +void BrushManagerProxyPrivate::brushAdded(const QString &name, const QBrush &brush) +{ + const QString filename = uniqueBrushFileName(name); + + QDir designerDir(m_designerFolder); + if (!designerDir.exists(m_BrushFolder)) + designerDir.mkdir(m_BrushFolder); + + QFile file(m_BrushPath + QDir::separator() +filename); + if (file.open(QIODevice::WriteOnly)) { + QSimpleResource resource(m_Core); + + DomBrush *dom = resource.saveBrush(brush); + + QXmlStreamWriter writer(&file); + writer.setAutoFormatting(true); + writer.setAutoFormattingIndent(1); + writer.writeStartDocument(); + writer.writeStartElement(QLatin1String("description")); + writer.writeAttribute(QLatin1String("name"), name); + dom->write(writer); + writer.writeEndElement(); + writer.writeEndDocument(); + + delete dom; + file.close(); + + m_FileToBrush[filename] = name; + m_BrushToFile[name] = filename; + } +} + +void BrushManagerProxyPrivate::brushRemoved(const QString &name) +{ + QDir brushDir(m_BrushPath); + + QString filename = m_BrushToFile[name]; + brushDir.remove(filename); + m_BrushToFile.remove(name); + m_FileToBrush.remove(filename); +} + +QString BrushManagerProxyPrivate::uniqueBrushFileName(const QString &brushName) const +{ + const QString extension = QLatin1String(".br"); + QString filename = brushName.toLower(); + filename += extension; + int i = 0; + while (m_FileToBrush.contains(filename)) { + filename = brushName.toLower(); + filename += QString::number(++i); + filename += extension; + } + return filename; +} + + +BrushManagerProxy::BrushManagerProxy(QDesignerFormEditorInterface *core, QObject *parent) + : QObject(parent), d_ptr(new BrushManagerProxyPrivate(this, core)) +{ +} + +BrushManagerProxy::~BrushManagerProxy() +{ +} + +void BrushManagerProxy::setBrushManager(QtBrushManager *manager) +{ + if (d_ptr->m_Manager == manager) + return; + + if (d_ptr->m_Manager) { + disconnect(d_ptr->m_Manager, SIGNAL(brushAdded(QString,QBrush)), + this, SLOT(brushAdded(QString,QBrush))); + disconnect(d_ptr->m_Manager, SIGNAL(brushRemoved(QString)), + this, SLOT(brushRemoved(QString))); + } + + d_ptr->m_Manager = manager; + + if (!d_ptr->m_Manager) + return; + + // clear the manager + QMap brushes = d_ptr->m_Manager->brushes(); + QMap::ConstIterator it = brushes.constBegin(); + while (it != brushes.constEnd()) { + QString name = it.key(); + d_ptr->m_Manager->removeBrush(name); + + it++; + } + + // fill up the manager from compiled resources or from brush folder here + const QString nameAttribute = QLatin1String("name"); + const QString brush = QLatin1String("brush"); + const QString description = QLatin1String("description"); + + QDir brushDir(d_ptr->m_BrushPath); + bool customBrushesExist = brushDir.exists(); + if (customBrushesExist) { + // load brushes from brush folder + QStringList nameFilters; + nameFilters.append(QLatin1String("*.br")); + + QFileInfoList infos = brushDir.entryInfoList(nameFilters); + QListIterator it(infos); + while (it.hasNext()) { + const QFileInfo fi = it.next(); + + QString filename = fi.absoluteFilePath(); + + QFile file(filename); + if (file.open(QIODevice::ReadOnly)) { + QXmlStreamReader reader(&file); + + // + // + // + // + // + + QString descname; + while (!reader.atEnd()) { + if (reader.readNext() == QXmlStreamReader::StartElement) { + const QString tag = reader.name().toString().toLower(); + if (tag == description) { + if (!reader.attributes().hasAttribute(nameAttribute)) + reader.raiseError(tr("The element '%1' is missing the required attribute '%2'.") + .arg(tag, nameAttribute)); + else + descname = reader.attributes().value(nameAttribute).toString(); + continue; + } + if (tag == brush) { + DomBrush brush; + brush.read(reader); + + if (descname.isEmpty()) { + reader.raiseError(tr("Empty brush name encountered.")); + } else { + QSimpleResource resource(d_ptr->m_Core); + QBrush br = resource.setupBrush(&brush); + d_ptr->m_Manager->addBrush(descname, br); + d_ptr->m_FileToBrush[filename] = descname; + d_ptr->m_BrushToFile[descname] = filename; + } + continue; + } + reader.raiseError(tr("An unexpected element '%1' was encountered.").arg(tag)); + } + } + + file.close(); + + if (reader.hasError()) { + qdesigner_internal::designerWarning(tr("An error occurred when reading the brush definition file '%1' at line line %2, column %3: %4") + .arg(fi.fileName()) + .arg(reader.lineNumber()) + .arg(reader.columnNumber()) + .arg(reader.errorString())); + continue; + } + } + } + } + + connect(d_ptr->m_Manager, SIGNAL(brushAdded(QString,QBrush)), + this, SLOT(brushAdded(QString,QBrush))); + connect(d_ptr->m_Manager, SIGNAL(brushRemoved(QString)), + this, SLOT(brushRemoved(QString))); + + if (!customBrushesExist) { + // load brushes from resources + QFile qrcFile(QLatin1String(":trolltech/brushes/defaultbrushes.xml")); + if (!qrcFile.open(QIODevice::ReadOnly)) + Q_ASSERT(0); + + QXmlStreamReader reader(&qrcFile); + + while (!reader.atEnd()) { + if (reader.readNext() == QXmlStreamReader::StartElement) { + if (reader.name().toString().toLower() == QLatin1String("description")) { + const QString name = reader.attributes().value(nameAttribute).toString(); + do { // forward to element, which DomBrush expects + reader.readNext(); + } while (!reader.atEnd() && reader.tokenType() != QXmlStreamReader::StartElement); + DomBrush brushDom; + brushDom.read(reader); + if (!reader.hasError()) { + QSimpleResource resource(d_ptr->m_Core); + QBrush br = resource.setupBrush(&brushDom); + d_ptr->m_Manager->addBrush(name, br); + } + } + } + } + if (reader.hasError()) { + // Should never happen + qdesigner_internal::designerWarning(tr("An error occurred when reading the resource file '%1' at line %2, column %3: %4") + .arg(qrcFile.fileName()) + .arg(reader.lineNumber()) + .arg(reader.columnNumber()) + .arg(reader.errorString())); + } + + qrcFile.close(); + } +} + +QT_END_NAMESPACE + +#include "moc_brushmanagerproxy.cpp" diff --git a/src/designer/src/components/formeditor/brushmanagerproxy.h b/src/designer/src/components/formeditor/brushmanagerproxy.h new file mode 100644 index 000000000..934bd8d46 --- /dev/null +++ b/src/designer/src/components/formeditor/brushmanagerproxy.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BRUSHMANAGERPROXY_H +#define BRUSHMANAGERPROXY_H + +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +class QtBrushManager; +class BrushManagerProxyPrivate; + +class BrushManagerProxy : public QObject +{ + Q_OBJECT +public: + explicit BrushManagerProxy(QDesignerFormEditorInterface *core, QObject *parent = 0); + ~BrushManagerProxy(); + + void setBrushManager(QtBrushManager *manager); + +private: + QScopedPointer d_ptr; + Q_DECLARE_PRIVATE(BrushManagerProxy) + Q_DISABLE_COPY(BrushManagerProxy) + Q_PRIVATE_SLOT(d_func(), void brushAdded(const QString &, const QBrush &)) + Q_PRIVATE_SLOT(d_func(), void brushRemoved(const QString &name)) +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif diff --git a/src/designer/src/components/formeditor/default_actionprovider.cpp b/src/designer/src/components/formeditor/default_actionprovider.cpp new file mode 100644 index 000000000..c0a51dede --- /dev/null +++ b/src/designer/src/components/formeditor/default_actionprovider.cpp @@ -0,0 +1,207 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "default_actionprovider.h" +#include "invisible_widget_p.h" +#include "qdesigner_toolbar_p.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// ------------ ActionProviderBase: +// Draws the drag indicator when dragging an action over a widget +// that receives action Dnd, such as ToolBar, Menu or MenuBar. +ActionProviderBase::ActionProviderBase(QWidget *widget) : + m_indicator(new InvisibleWidget(widget)) +{ + Q_ASSERT(widget != 0); + + m_indicator->setAutoFillBackground(true); + m_indicator->setBackgroundRole(QPalette::Window); + + QPalette p; + p.setColor(m_indicator->backgroundRole(), Qt::red); + m_indicator->setPalette(p); + m_indicator->hide(); +} + +enum { indicatorSize = 2 }; + +// Position an indicator horizontally over the rectangle, indicating +// 'Insert before' (left or right according to layout direction) +static inline QRect horizontalIndicatorRect(const QRect &rect, Qt::LayoutDirection layoutDirection) +{ + // Position right? + QRect rc = QRect(rect.x(), 0, indicatorSize, rect.height() - 1); + if (layoutDirection == Qt::RightToLeft) + rc.moveLeft(rc.x() + rect.width() - indicatorSize); + return rc; +} + +// Position an indicator vertically over the rectangle, indicating 'Insert before' (top) +static inline QRect verticalIndicatorRect(const QRect &rect) +{ + return QRect(0, rect.top(), rect.width() - 1, indicatorSize); +} + +// Determine the geometry of the indicator by retrieving +// the action under mouse and positioning the bar within its geometry. +QRect ActionProviderBase::indicatorGeometry(const QPoint &pos, Qt::LayoutDirection layoutDirection) const +{ + QAction *action = actionAt(pos); + if (!action) + return QRect(); + QRect rc = actionGeometry(action); + return orientation() == Qt::Horizontal ? horizontalIndicatorRect(rc, layoutDirection) : verticalIndicatorRect(rc); +} + +// Adjust the indicator while dragging. (-1,1) is called to finish a DND operation +void ActionProviderBase::adjustIndicator(const QPoint &pos) +{ + if (pos == QPoint(-1, -1)) { + m_indicator->hide(); + return; + } + const QRect ig = indicatorGeometry(pos, m_indicator->layoutDirection()); + if (ig.isValid()) { + m_indicator->setGeometry(ig); + QPalette p = m_indicator->palette(); + if (p.color(m_indicator->backgroundRole()) != Qt::red) { + p.setColor(m_indicator->backgroundRole(), Qt::red); + m_indicator->setPalette(p); + } + m_indicator->show(); + m_indicator->raise(); + } else { + m_indicator->hide(); + } +} + +// ------------- QToolBarActionProvider +QToolBarActionProvider::QToolBarActionProvider(QToolBar *widget, QObject *parent) : + QObject(parent), + ActionProviderBase(widget), + m_widget(widget) +{ +} + +QRect QToolBarActionProvider::actionGeometry(QAction *action) const +{ + return m_widget->actionGeometry(action); +} + +QAction *QToolBarActionProvider::actionAt(const QPoint &pos) const +{ + return ToolBarEventFilter::actionAt(m_widget, pos); +} + +Qt::Orientation QToolBarActionProvider::orientation() const +{ + return m_widget->orientation(); +} + +QRect QToolBarActionProvider::indicatorGeometry(const QPoint &pos, Qt::LayoutDirection layoutDirection) const +{ + const QRect actionRect = ActionProviderBase::indicatorGeometry(pos, layoutDirection); + if (actionRect.isValid()) + return actionRect; + // Toolbar differs in that is has no dummy placeholder to 'insert before' + // when intending to append. Check the free area. + const QRect freeArea = ToolBarEventFilter::freeArea(m_widget); + if (!freeArea.contains(pos)) + return QRect(); + return orientation() == Qt::Horizontal ? horizontalIndicatorRect(freeArea, layoutDirection) : verticalIndicatorRect(freeArea); +} + +// ------------- QMenuBarActionProvider +QMenuBarActionProvider::QMenuBarActionProvider(QMenuBar *widget, QObject *parent) : + QObject(parent), + ActionProviderBase(widget), + m_widget(widget) +{ +} + +QRect QMenuBarActionProvider::actionGeometry(QAction *action) const +{ + return m_widget->actionGeometry(action); +} + +QAction *QMenuBarActionProvider::actionAt(const QPoint &pos) const +{ + return m_widget->actionAt(pos); +} + +Qt::Orientation QMenuBarActionProvider::orientation() const +{ + return Qt::Horizontal; +} + +// ------------- QMenuActionProvider +QMenuActionProvider::QMenuActionProvider(QMenu *widget, QObject *parent) : + QObject(parent), + ActionProviderBase(widget), + m_widget(widget) +{ +} + +QRect QMenuActionProvider::actionGeometry(QAction *action) const +{ + return m_widget->actionGeometry(action); +} + +QAction *QMenuActionProvider::actionAt(const QPoint &pos) const +{ + return m_widget->actionAt(pos); +} + +Qt::Orientation QMenuActionProvider::orientation() const +{ + return Qt::Vertical; +} +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/default_actionprovider.h b/src/designer/src/components/formeditor/default_actionprovider.h new file mode 100644 index 000000000..9eba71eef --- /dev/null +++ b/src/designer/src/components/formeditor/default_actionprovider.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DEFAULT_ACTIONPROVIDER_H +#define DEFAULT_ACTIONPROVIDER_H + +#include "formeditor_global.h" +#include "actionprovider_p.h" +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class FormWindow; + +class QT_FORMEDITOR_EXPORT ActionProviderBase: public QDesignerActionProviderExtension +{ +protected: + explicit ActionProviderBase(QWidget *widget); + +public: + virtual void adjustIndicator(const QPoint &pos); + virtual Qt::Orientation orientation() const = 0; + +protected: + virtual QRect indicatorGeometry(const QPoint &pos, Qt::LayoutDirection layoutDirection) const; + +private: + QWidget *m_indicator; +}; + +class QT_FORMEDITOR_EXPORT QToolBarActionProvider: public QObject, public ActionProviderBase +{ + Q_OBJECT + Q_INTERFACES(QDesignerActionProviderExtension) +public: + explicit QToolBarActionProvider(QToolBar *widget, QObject *parent = 0); + + virtual QRect actionGeometry(QAction *action) const; + virtual QAction *actionAt(const QPoint &pos) const; + Qt::Orientation orientation() const; + +protected: + virtual QRect indicatorGeometry(const QPoint &pos, Qt::LayoutDirection layoutDirection) const; + +private: + QToolBar *m_widget; +}; + +class QT_FORMEDITOR_EXPORT QMenuBarActionProvider: public QObject, public ActionProviderBase +{ + Q_OBJECT + Q_INTERFACES(QDesignerActionProviderExtension) +public: + explicit QMenuBarActionProvider(QMenuBar *widget, QObject *parent = 0); + + virtual QRect actionGeometry(QAction *action) const; + virtual QAction *actionAt(const QPoint &pos) const; + Qt::Orientation orientation() const; + +private: + QMenuBar *m_widget; +}; + +class QT_FORMEDITOR_EXPORT QMenuActionProvider: public QObject, public ActionProviderBase +{ + Q_OBJECT + Q_INTERFACES(QDesignerActionProviderExtension) +public: + explicit QMenuActionProvider(QMenu *widget, QObject *parent = 0); + + virtual QRect actionGeometry(QAction *action) const; + virtual QAction *actionAt(const QPoint &pos) const; + Qt::Orientation orientation() const; + +private: + QMenu *m_widget; +}; + +typedef ExtensionFactory QToolBarActionProviderFactory; +typedef ExtensionFactory QMenuBarActionProviderFactory; +typedef ExtensionFactory QMenuActionProviderFactory; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // DEFAULT_ACTIONPROVIDER_H diff --git a/src/designer/src/components/formeditor/default_container.cpp b/src/designer/src/components/formeditor/default_container.cpp new file mode 100644 index 000000000..e5f2c5b87 --- /dev/null +++ b/src/designer/src/components/formeditor/default_container.cpp @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "default_container.h" +#include + +QT_BEGIN_NAMESPACE + +template +static inline void setCurrentContainerIndex(int index, Container *container) +{ + const bool blocked = container->signalsBlocked(); + container->blockSignals(true); + container->setCurrentIndex(index); + container->blockSignals(blocked); +} + +static inline void ensureNoParent(QWidget *widget) +{ + if (widget->parentWidget()) + widget->setParent(0); +} + +static const char *PageLabel = "Page"; + +namespace qdesigner_internal { + +// --------- QStackedWidgetContainer +QStackedWidgetContainer::QStackedWidgetContainer(QStackedWidget *widget, QObject *parent) : + QObject(parent), + m_widget(widget) +{ +} + +void QStackedWidgetContainer::setCurrentIndex(int index) +{ + setCurrentContainerIndex(index, m_widget); +} + +void QStackedWidgetContainer::addWidget(QWidget *widget) +{ + ensureNoParent(widget); + m_widget->addWidget(widget); +} + +void QStackedWidgetContainer::insertWidget(int index, QWidget *widget) +{ + ensureNoParent(widget); + m_widget->insertWidget(index, widget); +} + +void QStackedWidgetContainer::remove(int index) +{ + m_widget->removeWidget(widget(index)); +} + +// --------- QTabWidgetContainer +QTabWidgetContainer::QTabWidgetContainer(QTabWidget *widget, QObject *parent) : + QObject(parent), + m_widget(widget) +{ +} + +void QTabWidgetContainer::setCurrentIndex(int index) +{ + setCurrentContainerIndex(index, m_widget); +} + +void QTabWidgetContainer::addWidget(QWidget *widget) +{ + ensureNoParent(widget); + m_widget->addTab(widget, QString::fromUtf8(PageLabel)); +} + +void QTabWidgetContainer::insertWidget(int index, QWidget *widget) +{ + ensureNoParent(widget); + m_widget->insertTab(index, widget, QString::fromUtf8(PageLabel)); +} + +void QTabWidgetContainer::remove(int index) +{ + m_widget->removeTab(index); +} + +// ------------------- QToolBoxContainer +QToolBoxContainer::QToolBoxContainer(QToolBox *widget, QObject *parent) : + QObject(parent), + m_widget(widget) +{ +} + +void QToolBoxContainer::setCurrentIndex(int index) +{ + setCurrentContainerIndex(index, m_widget); +} + +void QToolBoxContainer::addWidget(QWidget *widget) +{ + ensureNoParent(widget); + m_widget->addItem(widget, QString::fromUtf8(PageLabel)); +} + +void QToolBoxContainer::insertWidget(int index, QWidget *widget) +{ + ensureNoParent(widget); + m_widget->insertItem(index, widget, QString::fromUtf8(PageLabel)); +} + +void QToolBoxContainer::remove(int index) +{ + m_widget->removeItem(index); +} + +// ------------------- QScrollAreaContainer +// We pass on active=true only if there are no children yet. +// If there are children, it is a legacy custom widget QScrollArea that has an internal, +// unmanaged child, in which case we deactivate the extension (otherwise we crash). +// The child will then not show up in the task menu + +QScrollAreaContainer::QScrollAreaContainer(QScrollArea *widget, QObject *parent) : + QObject(parent), + SingleChildContainer(widget, widget->widget() == 0) +{ +} +// ------------------- QDockWidgetContainer +QDockWidgetContainer::QDockWidgetContainer(QDockWidget *widget, QObject *parent) : + QObject(parent), + SingleChildContainer(widget) +{ +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/default_container.h b/src/designer/src/components/formeditor/default_container.h new file mode 100644 index 000000000..753f39794 --- /dev/null +++ b/src/designer/src/components/formeditor/default_container.h @@ -0,0 +1,213 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DEFAULT_CONTAINER_H +#define DEFAULT_CONTAINER_H + +#include +#include +#include + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// ------------ QStackedWidgetContainer +class QStackedWidgetContainer: public QObject, public QDesignerContainerExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerContainerExtension) +public: + explicit QStackedWidgetContainer(QStackedWidget *widget, QObject *parent = 0); + + virtual int count() const { return m_widget->count(); } + virtual QWidget *widget(int index) const { return m_widget->widget(index); } + + virtual int currentIndex() const { return m_widget->currentIndex(); } + virtual void setCurrentIndex(int index); + + virtual void addWidget(QWidget *widget); + virtual void insertWidget(int index, QWidget *widget); + virtual void remove(int index); + +private: + QStackedWidget *m_widget; +}; + +// ------------ QTabWidgetContainer +class QTabWidgetContainer: public QObject, public QDesignerContainerExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerContainerExtension) +public: + explicit QTabWidgetContainer(QTabWidget *widget, QObject *parent = 0); + + virtual int count() const { return m_widget->count(); } + virtual QWidget *widget(int index) const { return m_widget->widget(index); } + + virtual int currentIndex() const { return m_widget->currentIndex(); } + virtual void setCurrentIndex(int index); + + virtual void addWidget(QWidget *widget); + virtual void insertWidget(int index, QWidget *widget); + virtual void remove(int index); + +private: + QTabWidget *m_widget; +}; + +// ------------ QToolBoxContainer +class QToolBoxContainer: public QObject, public QDesignerContainerExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerContainerExtension) +public: + explicit QToolBoxContainer(QToolBox *widget, QObject *parent = 0); + + virtual int count() const { return m_widget->count(); } + virtual QWidget *widget(int index) const { return m_widget->widget(index); } + + virtual int currentIndex() const { return m_widget->currentIndex(); } + virtual void setCurrentIndex(int index); + + virtual void addWidget(QWidget *widget); + virtual void insertWidget(int index, QWidget *widget); + virtual void remove(int index); + +private: + QToolBox *m_widget; +}; + +// ------------ SingleChildContainer: +// Template for containers that have a single child widget using widget()/setWidget(). + +template +class SingleChildContainer: public QDesignerContainerExtension +{ +protected: + explicit SingleChildContainer(Container *widget, bool active = true); +public: + virtual int count() const; + virtual QWidget *widget(int index) const; + virtual int currentIndex() const; + virtual void setCurrentIndex(int /*index*/) {} + virtual void addWidget(QWidget *widget); + virtual void insertWidget(int index, QWidget *widget); + virtual void remove(int /*index*/) {} + +private: + const bool m_active; + Container *m_container; +}; + +template +SingleChildContainer::SingleChildContainer(Container *widget, bool active) : + m_active(active), + m_container(widget) +{ +} + +template +int SingleChildContainer::count() const +{ + return m_active && m_container->widget() ? 1 : 0; +} + +template +QWidget *SingleChildContainer::widget(int /* index */) const +{ + return m_container->widget(); +} + +template +int SingleChildContainer::currentIndex() const +{ + return m_active && m_container->widget() ? 0 : -1; +} + +template +void SingleChildContainer::addWidget(QWidget *widget) +{ + Q_ASSERT(m_container->widget() == 0); + widget->setParent(m_container); + m_container->setWidget(widget); +} + +template +void SingleChildContainer::insertWidget(int /* index */, QWidget *widget) +{ + addWidget(widget); +} + +// ------------ QScrollAreaContainer +class QScrollAreaContainer: public QObject, public SingleChildContainer +{ + Q_OBJECT + Q_INTERFACES(QDesignerContainerExtension) +public: + explicit QScrollAreaContainer(QScrollArea *widget, QObject *parent = 0); +}; + +// --------------- QDockWidgetContainer +class QDockWidgetContainer: public QObject, public SingleChildContainer +{ + Q_OBJECT + Q_INTERFACES(QDesignerContainerExtension) +public: + explicit QDockWidgetContainer(QDockWidget *widget, QObject *parent = 0); +}; + +typedef ExtensionFactory QDesignerStackedWidgetContainerFactory; +typedef ExtensionFactory QDesignerTabWidgetContainerFactory; +typedef ExtensionFactory QDesignerToolBoxContainerFactory; +typedef ExtensionFactory QScrollAreaContainerFactory; +typedef ExtensionFactory QDockWidgetContainerFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // DEFAULT_CONTAINER_H diff --git a/src/designer/src/components/formeditor/default_layoutdecoration.cpp b/src/designer/src/components/formeditor/default_layoutdecoration.cpp new file mode 100644 index 000000000..95f190d5d --- /dev/null +++ b/src/designer/src/components/formeditor/default_layoutdecoration.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "default_layoutdecoration.h" +#include "qlayout_widget_p.h" + +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// ---- QDesignerLayoutDecorationFactory ---- +QDesignerLayoutDecorationFactory::QDesignerLayoutDecorationFactory(QExtensionManager *parent) + : QExtensionFactory(parent) +{ +} + +QObject *QDesignerLayoutDecorationFactory::createExtension(QObject *object, const QString &iid, QObject *parent) const +{ + if (!object->isWidgetType() || iid != Q_TYPEID(QDesignerLayoutDecorationExtension)) + return 0; + + QWidget *widget = qobject_cast(object); + + if (const QLayoutWidget *layoutWidget = qobject_cast(widget)) + return QLayoutSupport::createLayoutSupport(layoutWidget->formWindow(), widget, parent); + + if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(widget)) + if (LayoutInfo::managedLayout(fw->core(), widget)) + return QLayoutSupport::createLayoutSupport(fw, widget, parent); + + return 0; +} +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/default_layoutdecoration.h b/src/designer/src/components/formeditor/default_layoutdecoration.h new file mode 100644 index 000000000..ee876e88e --- /dev/null +++ b/src/designer/src/components/formeditor/default_layoutdecoration.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DEFAULT_LAYOUTDECORATION_H +#define DEFAULT_LAYOUTDECORATION_H + +#include "formeditor_global.h" +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { +class QDesignerLayoutDecorationFactory: public QExtensionFactory +{ + Q_OBJECT + Q_INTERFACES(QAbstractExtensionFactory) +public: + explicit QDesignerLayoutDecorationFactory(QExtensionManager *parent = 0); + +protected: + virtual QObject *createExtension(QObject *object, const QString &iid, QObject *parent) const; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // DEFAULT_LAYOUTDECORATION_H diff --git a/src/designer/src/components/formeditor/defaultbrushes.xml b/src/designer/src/components/formeditor/defaultbrushes.xml new file mode 100644 index 000000000..88035c3a6 --- /dev/null +++ b/src/designer/src/components/formeditor/defaultbrushes.xml @@ -0,0 +1,542 @@ + + + + + + + 0 + 0 + 255 + + + + + 0 + 0 + 255 + + + + + 255 + 255 + 255 + + + + + 255 + 255 + 255 + + + + + 255 + 0 + 0 + + + + + 255 + 0 + 0 + + + + + + + + + + + 0 + 0 + 0 + + + + + 0 + 0 + 0 + + + + + 255 + 0 + 0 + + + + + 255 + 0 + 0 + + + + + 255 + 255 + 0 + + + + + 255 + 255 + 0 + + + + + + + + + + + 0 + 176 + 221 + + + + + 0 + 176 + 221 + + + + + 255 + 255 + 255 + + + + + 255 + 255 + 255 + + + + + 0 + 176 + 221 + + + + + 0 + 176 + 221 + + + + + 255 + 255 + 255 + + + + + 255 + 255 + 255 + + + + + 0 + 176 + 221 + + + + + 0 + 176 + 221 + + + + + 255 + 255 + 255 + + + + + 255 + 255 + 255 + + + + + 0 + 176 + 221 + + + + + 0 + 176 + 221 + + + + + 255 + 255 + 255 + + + + + 255 + 255 + 255 + + + + + 0 + 176 + 221 + + + + + 0 + 176 + 221 + + + + + + + + + + + 60 + 160 + 0 + + + + + 60 + 160 + 0 + + + + + 255 + 255 + 255 + + + + + 255 + 255 + 255 + + + + + 255 + 0 + 0 + + + + + 255 + 0 + 0 + + + + + + + + + + + 255 + 0 + 0 + + + + + 255 + 0 + 0 + + + + + 255 + 255 + 255 + + + + + 255 + 255 + 255 + + + + + + + + + + + 255 + 0 + 0 + + + + + 255 + 0 + 0 + + + + + 255 + 255 + 255 + + + + + 255 + 255 + 255 + + + + + 5 + 0 + 70 + + + + + 5 + 0 + 70 + + + + + 255 + 255 + 255 + + + + + 255 + 255 + 255 + + + + + 255 + 0 + 0 + + + + + 255 + 0 + 0 + + + + + + + + + + + 255 + 255 + 255 + + + + + 255 + 255 + 255 + + + + + 255 + 0 + 0 + + + + + 255 + 0 + 0 + + + + + + + + + + + 255 + 0 + 0 + + + + + 255 + 0 + 0 + + + + + 255 + 255 + 0 + + + + + 255 + 255 + 0 + + + + + 255 + 0 + 0 + + + + + 255 + 0 + 0 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 255 + + + + + + + 0 + 255 + 255 + + + + + + + 0 + 255 + 0 + + + + + + + 255 + 0 + 255 + + + + + + + 255 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 0 + + + + diff --git a/src/designer/src/components/formeditor/deviceprofiledialog.cpp b/src/designer/src/components/formeditor/deviceprofiledialog.cpp new file mode 100644 index 000000000..b7030689d --- /dev/null +++ b/src/designer/src/components/formeditor/deviceprofiledialog.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "deviceprofiledialog.h" +#include "ui_deviceprofiledialog.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +static const char *profileExtensionC = "qdp"; + +static inline QString fileFilter() +{ + return qdesigner_internal::DeviceProfileDialog::tr("Device Profiles (*.%1)").arg(QLatin1String(profileExtensionC)); +} + +// Populate a combo with a sequence of integers, also set them as data. +template + static void populateNumericCombo(IntIterator i1, IntIterator i2, QComboBox *cb) +{ + QString s; + cb->setEditable(false); + for ( ; i1 != i2 ; ++i1) { + const int n = *i1; + s.setNum(n); + cb->addItem(s, QVariant(n)); + } +} + +namespace qdesigner_internal { + +DeviceProfileDialog::DeviceProfileDialog(QDesignerDialogGuiInterface *dlgGui, QWidget *parent) : + QDialog(parent), + m_ui(new Ui::DeviceProfileDialog), + m_dlgGui(dlgGui) +{ + setModal(true); + m_ui->setupUi(this); + + const QList standardFontSizes = QFontDatabase::standardSizes(); + populateNumericCombo(standardFontSizes.constBegin(), standardFontSizes.constEnd(), m_ui->m_systemFontSizeCombo); + + // Styles + const QStringList styles = QStyleFactory::keys(); + m_ui->m_styleCombo->addItem(tr("Default"), QVariant(QString())); + const QStringList::const_iterator cend = styles.constEnd(); + for (QStringList::const_iterator it = styles.constBegin(); it != cend; ++it) + m_ui->m_styleCombo->addItem(*it, *it); + + connect(m_ui->m_nameLineEdit, SIGNAL(textChanged(QString)), this, SLOT(nameChanged(QString))); + connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + connect(m_ui->buttonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(accept())); + // Note that Load/Save emit accepted() of the button box.. + connect(m_ui->buttonBox->button(QDialogButtonBox::Save), SIGNAL(clicked()), this, SLOT(save())); + connect(m_ui->buttonBox->button(QDialogButtonBox::Open), SIGNAL(clicked()), this, SLOT(open())); +} + +DeviceProfileDialog::~DeviceProfileDialog() +{ + delete m_ui; +} + +DeviceProfile DeviceProfileDialog::deviceProfile() const +{ + DeviceProfile rc; + rc.setName(m_ui->m_nameLineEdit->text()); + rc.setFontFamily(m_ui->m_systemFontComboBox->currentFont().family()); + rc.setFontPointSize(m_ui->m_systemFontSizeCombo->itemData(m_ui->m_systemFontSizeCombo->currentIndex()).toInt()); + + int dpiX, dpiY; + m_ui->m_dpiChooser->getDPI(&dpiX, &dpiY); + rc.setDpiX(dpiX); + rc.setDpiY(dpiY); + + rc.setStyle(m_ui->m_styleCombo->itemData(m_ui->m_styleCombo->currentIndex()).toString()); + + return rc; +} + +void DeviceProfileDialog::setDeviceProfile(const DeviceProfile &s) +{ + m_ui->m_nameLineEdit->setText(s.name()); + m_ui->m_systemFontComboBox->setCurrentFont(QFont(s.fontFamily())); + const int fontSizeIndex = m_ui->m_systemFontSizeCombo->findData(QVariant(s.fontPointSize())); + m_ui->m_systemFontSizeCombo->setCurrentIndex(fontSizeIndex != -1 ? fontSizeIndex : 0); + m_ui->m_dpiChooser->setDPI(s.dpiX(), s.dpiY()); + const int styleIndex = m_ui->m_styleCombo->findData(s.style()); + m_ui->m_styleCombo->setCurrentIndex(styleIndex != -1 ? styleIndex : 0); +} + +void DeviceProfileDialog::setOkButtonEnabled(bool v) +{ + m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(v); +} + +bool DeviceProfileDialog::showDialog(const QStringList &existingNames) +{ + m_existingNames = existingNames; + m_ui->m_nameLineEdit->setFocus(Qt::OtherFocusReason); + nameChanged(m_ui->m_nameLineEdit->text()); + return exec() == Accepted; +} + +void DeviceProfileDialog::nameChanged(const QString &name) +{ + const bool invalid = name.isEmpty() || m_existingNames.indexOf(name) != -1; + setOkButtonEnabled(!invalid); +} + +void DeviceProfileDialog::save() +{ + QString fn = m_dlgGui->getSaveFileName(this, tr("Save Profile"), QString(), fileFilter()); + if (fn.isEmpty()) + return; + if (QFileInfo(fn).completeSuffix().isEmpty()) { + fn += QLatin1Char('.'); + fn += QLatin1String(profileExtensionC); + } + + QFile file(fn); + if (!file.open(QIODevice::WriteOnly|QIODevice::Text)) { + critical(tr("Save Profile - Error"), tr("Unable to open the file '%1' for writing: %2").arg(fn, file.errorString())); + return; + } + file.write(deviceProfile().toXml().toUtf8()); +} + +void DeviceProfileDialog::open() +{ + const QString fn = m_dlgGui->getOpenFileName(this, tr("Open profile"), QString(), fileFilter()); + if (fn.isEmpty()) + return; + + QFile file(fn); + if (!file.open(QIODevice::ReadOnly|QIODevice::Text)) { + critical(tr("Open Profile - Error"), tr("Unable to open the file '%1' for reading: %2").arg(fn, file.errorString())); + return; + } + QString errorMessage; + DeviceProfile newSettings; + if (!newSettings.fromXml(QString::fromUtf8(file.readAll()), &errorMessage)) { + critical(tr("Open Profile - Error"), tr("'%1' is not a valid profile: %2").arg(fn, errorMessage)); + return; + } + setDeviceProfile(newSettings); +} + +void DeviceProfileDialog::critical(const QString &title, const QString &msg) +{ + m_dlgGui->message(this, QDesignerDialogGuiInterface::OtherMessage, QMessageBox::Critical, title, msg); +} +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/deviceprofiledialog.h b/src/designer/src/components/formeditor/deviceprofiledialog.h new file mode 100644 index 000000000..e35f30077 --- /dev/null +++ b/src/designer/src/components/formeditor/deviceprofiledialog.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef SYSTEMSETTINGSDIALOG_H +#define SYSTEMSETTINGSDIALOG_H + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace Ui { + class DeviceProfileDialog; +} + +class QDesignerDialogGuiInterface; + +class QDialogButtonBox; + +namespace qdesigner_internal { + +class DeviceProfile; + +/* DeviceProfileDialog: Widget to edit system settings for embedded design */ + +class DeviceProfileDialog : public QDialog +{ + Q_DISABLE_COPY(DeviceProfileDialog) + Q_OBJECT +public: + explicit DeviceProfileDialog(QDesignerDialogGuiInterface *dlgGui, QWidget *parent = 0); + ~DeviceProfileDialog(); + + DeviceProfile deviceProfile() const; + void setDeviceProfile(const DeviceProfile &s); + + bool showDialog(const QStringList &existingNames); + +private slots: + void setOkButtonEnabled(bool); + void nameChanged(const QString &name); + void save(); + void open(); + +private: + void critical(const QString &title, const QString &msg); + Ui::DeviceProfileDialog *m_ui; + QDesignerDialogGuiInterface *m_dlgGui; + QStringList m_existingNames; +}; +} + +QT_END_NAMESPACE + +#endif // SYSTEMSETTINGSDIALOG_H diff --git a/src/designer/src/components/formeditor/deviceprofiledialog.ui b/src/designer/src/components/formeditor/deviceprofiledialog.ui new file mode 100644 index 000000000..d7a298c67 --- /dev/null +++ b/src/designer/src/components/formeditor/deviceprofiledialog.ui @@ -0,0 +1,108 @@ + + + DeviceProfileDialog + + + + 0 + 0 + 348 + 209 + + + + + + + + + + &Family + + + m_systemFontComboBox + + + + + + + + + + &Point Size + + + m_systemFontSizeCombo + + + + + + + + + + Style + + + m_styleCombo + + + + + + + + + + Device DPI + + + + + + + + + + Name + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Open|QDialogButtonBox::Save + + + + + + + + qdesigner_internal::DPI_Chooser + QWidget +
dpi_chooser.h
+ 1 +
+
+ + m_nameLineEdit + m_systemFontComboBox + m_systemFontSizeCombo + m_styleCombo + buttonBox + + + +
diff --git a/src/designer/src/components/formeditor/dpi_chooser.cpp b/src/designer/src/components/formeditor/dpi_chooser.cpp new file mode 100644 index 000000000..6d665dd79 --- /dev/null +++ b/src/designer/src/components/formeditor/dpi_chooser.cpp @@ -0,0 +1,207 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "dpi_chooser.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +enum { minDPI = 50, maxDPI = 400 }; + +namespace qdesigner_internal { + +// Entry struct for predefined values +struct DPI_Entry { + int dpiX; + int dpiY; + const char *description; +}; + +const struct DPI_Entry dpiEntries[] = { + //: Embedded device standard screen resolution + { 96, 96, QT_TRANSLATE_NOOP("DPI_Chooser", "Standard (96 x 96)") }, + //: Embedded device screen resolution + { 179, 185, QT_TRANSLATE_NOOP("DPI_Chooser", "Greenphone (179 x 185)") }, + //: Embedded device high definition screen resolution + { 192, 192, QT_TRANSLATE_NOOP("DPI_Chooser", "High (192 x 192)") } +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(const struct qdesigner_internal::DPI_Entry*); + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// ------------- DPI_Chooser + +DPI_Chooser::DPI_Chooser(QWidget *parent) : + QWidget(parent), + m_systemEntry(new DPI_Entry), + m_predefinedCombo(new QComboBox), + m_dpiXSpinBox(new QSpinBox), + m_dpiYSpinBox(new QSpinBox) +{ + // Predefined settings: System + DeviceProfile::systemResolution(&(m_systemEntry->dpiX), &(m_systemEntry->dpiY)); + m_systemEntry->description = 0; + const struct DPI_Entry *systemEntry = m_systemEntry; + //: System resolution + m_predefinedCombo->addItem(tr("System (%1 x %2)").arg(m_systemEntry->dpiX).arg(m_systemEntry->dpiY), QVariant::fromValue(systemEntry)); + // Devices. Exclude the system values as not to duplicate the entries + const int predefinedCount = sizeof(dpiEntries)/sizeof(DPI_Entry); + const struct DPI_Entry *ecend = dpiEntries + predefinedCount; + for (const struct DPI_Entry *it = dpiEntries; it < ecend; ++it) + if (it->dpiX != m_systemEntry->dpiX || it->dpiY != m_systemEntry->dpiY) + m_predefinedCombo->addItem(tr(it->description), QVariant::fromValue(it)); + m_predefinedCombo->addItem(tr("User defined")); + + setFocusProxy(m_predefinedCombo); + m_predefinedCombo->setEditable(false); + m_predefinedCombo->setCurrentIndex(0); + connect(m_predefinedCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(syncSpinBoxes())); + // top row with predefined settings + QVBoxLayout *vBoxLayout = new QVBoxLayout; + vBoxLayout->setMargin(0); + vBoxLayout->addWidget(m_predefinedCombo); + // Spin box row + QHBoxLayout *hBoxLayout = new QHBoxLayout; + hBoxLayout->setMargin(0); + + m_dpiXSpinBox->setMinimum(minDPI); + m_dpiXSpinBox->setMaximum(maxDPI); + hBoxLayout->addWidget(m_dpiXSpinBox); + //: DPI X/Y separator + hBoxLayout->addWidget(new QLabel(tr(" x "))); + + m_dpiYSpinBox->setMinimum(minDPI); + m_dpiYSpinBox->setMaximum(maxDPI); + hBoxLayout->addWidget(m_dpiYSpinBox); + + hBoxLayout->addStretch(); + vBoxLayout->addLayout(hBoxLayout); + setLayout(vBoxLayout); + + syncSpinBoxes(); +} + +DPI_Chooser::~DPI_Chooser() +{ + delete m_systemEntry; +} + +void DPI_Chooser::getDPI(int *dpiX, int *dpiY) const +{ + *dpiX = m_dpiXSpinBox->value(); + *dpiY = m_dpiYSpinBox->value(); +} + +void DPI_Chooser::setDPI(int dpiX, int dpiY) +{ + // Default to system if it is something weird + const bool valid = dpiX >= minDPI && dpiX <= maxDPI && dpiY >= minDPI && dpiY <= maxDPI; + if (!valid) { + m_predefinedCombo->setCurrentIndex(0); + return; + } + // Try to find the values among the predefined settings + const int count = m_predefinedCombo->count(); + int predefinedIndex = -1; + for (int i = 0; i < count; i++) { + const QVariant data = m_predefinedCombo->itemData(i); + if (data.type() != QVariant::Invalid) { + const struct DPI_Entry *entry = qvariant_cast(data); + if (entry->dpiX == dpiX && entry->dpiY == dpiY) { + predefinedIndex = i; + break; + } + } + } + if (predefinedIndex != -1) { + m_predefinedCombo->setCurrentIndex(predefinedIndex); // triggers syncSpinBoxes() + } else { + setUserDefinedValues(dpiX, dpiY); + } +} + +void DPI_Chooser::setUserDefinedValues(int dpiX, int dpiY) +{ + const bool blocked = m_predefinedCombo->blockSignals(true); + m_predefinedCombo->setCurrentIndex(m_predefinedCombo->count() - 1); + m_predefinedCombo->blockSignals(blocked); + + m_dpiXSpinBox->setEnabled(true); + m_dpiYSpinBox->setEnabled(true); + m_dpiXSpinBox->setValue(dpiX); + m_dpiYSpinBox->setValue(dpiY); +} + +void DPI_Chooser::syncSpinBoxes() +{ + const int predefIdx = m_predefinedCombo->currentIndex(); + const QVariant data = m_predefinedCombo->itemData(predefIdx); + + // Predefined mode in which spin boxes are disabled or user defined? + const bool userSetting = data.type() == QVariant::Invalid; + m_dpiXSpinBox->setEnabled(userSetting); + m_dpiYSpinBox->setEnabled(userSetting); + + if (!userSetting) { + const struct DPI_Entry *entry = qvariant_cast(data); + m_dpiXSpinBox->setValue(entry->dpiX); + m_dpiYSpinBox->setValue(entry->dpiY); + } +} +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/dpi_chooser.h b/src/designer/src/components/formeditor/dpi_chooser.h new file mode 100644 index 000000000..10e3c72d8 --- /dev/null +++ b/src/designer/src/components/formeditor/dpi_chooser.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef DPICHOOSER_H +#define DPICHOOSER_H + +#include + +QT_BEGIN_NAMESPACE + +class QSpinBox; +class QComboBox; + +namespace qdesigner_internal { + +struct DPI_Entry; + +/* Let the user choose a DPI settings */ +class DPI_Chooser : public QWidget { + Q_DISABLE_COPY(DPI_Chooser) + Q_OBJECT + +public: + explicit DPI_Chooser(QWidget *parent = 0); + ~DPI_Chooser(); + + void getDPI(int *dpiX, int *dpiY) const; + void setDPI(int dpiX, int dpiY); + +private slots: + void syncSpinBoxes(); + +private: + void setUserDefinedValues(int dpiX, int dpiY); + + struct DPI_Entry *m_systemEntry; + QComboBox *m_predefinedCombo; + QSpinBox *m_dpiXSpinBox; + QSpinBox *m_dpiYSpinBox; +}; +} + +QT_END_NAMESPACE + +#endif // DPICHOOSER_H diff --git a/src/designer/src/components/formeditor/embeddedoptionspage.cpp b/src/designer/src/components/formeditor/embeddedoptionspage.cpp new file mode 100644 index 000000000..10f4509df --- /dev/null +++ b/src/designer/src/components/formeditor/embeddedoptionspage.cpp @@ -0,0 +1,453 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "embeddedoptionspage.h" +#include "deviceprofiledialog.h" +#include "widgetfactory_p.h" +#include "formwindowmanager.h" + +#include +#include +#include +#include +#include + + +// SDK +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +typedef QList DeviceProfileList; + +enum { profileComboIndexOffset = 1 }; + +// Sort by name. Used by template, do not make it static! +bool deviceProfileLessThan(const DeviceProfile &d1, const DeviceProfile &d2) +{ + return d1.name().toLower() < d2.name().toLower(); +} + +static bool ask(QWidget *parent, + QDesignerDialogGuiInterface *dlgui, + const QString &title, + const QString &what) +{ + return dlgui->message(parent, QDesignerDialogGuiInterface::OtherMessage, + QMessageBox::Question, title, what, + QMessageBox::Yes|QMessageBox::No, QMessageBox::No) == QMessageBox::Yes; +} + +// ------------ EmbeddedOptionsControlPrivate +class EmbeddedOptionsControlPrivate { + Q_DISABLE_COPY(EmbeddedOptionsControlPrivate) +public: + EmbeddedOptionsControlPrivate(QDesignerFormEditorInterface *core); + void init(EmbeddedOptionsControl *q); + + bool isDirty() const { return m_dirty; } + + void loadSettings(); + void saveSettings(); + void slotAdd(); + void slotEdit(); + void slotDelete(); + void slotProfileIndexChanged(int); + +private: + QStringList existingProfileNames() const; + void sortAndPopulateProfileCombo(); + void updateState(); + void updateDescriptionLabel(); + + QDesignerFormEditorInterface *m_core; + QComboBox *m_profileCombo; + QToolButton *m_addButton; + QToolButton *m_editButton; + QToolButton *m_deleteButton; + QLabel *m_descriptionLabel; + + DeviceProfileList m_sortedProfiles; + EmbeddedOptionsControl *m_q; + bool m_dirty; + QSet m_usedProfiles; +}; + +EmbeddedOptionsControlPrivate::EmbeddedOptionsControlPrivate(QDesignerFormEditorInterface *core) : + m_core(core), + m_profileCombo(new QComboBox), + m_addButton(new QToolButton), + m_editButton(new QToolButton), + m_deleteButton(new QToolButton), + m_descriptionLabel(new QLabel), + m_q(0), + m_dirty(false) +{ + m_descriptionLabel->setMinimumHeight(80); + // Determine used profiles to lock them + const QDesignerFormWindowManagerInterface *fwm = core->formWindowManager(); + if (const int fwCount = fwm->formWindowCount()) { + for (int i = 0; i < fwCount; i++) + if (const FormWindowBase *fwb = qobject_cast(fwm->formWindow(i))) { + const QString deviceProfileName = fwb->deviceProfileName(); + if (!deviceProfileName.isEmpty()) + m_usedProfiles.insert(deviceProfileName); + } + } +} + +void EmbeddedOptionsControlPrivate::init(EmbeddedOptionsControl *q) +{ + m_q = q; + QVBoxLayout *vLayout = new QVBoxLayout; + QHBoxLayout *hLayout = new QHBoxLayout; + m_profileCombo->setMinimumWidth(200); + m_profileCombo->setEditable(false); + hLayout->addWidget(m_profileCombo); + m_profileCombo->addItem(EmbeddedOptionsControl::tr("None")); + EmbeddedOptionsControl::connect(m_profileCombo, SIGNAL(currentIndexChanged(int)), m_q, SLOT(slotProfileIndexChanged(int))); + + m_addButton->setIcon(createIconSet(QString::fromUtf8("plus.png"))); + m_addButton->setToolTip(EmbeddedOptionsControl::tr("Add a profile")); + EmbeddedOptionsControl::connect(m_addButton, SIGNAL(clicked()), m_q, SLOT(slotAdd())); + hLayout->addWidget(m_addButton); + + EmbeddedOptionsControl::connect(m_editButton, SIGNAL(clicked()), m_q, SLOT(slotEdit())); + m_editButton->setIcon(createIconSet(QString::fromUtf8("edit.png"))); + m_editButton->setToolTip(EmbeddedOptionsControl::tr("Edit the selected profile")); + hLayout->addWidget(m_editButton); + + m_deleteButton->setIcon(createIconSet(QString::fromUtf8("minus.png"))); + m_deleteButton->setToolTip(EmbeddedOptionsControl::tr("Delete the selected profile")); + EmbeddedOptionsControl::connect(m_deleteButton, SIGNAL(clicked()), m_q, SLOT(slotDelete())); + hLayout->addWidget(m_deleteButton); + + hLayout->addStretch(); + vLayout->addLayout(hLayout); + vLayout->addWidget(m_descriptionLabel); + m_q->setLayout(vLayout); +} + +QStringList EmbeddedOptionsControlPrivate::existingProfileNames() const +{ + QStringList rc; + const DeviceProfileList::const_iterator dcend = m_sortedProfiles.constEnd(); + for (DeviceProfileList::const_iterator it = m_sortedProfiles.constBegin(); it != dcend; ++it) + rc.push_back(it->name()); + return rc; +} + +void EmbeddedOptionsControlPrivate::slotAdd() +{ + DeviceProfileDialog dlg(m_core->dialogGui(), m_q); + dlg.setWindowTitle(EmbeddedOptionsControl::tr("Add Profile")); + // Create a new profile with a new, unique name + DeviceProfile settings; + settings.fromSystem(); + dlg.setDeviceProfile(settings); + + const QStringList names = existingProfileNames(); + const QString newNamePrefix = EmbeddedOptionsControl::tr("New profile"); + QString newName = newNamePrefix; + for (int i = 2; names.contains(newName); i++) { + newName = newNamePrefix; + newName += QString::number(i); + } + + settings.setName(newName); + dlg.setDeviceProfile(settings); + if (dlg.showDialog(names)) { + const DeviceProfile newProfile = dlg.deviceProfile(); + m_sortedProfiles.push_back(newProfile); + // Maintain sorted order + sortAndPopulateProfileCombo(); + const int index = m_profileCombo->findText(newProfile.name()); + m_profileCombo->setCurrentIndex(index); + m_dirty = true; + } +} + +void EmbeddedOptionsControlPrivate::slotEdit() +{ + const int index = m_profileCombo->currentIndex() - profileComboIndexOffset; + if (index < 0) + return; + + // Edit the profile, compile a list of existing names + // excluding current one. re-insert if changed, + // re-sort if name changed. + const DeviceProfile oldProfile = m_sortedProfiles.at(index); + const QString oldName = oldProfile.name(); + QStringList names = existingProfileNames(); + names.removeAll(oldName); + + DeviceProfileDialog dlg(m_core->dialogGui(), m_q); + dlg.setWindowTitle(EmbeddedOptionsControl::tr("Edit Profile")); + dlg.setDeviceProfile(oldProfile); + if (dlg.showDialog(names)) { + const DeviceProfile newProfile = dlg.deviceProfile(); + if (newProfile != oldProfile) { + m_dirty = true; + m_sortedProfiles[index] = newProfile; + if (newProfile.name() != oldName) { + sortAndPopulateProfileCombo(); + const int index = m_profileCombo->findText(newProfile.name()); + m_profileCombo->setCurrentIndex(index); + } else { + updateDescriptionLabel(); + } + + } + } +} + +void EmbeddedOptionsControlPrivate::slotDelete() +{ + const int index = m_profileCombo->currentIndex() - profileComboIndexOffset; + if (index < 0) + return; + const QString name = m_sortedProfiles.at(index).name(); + if (ask(m_q, m_core->dialogGui(), + EmbeddedOptionsControl::tr("Delete Profile"), + EmbeddedOptionsControl::tr("Would you like to delete the profile '%1'?").arg(name))) { + m_profileCombo->setCurrentIndex(0); + m_sortedProfiles.removeAt(index); + m_profileCombo->removeItem(index + profileComboIndexOffset); + m_dirty = true; + } +} + +void EmbeddedOptionsControlPrivate::sortAndPopulateProfileCombo() +{ + // Clear items until only "None" is left + for (int i = m_profileCombo->count() - 1; i > 0; i--) + m_profileCombo->removeItem(i); + if (!m_sortedProfiles.empty()) { + qSort(m_sortedProfiles.begin(), m_sortedProfiles.end(), deviceProfileLessThan); + m_profileCombo->addItems(existingProfileNames()); + } +} + +void EmbeddedOptionsControlPrivate::loadSettings() +{ + const QDesignerSharedSettings settings(m_core); + m_sortedProfiles = settings.deviceProfiles(); + sortAndPopulateProfileCombo(); + // Index: 0 is "None" + const int settingsIndex = settings.currentDeviceProfileIndex(); + const int profileIndex = settingsIndex >= 0 && settingsIndex < m_sortedProfiles.size() ? settingsIndex + profileComboIndexOffset : 0; + m_profileCombo->setCurrentIndex(profileIndex); + updateState(); + m_dirty = false; +} + +void EmbeddedOptionsControlPrivate::saveSettings() +{ + QDesignerSharedSettings settings(m_core); + settings.setDeviceProfiles(m_sortedProfiles); + // Index: 0 is "None" + settings.setCurrentDeviceProfileIndex(m_profileCombo->currentIndex() - profileComboIndexOffset); + m_dirty = false; +} + +//: Format embedded device profile description +static const char *descriptionFormat = QT_TRANSLATE_NOOP("EmbeddedOptionsControl", +"" +"" +"" +"" +"" +"
Font%1, %2
Style%3
Resolution%4 x %5
" +""); + +static inline QString description(const DeviceProfile& p) +{ + QString styleName = p.style(); + if (styleName.isEmpty()) + styleName = EmbeddedOptionsControl::tr("Default"); + return EmbeddedOptionsControl::tr(descriptionFormat). + arg(p.fontFamily()).arg(p.fontPointSize()).arg(styleName).arg(p.dpiX()).arg(p.dpiY()); +} + +void EmbeddedOptionsControlPrivate::updateDescriptionLabel() +{ + const int profileIndex = m_profileCombo->currentIndex() - profileComboIndexOffset; + if (profileIndex >= 0) { + m_descriptionLabel->setText(description(m_sortedProfiles.at(profileIndex))); + } else { + m_descriptionLabel->clear(); + } +} + +void EmbeddedOptionsControlPrivate::updateState() +{ + const int profileIndex = m_profileCombo->currentIndex() - profileComboIndexOffset; + // Allow for changing/deleting only if it is not in use + bool modifyEnabled = false; + if (profileIndex >= 0) + modifyEnabled = !m_usedProfiles.contains(m_sortedProfiles.at(profileIndex).name()); + m_editButton->setEnabled(modifyEnabled); + m_deleteButton->setEnabled(modifyEnabled); + updateDescriptionLabel(); +} + +void EmbeddedOptionsControlPrivate::slotProfileIndexChanged(int) +{ + updateState(); + m_dirty = true; +} + +// ------------- EmbeddedOptionsControl +EmbeddedOptionsControl::EmbeddedOptionsControl(QDesignerFormEditorInterface *core, QWidget *parent) : + QWidget(parent), + m_d(new EmbeddedOptionsControlPrivate(core)) +{ + m_d->init(this); +} + +EmbeddedOptionsControl::~EmbeddedOptionsControl() +{ + delete m_d; +} + +void EmbeddedOptionsControl::slotAdd() +{ + m_d->slotAdd(); +} + +void EmbeddedOptionsControl::slotEdit() +{ + m_d->slotEdit(); +} + +void EmbeddedOptionsControl::slotDelete() +{ + m_d->slotDelete(); +} + +void EmbeddedOptionsControl::loadSettings() +{ + m_d->loadSettings(); +} + +void EmbeddedOptionsControl::saveSettings() +{ + m_d->saveSettings(); +} + +void EmbeddedOptionsControl::slotProfileIndexChanged(int i) +{ + m_d->slotProfileIndexChanged(i); +} + +bool EmbeddedOptionsControl::isDirty() const +{ + return m_d->isDirty(); +} + +// EmbeddedOptionsPage: +EmbeddedOptionsPage::EmbeddedOptionsPage(QDesignerFormEditorInterface *core) : + m_core(core) +{ +} + +QString EmbeddedOptionsPage::name() const +{ + //: Tab in preferences dialog + return QCoreApplication::translate("EmbeddedOptionsPage", "Embedded Design"); +} + +QWidget *EmbeddedOptionsPage::createPage(QWidget *parent) +{ + QWidget *optionsWidget = new QWidget(parent); + + QVBoxLayout *optionsVLayout = new QVBoxLayout(); + + //: EmbeddedOptionsControl group box" + QGroupBox *gb = new QGroupBox(QCoreApplication::translate("EmbeddedOptionsPage", "Device Profiles")); + QVBoxLayout *gbVLayout = new QVBoxLayout(); + m_embeddedOptionsControl = new EmbeddedOptionsControl(m_core); + m_embeddedOptionsControl->loadSettings(); + gbVLayout->addWidget(m_embeddedOptionsControl); + gb->setLayout(gbVLayout); + optionsVLayout->addWidget(gb); + + optionsVLayout->addStretch(1); + + // Outer layout to give it horizontal stretch + QHBoxLayout *optionsHLayout = new QHBoxLayout(); + optionsHLayout->addLayout(optionsVLayout); + optionsHLayout->addStretch(1); + optionsWidget->setLayout(optionsHLayout); + return optionsWidget; +} + +void EmbeddedOptionsPage::apply() +{ + if (!m_embeddedOptionsControl || !m_embeddedOptionsControl->isDirty()) + return; + + m_embeddedOptionsControl->saveSettings(); + if (FormWindowManager *fw = qobject_cast(m_core->formWindowManager())) + fw->deviceProfilesChanged(); +} + +void EmbeddedOptionsPage::finish() +{ +} +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/embeddedoptionspage.h b/src/designer/src/components/formeditor/embeddedoptionspage.h new file mode 100644 index 000000000..7947c3790 --- /dev/null +++ b/src/designer/src/components/formeditor/embeddedoptionspage.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef EMBEDDEDOPTIONSPAGE_H +#define EMBEDDEDOPTIONSPAGE_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +class EmbeddedOptionsControlPrivate; + +/* EmbeddedOptions Control. Presents the user with a list of embedded + * device profiles he can modify/add/delete. */ +class EmbeddedOptionsControl : public QWidget { + Q_DISABLE_COPY(EmbeddedOptionsControl) + Q_OBJECT +public: + explicit EmbeddedOptionsControl(QDesignerFormEditorInterface *core, QWidget *parent = 0); + ~EmbeddedOptionsControl(); + + bool isDirty() const; + +public slots: + void loadSettings(); + void saveSettings(); + +private slots: + void slotAdd(); + void slotEdit(); + void slotDelete(); + void slotProfileIndexChanged(int); + +private: + EmbeddedOptionsControlPrivate *m_d; +}; + +// EmbeddedOptionsPage +class EmbeddedOptionsPage : public QDesignerOptionsPageInterface +{ + Q_DISABLE_COPY(EmbeddedOptionsPage) +public: + explicit EmbeddedOptionsPage(QDesignerFormEditorInterface *core); + + QString name() const; + QWidget *createPage(QWidget *parent); + virtual void finish(); + virtual void apply(); + +private: + QDesignerFormEditorInterface *m_core; + QPointer m_embeddedOptionsControl; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // EMBEDDEDOPTIONSPAGE_H diff --git a/src/designer/src/components/formeditor/formeditor.cpp b/src/designer/src/components/formeditor/formeditor.cpp new file mode 100644 index 000000000..847b99de3 --- /dev/null +++ b/src/designer/src/components/formeditor/formeditor.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "formeditor.h" +#include "formeditor_optionspage.h" +#include "embeddedoptionspage.h" +#include "templateoptionspage.h" +#include "metadatabase_p.h" +#include "widgetdatabase_p.h" +#include "widgetfactory_p.h" +#include "formwindowmanager.h" +#include "qmainwindow_container.h" +#include "qworkspace_container.h" +#include "qmdiarea_container.h" +#include "qwizard_container.h" +#include "default_container.h" +#include "default_layoutdecoration.h" +#include "default_actionprovider.h" +#include "qlayoutwidget_propertysheet.h" +#include "spacer_propertysheet.h" +#include "line_propertysheet.h" +#include "layout_propertysheet.h" +#include "qdesigner_stackedbox_p.h" +#include "qdesigner_toolbox_p.h" +#include "qdesigner_tabwidget_p.h" +#include "qtbrushmanager.h" +#include "brushmanagerproxy.h" +#include "iconcache.h" +#include "qtresourcemodel_p.h" +#include "qdesigner_integration_p.h" +#include "itemview_propertysheet.h" + +// sdk +#include + +// shared +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +FormEditor::FormEditor(QObject *parent) + : QDesignerFormEditorInterface(parent) +{ + setIntrospection(new QDesignerIntrospection); + setDialogGui(new DialogGui); + QDesignerPluginManager *pluginManager = new QDesignerPluginManager(this); + setPluginManager(pluginManager); + + WidgetDataBase *widgetDatabase = new WidgetDataBase(this, this); + setWidgetDataBase(widgetDatabase); + + MetaDataBase *metaDataBase = new MetaDataBase(this, this); + setMetaDataBase(metaDataBase); + + WidgetFactory *widgetFactory = new WidgetFactory(this, this); + setWidgetFactory(widgetFactory); + + FormWindowManager *formWindowManager = new FormWindowManager(this, this); + setFormManager(formWindowManager); + connect(formWindowManager, SIGNAL(formWindowAdded(QDesignerFormWindowInterface*)), widgetFactory, SLOT(formWindowAdded(QDesignerFormWindowInterface*))); + connect(formWindowManager, SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)), widgetFactory, SLOT(activeFormWindowChanged(QDesignerFormWindowInterface*))); + + QExtensionManager *mgr = new QExtensionManager(this); + const QString containerExtensionId = Q_TYPEID(QDesignerContainerExtension); + + QDesignerStackedWidgetContainerFactory::registerExtension(mgr, containerExtensionId); + QDesignerTabWidgetContainerFactory::registerExtension(mgr, containerExtensionId); + QDesignerToolBoxContainerFactory::registerExtension(mgr, containerExtensionId); + QMainWindowContainerFactory::registerExtension(mgr, containerExtensionId); + QDockWidgetContainerFactory::registerExtension(mgr, containerExtensionId); + QScrollAreaContainerFactory::registerExtension(mgr, containerExtensionId); + QWorkspaceContainerFactory::registerExtension(mgr, containerExtensionId); + QMdiAreaContainerFactory::registerExtension(mgr, containerExtensionId); + QWizardContainerFactory::registerExtension(mgr, containerExtensionId); + + mgr->registerExtensions(new QDesignerLayoutDecorationFactory(mgr), + Q_TYPEID(QDesignerLayoutDecorationExtension)); + + const QString actionProviderExtensionId = Q_TYPEID(QDesignerActionProviderExtension); + QToolBarActionProviderFactory::registerExtension(mgr, actionProviderExtensionId); + QMenuBarActionProviderFactory::registerExtension(mgr, actionProviderExtensionId); + QMenuActionProviderFactory::registerExtension(mgr, actionProviderExtensionId); + + QDesignerDefaultPropertySheetFactory::registerExtension(mgr); + QLayoutWidgetPropertySheetFactory::registerExtension(mgr); + SpacerPropertySheetFactory::registerExtension(mgr); + LinePropertySheetFactory::registerExtension(mgr); + LayoutPropertySheetFactory::registerExtension(mgr); + QStackedWidgetPropertySheetFactory::registerExtension(mgr); + QToolBoxWidgetPropertySheetFactory::registerExtension(mgr); + QTabWidgetPropertySheetFactory::registerExtension(mgr); + QMdiAreaPropertySheetFactory::registerExtension(mgr); + QWorkspacePropertySheetFactory::registerExtension(mgr); + QWizardPagePropertySheetFactory::registerExtension(mgr); + QWizardPropertySheetFactory::registerExtension(mgr); + + QTreeViewPropertySheetFactory::registerExtension(mgr); + QTableViewPropertySheetFactory::registerExtension(mgr); + + const QString internalTaskMenuId = QLatin1String("QDesignerInternalTaskMenuExtension"); + QDesignerTaskMenuFactory::registerExtension(mgr, internalTaskMenuId); + + mgr->registerExtensions(new QDesignerMemberSheetFactory(mgr), + Q_TYPEID(QDesignerMemberSheetExtension)); + + setExtensionManager(mgr); + + setIconCache(new IconCache(this)); + + QtBrushManager *brushManager = new QtBrushManager(this); + setBrushManager(brushManager); + + BrushManagerProxy *brushProxy = new BrushManagerProxy(this, this); + brushProxy->setBrushManager(brushManager); + setPromotion(new QDesignerPromotion(this)); + + QtResourceModel *resourceModel = new QtResourceModel(this); + setResourceModel(resourceModel); + connect(resourceModel, SIGNAL(qrcFileModifiedExternally(QString)), + this, SLOT(slotQrcFileChangedExternally(QString))); + + QList optionsPages; + optionsPages << new TemplateOptionsPage(this) << new FormEditorOptionsPage(this) << new EmbeddedOptionsPage(this); + setOptionsPages(optionsPages); + + setSettingsManager(new QDesignerQSettings()); +} + +FormEditor::~FormEditor() +{ +} + +void FormEditor::slotQrcFileChangedExternally(const QString &path) +{ + QDesignerIntegration *designerIntegration = qobject_cast(integration()); + if (!designerIntegration) + return; + + QDesignerIntegration::ResourceFileWatcherBehaviour behaviour = designerIntegration->resourceFileWatcherBehaviour(); + if (behaviour == QDesignerIntegration::NoWatcher) { + return; + } else if (behaviour == QDesignerIntegration::PromptAndReload) { + QMessageBox::StandardButton button = dialogGui()->message(topLevel(), QDesignerDialogGuiInterface::FileChangedMessage, QMessageBox::Warning, + tr("Resource File Changed"), + tr("The file \"%1\" has changed outside Designer. Do you want to reload it?").arg(path), + QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); + + if (button != QMessageBox::Yes) + return; + } + + resourceModel()->reload(path); +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/formeditor.h b/src/designer/src/components/formeditor/formeditor.h new file mode 100644 index 000000000..88c24b84e --- /dev/null +++ b/src/designer/src/components/formeditor/formeditor.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FORMEDITOR_H +#define FORMEDITOR_H + +#include "formeditor_global.h" + +#include + +QT_BEGIN_NAMESPACE + +class QObject; + +namespace qdesigner_internal { + +class QT_FORMEDITOR_EXPORT FormEditor: public QDesignerFormEditorInterface +{ + Q_OBJECT +public: + FormEditor(QObject *parent = 0); + virtual ~FormEditor(); +public slots: + void slotQrcFileChangedExternally(const QString &path); +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // FORMEDITOR_H diff --git a/src/designer/src/components/formeditor/formeditor.pri b/src/designer/src/components/formeditor/formeditor.pri new file mode 100644 index 000000000..b1a93188a --- /dev/null +++ b/src/designer/src/components/formeditor/formeditor.pri @@ -0,0 +1,77 @@ + +QT += xml + +INCLUDEPATH += $$PWD + +FORMS += $$PWD/deviceprofiledialog.ui \ + $$PWD/formwindowsettings.ui \ + $$PWD/templateoptionspage.ui + +HEADERS += $$PWD/qdesigner_resource.h \ + $$PWD/qdesignerundostack.h \ + $$PWD/formwindow.h \ + $$PWD/formwindow_widgetstack.h \ + $$PWD/formwindow_dnditem.h \ + $$PWD/formwindowcursor.h \ + $$PWD/widgetselection.h \ + $$PWD/formwindowmanager.h \ + $$PWD/formeditor.h \ + $$PWD/formeditor_global.h \ + $$PWD/qlayoutwidget_propertysheet.h \ + $$PWD/layout_propertysheet.h \ + $$PWD/spacer_propertysheet.h \ + $$PWD/line_propertysheet.h \ + $$PWD/default_container.h \ + $$PWD/default_actionprovider.h \ + $$PWD/qmainwindow_container.h \ + $$PWD/qworkspace_container.h \ + $$PWD/qmdiarea_container.h \ + $$PWD/qwizard_container.h \ + $$PWD/default_layoutdecoration.h \ + $$PWD/qtbrushmanager.h \ + $$PWD/brushmanagerproxy.h \ + $$PWD/iconcache.h \ + $$PWD/tool_widgeteditor.h \ + $$PWD/formeditor_optionspage.h \ + $$PWD/embeddedoptionspage.h \ + $$PWD/formwindowsettings.h \ + $$PWD/deviceprofiledialog.h \ + $$PWD/dpi_chooser.h \ + $$PWD/previewactiongroup.h \ + $$PWD/itemview_propertysheet.h \ + $$PWD/templateoptionspage.h + +SOURCES += $$PWD/qdesigner_resource.cpp \ + $$PWD/qdesignerundostack.cpp \ + $$PWD/formwindow.cpp \ + $$PWD/formwindow_widgetstack.cpp \ + $$PWD/formwindow_dnditem.cpp \ + $$PWD/formwindowcursor.cpp \ + $$PWD/widgetselection.cpp \ + $$PWD/formwindowmanager.cpp \ + $$PWD/formeditor.cpp \ + $$PWD/qlayoutwidget_propertysheet.cpp \ + $$PWD/layout_propertysheet.cpp \ + $$PWD/spacer_propertysheet.cpp \ + $$PWD/line_propertysheet.cpp \ + $$PWD/qmainwindow_container.cpp \ + $$PWD/qworkspace_container.cpp \ + $$PWD/qmdiarea_container.cpp \ + $$PWD/qwizard_container.cpp \ + $$PWD/default_container.cpp \ + $$PWD/default_layoutdecoration.cpp \ + $$PWD/default_actionprovider.cpp \ + $$PWD/tool_widgeteditor.cpp \ + $$PWD/qtbrushmanager.cpp \ + $$PWD/brushmanagerproxy.cpp \ + $$PWD/iconcache.cpp \ + $$PWD/formeditor_optionspage.cpp \ + $$PWD/embeddedoptionspage.cpp \ + $$PWD/formwindowsettings.cpp \ + $$PWD/deviceprofiledialog.cpp \ + $$PWD/dpi_chooser.cpp \ + $$PWD/previewactiongroup.cpp \ + $$PWD/itemview_propertysheet.cpp \ + $$PWD/templateoptionspage.cpp + +RESOURCES += $$PWD/formeditor.qrc diff --git a/src/designer/src/components/formeditor/formeditor.qrc b/src/designer/src/components/formeditor/formeditor.qrc new file mode 100644 index 000000000..e42cc66ec --- /dev/null +++ b/src/designer/src/components/formeditor/formeditor.qrc @@ -0,0 +1,175 @@ + + + images/submenu.png + images/cursors/arrow.png + images/cursors/busy.png + images/cursors/closedhand.png + images/cursors/cross.png + images/cursors/hand.png + images/cursors/hsplit.png + images/cursors/ibeam.png + images/cursors/no.png + images/cursors/openhand.png + images/cursors/sizeall.png + images/cursors/sizeb.png + images/cursors/sizef.png + images/cursors/sizeh.png + images/cursors/sizev.png + images/cursors/uparrow.png + images/cursors/vsplit.png + images/cursors/wait.png + images/cursors/whatsthis.png + images/emptyicon.png + images/filenew-16.png + images/fileopen-16.png + images/editdelete-16.png + images/plus-16.png + images/minus-16.png + images/prefix-add.png + images/downplus.png + images/leveldown.png + images/levelup.png + images/mac/adjustsize.png + images/mac/widgettool.png + images/mac/signalslottool.png + images/mac/tabordertool.png + images/mac/buddytool.png + images/mac/editbreaklayout.png + images/mac/editcopy.png + images/mac/editcut.png + images/mac/editdelete.png + images/mac/editgrid.png + images/mac/editform.png + images/mac/edithlayout.png + images/mac/edithlayoutsplit.png + images/mac/editlower.png + images/mac/editpaste.png + images/mac/editraise.png + images/mac/editvlayout.png + images/mac/editvlayoutsplit.png + images/mac/filenew.png + images/mac/insertimage.png + images/mac/undo.png + images/mac/redo.png + images/mac/fileopen.png + images/mac/filesave.png + images/mac/resourceeditortool.png + images/mac/plus.png + images/mac/minus.png + images/mac/back.png + images/mac/forward.png + images/mac/down.png + images/mac/up.png + images/qtlogo.png + images/qt3logo.png + images/resetproperty.png + images/cleartext.png + images/sort.png + images/edit.png + images/reload.png + images/configure.png + images/color.png + images/dropdownbutton.png + images/widgets/calendarwidget.png + images/widgets/checkbox.png + images/widgets/columnview.png + images/widgets/combobox.png + images/widgets/commandlinkbutton.png + images/widgets/dateedit.png + images/widgets/datetimeedit.png + images/widgets/dial.png + images/widgets/dialogbuttonbox.png + images/widgets/dockwidget.png + images/widgets/doublespinbox.png + images/widgets/fontcombobox.png + images/widgets/frame.png + images/widgets/graphicsview.png + images/widgets/groupbox.png + images/widgets/hscrollbar.png + images/widgets/hslider.png + images/widgets/hsplit.png + images/widgets/label.png + images/widgets/lcdnumber.png + images/widgets/line.png + images/widgets/lineedit.png + images/widgets/listbox.png + images/widgets/listview.png + images/widgets/mdiarea.png + images/widgets/plaintextedit.png + images/widgets/progress.png + images/widgets/pushbutton.png + images/widgets/radiobutton.png + images/widgets/scrollarea.png + images/widgets/spacer.png + images/widgets/spinbox.png + images/widgets/table.png + images/widgets/tabwidget.png + images/widgets/textedit.png + images/widgets/timeedit.png + images/widgets/toolbox.png + images/widgets/toolbutton.png + images/widgets/vline.png + images/widgets/vscrollbar.png + images/widgets/vslider.png + images/widgets/vspacer.png + images/widgets/widget.png + images/widgets/widgetstack.png + images/widgets/wizard.png + images/win/adjustsize.png + images/win/widgettool.png + images/win/signalslottool.png + images/win/tabordertool.png + images/win/buddytool.png + images/win/editbreaklayout.png + images/win/editcopy.png + images/win/editcut.png + images/win/editdelete.png + images/win/editgrid.png + images/win/editform.png + images/win/edithlayout.png + images/win/edithlayoutsplit.png + images/win/editlower.png + images/win/editpaste.png + images/win/editraise.png + images/win/editvlayout.png + images/win/editvlayoutsplit.png + images/win/filenew.png + images/win/insertimage.png + images/win/undo.png + images/win/redo.png + images/win/fileopen.png + images/win/filesave.png + images/win/resourceeditortool.png + images/win/plus.png + images/win/minus.png + images/win/textanchor.png + images/win/textbold.png + images/win/textitalic.png + images/win/textunder.png + images/win/textleft.png + images/win/textcenter.png + images/win/textright.png + images/win/textjustify.png + images/win/textsuperscript.png + images/win/textsubscript.png + images/win/simplifyrichtext.png + images/win/back.png + images/win/forward.png + images/win/down.png + images/win/up.png + images/mac/textanchor.png + images/mac/textbold.png + images/mac/textitalic.png + images/mac/textunder.png + images/mac/textleft.png + images/mac/textcenter.png + images/mac/textright.png + images/mac/textjustify.png + images/mac/textsuperscript.png + images/mac/textsubscript.png + images/mac/simplifyrichtext.png + + + defaultbrushes.xml + + diff --git a/src/designer/src/components/formeditor/formeditor_global.h b/src/designer/src/components/formeditor/formeditor_global.h new file mode 100644 index 000000000..f5df69114 --- /dev/null +++ b/src/designer/src/components/formeditor/formeditor_global.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FORMEDITOR_GLOBAL_H +#define FORMEDITOR_GLOBAL_H + +#include + +#ifdef Q_OS_WIN +#ifdef QT_FORMEDITOR_LIBRARY +# define QT_FORMEDITOR_EXPORT +#else +# define QT_FORMEDITOR_EXPORT +#endif +#else +#define QT_FORMEDITOR_EXPORT +#endif + +#endif // FORMEDITOR_GLOBAL_H diff --git a/src/designer/src/components/formeditor/formeditor_optionspage.cpp b/src/designer/src/components/formeditor/formeditor_optionspage.cpp new file mode 100644 index 000000000..e50072aac --- /dev/null +++ b/src/designer/src/components/formeditor/formeditor_optionspage.cpp @@ -0,0 +1,191 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "formeditor_optionspage.h" + +// shared +#include "formwindowbase_p.h" +#include "gridpanel_p.h" +#include "grid_p.h" +#include "previewconfigurationwidget_p.h" +#include "shared_settings_p.h" +#include "zoomwidget_p.h" + +// SDK +#include +#include + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +typedef QList IntList; + +namespace qdesigner_internal { + +// Zoom, currently for preview only +class ZoomSettingsWidget : public QGroupBox { + Q_DISABLE_COPY(ZoomSettingsWidget) +public: + explicit ZoomSettingsWidget(QWidget *parent = 0); + + void fromSettings(const QDesignerSharedSettings &s); + void toSettings(QDesignerSharedSettings &s) const; + +private: + QComboBox *m_zoomCombo; +}; + +ZoomSettingsWidget::ZoomSettingsWidget(QWidget *parent) : + QGroupBox(parent), + m_zoomCombo(new QComboBox) +{ + m_zoomCombo->setEditable(false); + const IntList zoomValues = ZoomMenu::zoomValues(); + const IntList::const_iterator cend = zoomValues.constEnd(); + + for (IntList::const_iterator it = zoomValues.constBegin(); it != cend; ++it) { + //: Zoom percentage + m_zoomCombo->addItem(QCoreApplication::translate("FormEditorOptionsPage", "%1 %").arg(*it), QVariant(*it)); + } + + // Layout + setCheckable(true); + setTitle(QCoreApplication::translate("FormEditorOptionsPage", "Preview Zoom")); + QFormLayout *lt = new QFormLayout; + lt->addRow(QCoreApplication::translate("FormEditorOptionsPage", "Default Zoom"), m_zoomCombo); + setLayout(lt); +} + +void ZoomSettingsWidget::fromSettings(const QDesignerSharedSettings &s) +{ + setChecked(s.zoomEnabled()); + const int idx = m_zoomCombo->findData(QVariant(s.zoom())); + m_zoomCombo->setCurrentIndex(qMax(0, idx)); +} + +void ZoomSettingsWidget::toSettings(QDesignerSharedSettings &s) const +{ + s.setZoomEnabled(isChecked()); + const int zoom = m_zoomCombo->itemData(m_zoomCombo->currentIndex()).toInt(); + s.setZoom(zoom); +} + + + +// FormEditorOptionsPage: +FormEditorOptionsPage::FormEditorOptionsPage(QDesignerFormEditorInterface *core) + : m_core(core) +{ +} + +QString FormEditorOptionsPage::name() const +{ + //: Tab in preferences dialog + return QCoreApplication::translate("FormEditorOptionsPage", "Forms"); +} + +QWidget *FormEditorOptionsPage::createPage(QWidget *parent) +{ + QWidget *optionsWidget = new QWidget(parent); + + const QDesignerSharedSettings settings(m_core); + m_previewConf = new PreviewConfigurationWidget(m_core); + m_zoomSettingsWidget = new ZoomSettingsWidget; + m_zoomSettingsWidget->fromSettings(settings); + + m_defaultGridConf = new GridPanel(); + m_defaultGridConf->setTitle(QCoreApplication::translate("FormEditorOptionsPage", "Default Grid")); + m_defaultGridConf->setGrid(settings.defaultGrid()); + + QVBoxLayout *optionsVLayout = new QVBoxLayout(); + optionsVLayout->addWidget(m_defaultGridConf); + optionsVLayout->addWidget(m_previewConf); + optionsVLayout->addWidget(m_zoomSettingsWidget); + optionsVLayout->addStretch(1); + + // Outer layout to give it horizontal stretch + QHBoxLayout *optionsHLayout = new QHBoxLayout(); + optionsHLayout->addLayout(optionsVLayout); + optionsHLayout->addStretch(1); + optionsWidget->setLayout(optionsHLayout); + + return optionsWidget; +} + +void FormEditorOptionsPage::apply() +{ + QDesignerSharedSettings settings(m_core); + if (m_defaultGridConf) { + const Grid defaultGrid = m_defaultGridConf->grid(); + settings.setDefaultGrid(defaultGrid); + + FormWindowBase::setDefaultDesignerGrid(defaultGrid); + // Update grid settings in all existing form windows + QDesignerFormWindowManagerInterface *fwm = m_core->formWindowManager(); + if (const int numWindows = fwm->formWindowCount()) { + for (int i = 0; i < numWindows; i++) + if (qdesigner_internal::FormWindowBase *fwb + = qobject_cast( fwm->formWindow(i))) + if (!fwb->hasFormGrid()) + fwb->setDesignerGrid(defaultGrid); + } + } + if (m_previewConf) { + m_previewConf->saveState(); + } + + if (m_zoomSettingsWidget) + m_zoomSettingsWidget->toSettings(settings); +} + +void FormEditorOptionsPage::finish() +{ +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/formeditor_optionspage.h b/src/designer/src/components/formeditor/formeditor_optionspage.h new file mode 100644 index 000000000..d7d169be2 --- /dev/null +++ b/src/designer/src/components/formeditor/formeditor_optionspage.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FORMEDITOR_OPTIONSPAGE_H +#define FORMEDITOR_OPTIONSPAGE_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +class PreviewConfigurationWidget; +class GridPanel; +class ZoomSettingsWidget; + +class FormEditorOptionsPage : public QDesignerOptionsPageInterface +{ +public: + explicit FormEditorOptionsPage(QDesignerFormEditorInterface *core); + + QString name() const; + QWidget *createPage(QWidget *parent); + virtual void apply(); + virtual void finish(); + +private: + QDesignerFormEditorInterface *m_core; + QPointer m_previewConf; + QPointer m_defaultGridConf; + QPointer m_zoomSettingsWidget; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // FORMEDITOR_OPTIONSPAGE_H diff --git a/src/designer/src/components/formeditor/formwindow.cpp b/src/designer/src/components/formeditor/formwindow.cpp new file mode 100644 index 000000000..3fb18aa31 --- /dev/null +++ b/src/designer/src/components/formeditor/formwindow.cpp @@ -0,0 +1,2981 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "formwindow.h" +#include "formeditor.h" +#include "formwindow_dnditem.h" +#include "formwindow_widgetstack.h" +#include "formwindowcursor.h" +#include "formwindowmanager.h" +#include "tool_widgeteditor.h" +#include "widgetselection.h" +#include "qtresourcemodel_p.h" +#include "widgetfactory_p.h" + +// shared +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +Q_DECLARE_METATYPE(QWidget*) + +QT_BEGIN_NAMESPACE + +namespace { +class BlockSelection +{ +public: + BlockSelection(qdesigner_internal::FormWindow *fw) + : m_formWindow(fw), + m_blocked(m_formWindow->blockSelectionChanged(true)) + { + } + + ~BlockSelection() + { + if (m_formWindow) + m_formWindow->blockSelectionChanged(m_blocked); + } + +private: + QPointer m_formWindow; + const bool m_blocked; +}; + +enum { debugFormWindow = 0 }; +} + +namespace qdesigner_internal { + +// ------------------------ FormWindow::Selection +// Maintains a pool of WidgetSelections to be used for selected widgets. + +class FormWindow::Selection +{ +public: + Selection(); + ~Selection(); + + // Clear + void clear(); + + // Also clear out the pool. Call if reparenting of the main container occurs. + void clearSelectionPool(); + + void repaintSelection(QWidget *w); + void repaintSelection(); + + bool isWidgetSelected(QWidget *w) const; + QWidgetList selectedWidgets() const; + + WidgetSelection *addWidget(FormWindow* fw, QWidget *w); + // remove widget, return new current widget or 0 + QWidget* removeWidget(QWidget *w); + + void raiseList(const QWidgetList& l); + void raiseWidget(QWidget *w); + + void updateGeometry(QWidget *w); + + void hide(QWidget *w); + void show(QWidget *w); + +private: + + typedef QList SelectionPool; + SelectionPool m_selectionPool; + + typedef QHash SelectionHash; + SelectionHash m_usedSelections; +}; + +FormWindow::Selection::Selection() +{ +} + +FormWindow::Selection::~Selection() +{ + clearSelectionPool(); +} + +void FormWindow::Selection::clear() +{ + if (!m_usedSelections.empty()) { + const SelectionHash::iterator mend = m_usedSelections.end(); + for (SelectionHash::iterator it = m_usedSelections.begin(); it != mend; ++it) { + it.value()->setWidget(0); + } + m_usedSelections.clear(); + } +} + +void FormWindow::Selection::clearSelectionPool() +{ + clear(); + qDeleteAll(m_selectionPool); + m_selectionPool.clear(); +} + +WidgetSelection *FormWindow::Selection::addWidget(FormWindow* fw, QWidget *w) +{ + WidgetSelection *rc = m_usedSelections.value(w); + if (rc != 0) { + rc->show(); + rc->updateActive(); + return rc; + } + // find a free one in the pool + const SelectionPool::iterator pend = m_selectionPool.end(); + for (SelectionPool::iterator it = m_selectionPool.begin(); it != pend; ++it) { + if (! (*it)->isUsed()) { + rc = *it; + break; + } + } + + if (rc == 0) { + rc = new WidgetSelection(fw); + m_selectionPool.push_back(rc); + } + + m_usedSelections.insert(w, rc); + rc->setWidget(w); + return rc; +} + +QWidget* FormWindow::Selection::removeWidget(QWidget *w) +{ + WidgetSelection *s = m_usedSelections.value(w); + if (!s) + return w; + + s->setWidget(0); + m_usedSelections.remove(w); + + if (m_usedSelections.isEmpty()) + return 0; + + return (*m_usedSelections.begin())->widget(); +} + +void FormWindow::Selection::repaintSelection(QWidget *w) +{ + if (WidgetSelection *s = m_usedSelections.value(w)) + s->update(); +} + +void FormWindow::Selection::repaintSelection() +{ + const SelectionHash::iterator mend = m_usedSelections.end(); + for (SelectionHash::iterator it = m_usedSelections.begin(); it != mend; ++it) { + it.value()->update(); + } +} + +bool FormWindow::Selection::isWidgetSelected(QWidget *w) const{ + return m_usedSelections.contains(w); +} + +QWidgetList FormWindow::Selection::selectedWidgets() const +{ + return m_usedSelections.keys(); +} + +void FormWindow::Selection::raiseList(const QWidgetList& l) +{ + const SelectionHash::iterator mend = m_usedSelections.end(); + for (SelectionHash::iterator it = m_usedSelections.begin(); it != mend; ++it) { + WidgetSelection *w = it.value(); + if (l.contains(w->widget())) + w->show(); + } +} + +void FormWindow::Selection::raiseWidget(QWidget *w) +{ + if (WidgetSelection *s = m_usedSelections.value(w)) + s->show(); +} + +void FormWindow::Selection::updateGeometry(QWidget *w) +{ + if (WidgetSelection *s = m_usedSelections.value(w)) { + s->updateGeometry(); + } +} + +void FormWindow::Selection::hide(QWidget *w) +{ + if (WidgetSelection *s = m_usedSelections.value(w)) + s->hide(); +} + +void FormWindow::Selection::show(QWidget *w) +{ + if (WidgetSelection *s = m_usedSelections.value(w)) + s->show(); +} + +// ------------------------ FormWindow +FormWindow::FormWindow(FormEditor *core, QWidget *parent, Qt::WindowFlags flags) : + FormWindowBase(core, parent, flags), + m_mouseState(NoMouseState), + m_core(core), + m_selection(new Selection), + m_widgetStack(new FormWindowWidgetStack(this)), + m_contextMenuPosition(-1, -1) +{ + // Apply settings to formcontainer + deviceProfile().apply(core, m_widgetStack->formContainer(), qdesigner_internal::DeviceProfile::ApplyFormParent); + + setLayout(m_widgetStack->layout()); + init(); + + m_cursor = new FormWindowCursor(this, this); + + core->formWindowManager()->addFormWindow(this); + + setDirty(false); + setAcceptDrops(true); +} + +FormWindow::~FormWindow() +{ + Q_ASSERT(core() != 0); + Q_ASSERT(core()->metaDataBase() != 0); + Q_ASSERT(core()->formWindowManager() != 0); + + core()->formWindowManager()->removeFormWindow(this); + core()->metaDataBase()->remove(this); + + QWidgetList l = widgets(); + foreach (QWidget *w, l) + core()->metaDataBase()->remove(w); + + m_widgetStack = 0; + m_rubberBand = 0; + if (resourceSet()) + core()->resourceModel()->removeResourceSet(resourceSet()); + delete m_selection; +} + +QDesignerFormEditorInterface *FormWindow::core() const +{ + return m_core; +} + +QDesignerFormWindowCursorInterface *FormWindow::cursor() const +{ + return m_cursor; +} + +void FormWindow::updateWidgets() +{ + if (!m_mainContainer) + return; +} + +int FormWindow::widgetDepth(const QWidget *w) +{ + int d = -1; + while (w && !w->isWindow()) { + d++; + w = w->parentWidget(); + } + + return d; +} + +bool FormWindow::isChildOf(const QWidget *c, const QWidget *p) +{ + while (c) { + if (c == p) + return true; + c = c->parentWidget(); + } + return false; +} + +void FormWindow::setCursorToAll(const QCursor &c, QWidget *start) +{ +#ifndef QT_NO_CURSOR + start->setCursor(c); + const QWidgetList widgets = start->findChildren(); + foreach (QWidget *widget, widgets) { + if (!qobject_cast(widget)) { + widget->setCursor(c); + } + } +#endif +} + +void FormWindow::init() +{ + if (FormWindowManager *manager = qobject_cast (core()->formWindowManager())) { + manager->undoGroup()->addStack(m_undoStack.qundoStack()); + } + + m_blockSelectionChanged = false; + + m_defaultMargin = INT_MIN; + m_defaultSpacing = INT_MIN; + + connect(m_widgetStack, SIGNAL(currentToolChanged(int)), this, SIGNAL(toolChanged(int))); + + m_selectionChangedTimer = new QTimer(this); + m_selectionChangedTimer->setSingleShot(true); + connect(m_selectionChangedTimer, SIGNAL(timeout()), this, SLOT(selectionChangedTimerDone())); + + m_checkSelectionTimer = new QTimer(this); + m_checkSelectionTimer->setSingleShot(true); + connect(m_checkSelectionTimer, SIGNAL(timeout()), this, SLOT(checkSelectionNow())); + + m_geometryChangedTimer = new QTimer(this); + m_geometryChangedTimer->setSingleShot(true); + connect(m_geometryChangedTimer, SIGNAL(timeout()), this, SIGNAL(geometryChanged())); + + m_rubberBand = 0; + + setFocusPolicy(Qt::StrongFocus); + + m_mainContainer = 0; + m_currentWidget = 0; + + connect(&m_undoStack, SIGNAL(changed()), this, SIGNAL(changed())); + connect(&m_undoStack, SIGNAL(changed()), this, SLOT(checkSelection())); + + core()->metaDataBase()->add(this); + + initializeCoreTools(); + + QAction *a = new QAction(this); + a->setText(tr("Edit contents")); + a->setShortcut(tr("F2")); + connect(a, SIGNAL(triggered()), this, SLOT(editContents())); + addAction(a); +} + +QWidget *FormWindow::mainContainer() const +{ + return m_mainContainer; +} + + +void FormWindow::clearMainContainer() +{ + if (m_mainContainer) { + setCurrentTool(0); + m_widgetStack->setMainContainer(0); + core()->metaDataBase()->remove(m_mainContainer); + unmanageWidget(m_mainContainer); + delete m_mainContainer; + m_mainContainer = 0; + } +} + +void FormWindow::setMainContainer(QWidget *w) +{ + if (w == m_mainContainer) { + // nothing to do + return; + } + + clearMainContainer(); + + m_mainContainer = w; + const QSize sz = m_mainContainer->size(); + + m_widgetStack->setMainContainer(m_mainContainer); + m_widgetStack->setCurrentTool(m_widgetEditor); + + setCurrentWidget(m_mainContainer); + manageWidget(m_mainContainer); + + if (QDesignerPropertySheetExtension *sheet = qt_extension(core()->extensionManager(), m_mainContainer)) { + sheet->setVisible(sheet->indexOf(QLatin1String("windowTitle")), true); + sheet->setVisible(sheet->indexOf(QLatin1String("windowIcon")), true); + sheet->setVisible(sheet->indexOf(QLatin1String("windowModality")), true); + sheet->setVisible(sheet->indexOf(QLatin1String("windowOpacity")), true); + sheet->setVisible(sheet->indexOf(QLatin1String("windowFilePath")), true); + // ### generalize + } + + m_mainContainer->setFocusPolicy(Qt::StrongFocus); + m_mainContainer->resize(sz); + + emit mainContainerChanged(m_mainContainer); +} + +QWidget *FormWindow::findTargetContainer(QWidget *widget) const +{ + Q_ASSERT(widget); + + while (QWidget *parentWidget = widget->parentWidget()) { + if (LayoutInfo::layoutType(m_core, parentWidget) == LayoutInfo::NoLayout && isManaged(widget)) + return widget; + + widget = parentWidget; + } + + return mainContainer(); +} + +static inline void clearObjectInspectorSelection(const QDesignerFormEditorInterface *core) +{ + if (QDesignerObjectInspector *oi = qobject_cast(core->objectInspector())) + oi->clearSelection(); +} + +// Find a parent of a desired selection state +static QWidget *findSelectedParent(QDesignerFormWindowInterface *fw, const QWidget *w, bool selected) +{ + const QDesignerFormWindowCursorInterface *cursor = fw->cursor(); + QWidget *mainContainer = fw->mainContainer(); + for (QWidget *p = w->parentWidget(); p && p != mainContainer; p = p->parentWidget()) + if (fw->isManaged(p)) + if (cursor->isWidgetSelected(p) == selected) + return p; + return 0; +} + +// Mouse modifiers. + +enum MouseFlags { ToggleSelectionModifier = 0x1, CycleParentModifier=0x2, CopyDragModifier=0x4 }; + +static inline unsigned mouseFlags(Qt::KeyboardModifiers mod) +{ + switch (mod) { + case Qt::ShiftModifier: + return CycleParentModifier; + break; +#ifdef Q_WS_MAC + case Qt::AltModifier: // "Alt" or "option" key on Mac means copy + return CopyDragModifier; +#endif + case Qt::ControlModifier: + return CopyDragModifier|ToggleSelectionModifier; + break; + default: + break; + } + return 0; +} + +// Handle the click selection: Do toggling/cycling +// of parents according to the modifiers. +void FormWindow::handleClickSelection(QWidget *managedWidget, unsigned mouseMode) +{ + const bool sameWidget = managedWidget == m_lastClickedWidget; + m_lastClickedWidget = managedWidget; + + const bool selected = isWidgetSelected(managedWidget); + if (debugFormWindow) + qDebug() << "handleClickSelection" << managedWidget << " same=" << sameWidget << " mouse= " << mouseMode << " selected=" << selected; + + // // toggle selection state of widget + if (mouseMode & ToggleSelectionModifier) { + selectWidget(managedWidget, !selected); + return; + } + + QWidget *selectionCandidate = 0; + // Hierarchy cycling: If the same widget clicked again: Attempt to cycle + // trough the hierarchy. Find the next currently selected parent + if (sameWidget && (mouseMode & CycleParentModifier)) + if (QWidget *currentlySelectedParent = selected ? managedWidget : findSelectedParent(this, managedWidget, true)) + selectionCandidate = findSelectedParent(this, currentlySelectedParent, false); + // Not the same widget, list wrapped over or there was no unselected parent + if (!selectionCandidate && !selected) + selectionCandidate = managedWidget; + + if (selectionCandidate) + selectSingleWidget(selectionCandidate); +} + +void FormWindow::selectSingleWidget(QWidget *w) +{ + clearSelection(false); + selectWidget(w, true); + raiseChildSelections(w); +} + +bool FormWindow::handleMousePressEvent(QWidget * widget, QWidget *managedWidget, QMouseEvent *e) +{ + m_mouseState = NoMouseState; + m_startPos = QPoint(); + e->accept(); + + BlockSelection blocker(this); + + if (core()->formWindowManager()->activeFormWindow() != this) + core()->formWindowManager()->setActiveFormWindow(this); + + const Qt::MouseButtons buttons = e->buttons(); + if (buttons != Qt::LeftButton && buttons != Qt::MidButton) + return true; + + m_startPos = mapFromGlobal(e->globalPos()); + + if (debugFormWindow) + qDebug() << "handleMousePressEvent:" << widget << ',' << managedWidget; + + if (buttons == Qt::MidButton || isMainContainer(managedWidget) == true) { // press was on the formwindow + clearObjectInspectorSelection(m_core); // We might have a toolbar or non-widget selected in the object inspector. + clearSelection(false); + + m_mouseState = MouseDrawRubber; + m_currRect = QRect(); + startRectDraw(mapFromGlobal(e->globalPos()), this, Rubber); + return true; + } + if (buttons != Qt::LeftButton) + return true; + + const unsigned mouseMode = mouseFlags(e->modifiers()); + + /* Normally, we want to be able to click /select-on-press to drag away + * the widget in the next step. However, in the case of a widget which + * itself or whose parent is selected, we defer the selection to the + * release event. + * This is to prevent children from being dragged away from layouts + * when their layouts are selected and one wants to move the layout. + * Note that toggle selection is only deferred if the widget is already + * selected, so, it is still possible to just Ctrl+Click and CopyDrag. */ + const bool deferSelection = isWidgetSelected(managedWidget) || findSelectedParent(this, managedWidget, true); + if (deferSelection) { + m_mouseState = MouseDeferredSelection; + } else { + // Cycle the parent unless we explicitly want toggle + const unsigned effectiveMouseMode = (mouseMode & ToggleSelectionModifier) ? mouseMode : static_cast(CycleParentModifier); + handleClickSelection(managedWidget, effectiveMouseMode); + } + return true; +} + +// We can drag widget in managed layouts except splitter. +static bool canDragWidgetInLayout(const QDesignerFormEditorInterface *core, QWidget *w) +{ + bool managed; + const LayoutInfo::Type type = LayoutInfo::laidoutWidgetType(core ,w, &managed); + if (!managed) + return false; + switch (type) { + case LayoutInfo::NoLayout: + case LayoutInfo::HSplitter: + case LayoutInfo::VSplitter: + return false; + default: + break; + } + return true; +} + +bool FormWindow::handleMouseMoveEvent(QWidget *, QWidget *, QMouseEvent *e) +{ + e->accept(); + if (m_startPos.isNull()) + return true; + + const QPoint pos = mapFromGlobal(e->globalPos()); + + switch (m_mouseState) { + case MouseDrawRubber: // Rubber band with left/middle mouse + continueRectDraw(pos, this, Rubber); + return true; + case MouseMoveDrag: // Spurious move event after drag started? + return true; + default: + break; + } + + if (e->buttons() != Qt::LeftButton) + return true; + + const bool canStartDrag = (m_startPos - pos).manhattanLength() > QApplication::startDragDistance(); + + if (canStartDrag == false) { + // nothing to do + return true; + } + + m_mouseState = MouseMoveDrag; + const bool blocked = blockSelectionChanged(true); + + QWidgetList sel = selectedWidgets(); + simplifySelection(&sel); + + QSet widget_set; + + foreach (QWidget *child, sel) { // Move parent layout or container? + QWidget *current = child; + + bool done = false; + while (!isMainContainer(current) && !done) { + if (!isManaged(current)) { + current = current->parentWidget(); + continue; + } else if (LayoutInfo::isWidgetLaidout(core(), current)) { + // Go up to parent of layout if shift pressed, else do that only for splitters + if (!canDragWidgetInLayout(core(), current)) { + current = current->parentWidget(); + continue; + } + } + done = true; + } + + if (current == mainContainer()) + continue; + + widget_set.insert(current); + } + + sel = widget_set.toList(); + QDesignerFormWindowCursorInterface *c = cursor(); + QWidget *current = c->current(); + if (sel.contains(current)) { + sel.removeAll(current); + sel.prepend(current); + } + + QList item_list; + const QPoint globalPos = mapToGlobal(m_startPos); + const QDesignerDnDItemInterface::DropType dropType = (mouseFlags(e->modifiers()) & CopyDragModifier) ? + QDesignerDnDItemInterface::CopyDrop : QDesignerDnDItemInterface::MoveDrop; + foreach (QWidget *widget, sel) { + item_list.append(new FormWindowDnDItem(dropType, this, widget, globalPos)); + if (dropType == QDesignerDnDItemInterface::MoveDrop) { + m_selection->hide(widget); + widget->hide(); + } + } + + blockSelectionChanged(blocked); + + if (!sel.empty()) // reshow selection? + if (QDesignerMimeData::execDrag(item_list, core()->topLevel()) == Qt::IgnoreAction && dropType == QDesignerDnDItemInterface::MoveDrop) + foreach (QWidget *widget, sel) + m_selection->show(widget); + + m_startPos = QPoint(); + + return true; +} + +bool FormWindow::handleMouseReleaseEvent(QWidget *w, QWidget *mw, QMouseEvent *e) +{ + const MouseState oldState = m_mouseState; + m_mouseState = NoMouseState; + + if (debugFormWindow) + qDebug() << "handleMouseeleaseEvent:" << w << ',' << mw << "state=" << oldState; + + if (oldState == MouseDoubleClicked) + return true; + + e->accept(); + + switch (oldState) { + case MouseDrawRubber: { // we were drawing a rubber selection + endRectDraw(); // get rid of the rectangle + const bool blocked = blockSelectionChanged(true); + selectWidgets(); // select widgets which intersect the rect + blockSelectionChanged(blocked); + } + break; + // Deferred select: Select the child here unless the parent was moved. + case MouseDeferredSelection: + handleClickSelection(mw, mouseFlags(e->modifiers())); + break; + default: + break; + } + + m_startPos = QPoint(); + + /* Inform about selection changes (left/mid or context menu). Also triggers + * in the case of an empty rubber drag that cleared the selection in + * MousePressEvent. */ + switch (e->button()) { + case Qt::LeftButton: + case Qt::MidButton: + case Qt::RightButton: + emitSelectionChanged(); + break; + default: + break; + } + + return true; +} + +void FormWindow::checkPreviewGeometry(QRect &r) +{ + if (!rect().contains(r)) { + if (r.left() < rect().left()) + r.moveTopLeft(QPoint(0, r.top())); + if (r.right() > rect().right()) + r.moveBottomRight(QPoint(rect().right(), r.bottom())); + if (r.top() < rect().top()) + r.moveTopLeft(QPoint(r.left(), rect().top())); + if (r.bottom() > rect().bottom()) + r.moveBottomRight(QPoint(r.right(), rect().bottom())); + } +} + +void FormWindow::startRectDraw(const QPoint &pos, QWidget *, RectType t) +{ + m_rectAnchor = (t == Insert) ? designerGrid().snapPoint(pos) : pos; + + m_currRect = QRect(m_rectAnchor, QSize(0, 0)); + if (!m_rubberBand) + m_rubberBand = new QRubberBand(QRubberBand::Rectangle, this); + m_rubberBand->setGeometry(m_currRect); + m_rubberBand->show(); +} + +void FormWindow::continueRectDraw(const QPoint &pos, QWidget *, RectType t) +{ + const QPoint p2 = (t == Insert) ? designerGrid().snapPoint(pos) : pos; + + QRect r(m_rectAnchor, p2); + r = r.normalized(); + + if (m_currRect == r) + return; + + if (r.width() > 1 || r.height() > 1) { + m_currRect = r; + if (m_rubberBand) + m_rubberBand->setGeometry(m_currRect); + } +} + +void FormWindow::endRectDraw() +{ + if (m_rubberBand) { + delete m_rubberBand; + m_rubberBand = 0; + } +} + +QWidget *FormWindow::currentWidget() const +{ + return m_currentWidget; +} + +bool FormWindow::setCurrentWidget(QWidget *currentWidget) +{ + if (debugFormWindow) + qDebug() << "setCurrentWidget:" << m_currentWidget << " --> " << currentWidget; + if (currentWidget == m_currentWidget) + return false; + // repaint the old widget unless it is the main window + if (m_currentWidget && m_currentWidget != mainContainer()) { + m_selection->repaintSelection(m_currentWidget); + } + // set new and repaint + m_currentWidget = currentWidget; + if (m_currentWidget && m_currentWidget != mainContainer()) { + m_selection->repaintSelection(m_currentWidget); + } + return true; +} + +void FormWindow::selectWidget(QWidget* w, bool select) +{ + if (trySelectWidget(w, select)) + emitSelectionChanged(); +} + +// Selects a widget and determines the new current one. Returns true if a change occurs. +bool FormWindow::trySelectWidget(QWidget *w, bool select) +{ + if (debugFormWindow) + qDebug() << "trySelectWidget:" << w << select; + if (!isManaged(w) && !isCentralWidget(w)) + return false; + + if (!select && !isWidgetSelected(w)) + return false; + + if (!mainContainer()) + return false; + + if (isMainContainer(w) || isCentralWidget(w)) { + setCurrentWidget(mainContainer()); + return true; + } + + if (select) { + setCurrentWidget(w); + m_selection->addWidget(this, w); + } else { + QWidget *newCurrent = m_selection->removeWidget(w); + if (!newCurrent) + newCurrent = mainContainer(); + setCurrentWidget(newCurrent); + } + return true; +} + +void FormWindow::clearSelection(bool changePropertyDisplay) +{ + if (debugFormWindow) + qDebug() << "clearSelection(" << changePropertyDisplay << ')'; + // At all events, we need a current widget. + m_selection->clear(); + setCurrentWidget(mainContainer()); + + if (changePropertyDisplay) + emitSelectionChanged(); +} + +void FormWindow::emitSelectionChanged() +{ + if (m_blockSelectionChanged == true) { + // nothing to do + return; + } + + m_selectionChangedTimer->start(0); +} + +void FormWindow::selectionChangedTimerDone() +{ + emit selectionChanged(); +} + +bool FormWindow::isWidgetSelected(QWidget *w) const +{ + return m_selection->isWidgetSelected(w); +} + +bool FormWindow::isMainContainer(const QWidget *w) const +{ + return w && (w == this || w == mainContainer()); +} + +void FormWindow::updateChildSelections(QWidget *w) +{ + const QWidgetList l = w->findChildren(); + if (!l.empty()) { + const QWidgetList::const_iterator lcend = l.constEnd(); + for (QWidgetList::const_iterator it = l.constBegin(); it != lcend; ++it) { + QWidget *w = *it; + if (isManaged(w)) + updateSelection(w); + } + } +} + +void FormWindow::repaintSelection() +{ + m_selection->repaintSelection(); +} + +void FormWindow::raiseSelection(QWidget *w) +{ + m_selection->raiseWidget(w); +} + +void FormWindow::updateSelection(QWidget *w) +{ + if (!w->isVisibleTo(this)) { + selectWidget(w, false); + } else { + m_selection->updateGeometry(w); + } +} + +QWidget *FormWindow::designerWidget(QWidget *w) const +{ + while ((w && !isMainContainer(w) && !isManaged(w)) || isCentralWidget(w)) + w = w->parentWidget(); + + return w; +} + +bool FormWindow::isCentralWidget(QWidget *w) const +{ + if (QMainWindow *mainWindow = qobject_cast(mainContainer())) + return w == mainWindow->centralWidget(); + + return false; +} + +void FormWindow::ensureUniqueObjectName(QObject *object) +{ + QString name = object->objectName(); + if (name.isEmpty()) { + QDesignerWidgetDataBaseInterface *db = core()->widgetDataBase(); + if (QDesignerWidgetDataBaseItemInterface *item = db->item(db->indexOfObject(object))) + name = qdesigner_internal::qtify(item->name()); + } + unify(object, name, true); + object->setObjectName(name); +} + +template +static inline void insertNames(const QDesignerMetaDataBaseInterface *metaDataBase, + Iterator it, const Iterator &end, + QObject *excludedObject, QSet &nameSet) +{ + for ( ; it != end; ++it) + if (excludedObject != *it && metaDataBase->item(*it)) + nameSet.insert((*it)->objectName()); +} + +static QSet languageKeywords() +{ + static QSet keywords; + if (keywords.isEmpty()) { + // C++ keywords + keywords.insert(QLatin1String("asm")); + keywords.insert(QLatin1String("auto")); + keywords.insert(QLatin1String("bool")); + keywords.insert(QLatin1String("break")); + keywords.insert(QLatin1String("case")); + keywords.insert(QLatin1String("catch")); + keywords.insert(QLatin1String("char")); + keywords.insert(QLatin1String("class")); + keywords.insert(QLatin1String("const")); + keywords.insert(QLatin1String("const_cast")); + keywords.insert(QLatin1String("continue")); + keywords.insert(QLatin1String("default")); + keywords.insert(QLatin1String("delete")); + keywords.insert(QLatin1String("do")); + keywords.insert(QLatin1String("double")); + keywords.insert(QLatin1String("dynamic_cast")); + keywords.insert(QLatin1String("else")); + keywords.insert(QLatin1String("enum")); + keywords.insert(QLatin1String("explicit")); + keywords.insert(QLatin1String("export")); + keywords.insert(QLatin1String("extern")); + keywords.insert(QLatin1String("false")); + keywords.insert(QLatin1String("float")); + keywords.insert(QLatin1String("for")); + keywords.insert(QLatin1String("friend")); + keywords.insert(QLatin1String("goto")); + keywords.insert(QLatin1String("if")); + keywords.insert(QLatin1String("inline")); + keywords.insert(QLatin1String("int")); + keywords.insert(QLatin1String("long")); + keywords.insert(QLatin1String("mutable")); + keywords.insert(QLatin1String("namespace")); + keywords.insert(QLatin1String("new")); + keywords.insert(QLatin1String("NULL")); + keywords.insert(QLatin1String("operator")); + keywords.insert(QLatin1String("private")); + keywords.insert(QLatin1String("protected")); + keywords.insert(QLatin1String("public")); + keywords.insert(QLatin1String("register")); + keywords.insert(QLatin1String("reinterpret_cast")); + keywords.insert(QLatin1String("return")); + keywords.insert(QLatin1String("short")); + keywords.insert(QLatin1String("signed")); + keywords.insert(QLatin1String("sizeof")); + keywords.insert(QLatin1String("static")); + keywords.insert(QLatin1String("static_cast")); + keywords.insert(QLatin1String("struct")); + keywords.insert(QLatin1String("switch")); + keywords.insert(QLatin1String("template")); + keywords.insert(QLatin1String("this")); + keywords.insert(QLatin1String("throw")); + keywords.insert(QLatin1String("true")); + keywords.insert(QLatin1String("try")); + keywords.insert(QLatin1String("typedef")); + keywords.insert(QLatin1String("typeid")); + keywords.insert(QLatin1String("typename")); + keywords.insert(QLatin1String("union")); + keywords.insert(QLatin1String("unsigned")); + keywords.insert(QLatin1String("using")); + keywords.insert(QLatin1String("virtual")); + keywords.insert(QLatin1String("void")); + keywords.insert(QLatin1String("volatile")); + keywords.insert(QLatin1String("wchar_t")); + keywords.insert(QLatin1String("while")); + + // java keywords + keywords.insert(QLatin1String("abstract")); + keywords.insert(QLatin1String("assert")); + keywords.insert(QLatin1String("boolean")); + keywords.insert(QLatin1String("break")); + keywords.insert(QLatin1String("byte")); + keywords.insert(QLatin1String("case")); + keywords.insert(QLatin1String("catch")); + keywords.insert(QLatin1String("char")); + keywords.insert(QLatin1String("class")); + keywords.insert(QLatin1String("const")); + keywords.insert(QLatin1String("continue")); + keywords.insert(QLatin1String("default")); + keywords.insert(QLatin1String("do")); + keywords.insert(QLatin1String("double")); + keywords.insert(QLatin1String("else")); + keywords.insert(QLatin1String("enum")); + keywords.insert(QLatin1String("extends")); + keywords.insert(QLatin1String("false")); + keywords.insert(QLatin1String("final")); + keywords.insert(QLatin1String("finality")); + keywords.insert(QLatin1String("float")); + keywords.insert(QLatin1String("for")); + keywords.insert(QLatin1String("goto")); + keywords.insert(QLatin1String("if")); + keywords.insert(QLatin1String("implements")); + keywords.insert(QLatin1String("import")); + keywords.insert(QLatin1String("instanceof")); + keywords.insert(QLatin1String("int")); + keywords.insert(QLatin1String("interface")); + keywords.insert(QLatin1String("long")); + keywords.insert(QLatin1String("native")); + keywords.insert(QLatin1String("new")); + keywords.insert(QLatin1String("null")); + keywords.insert(QLatin1String("package")); + keywords.insert(QLatin1String("private")); + keywords.insert(QLatin1String("protected")); + keywords.insert(QLatin1String("public")); + keywords.insert(QLatin1String("return")); + keywords.insert(QLatin1String("short")); + keywords.insert(QLatin1String("static")); + keywords.insert(QLatin1String("strictfp")); + keywords.insert(QLatin1String("super")); + keywords.insert(QLatin1String("switch")); + keywords.insert(QLatin1String("synchronized")); + keywords.insert(QLatin1String("this")); + keywords.insert(QLatin1String("throw")); + keywords.insert(QLatin1String("throws")); + keywords.insert(QLatin1String("transient")); + keywords.insert(QLatin1String("true")); + keywords.insert(QLatin1String("try")); + keywords.insert(QLatin1String("void")); + keywords.insert(QLatin1String("volatile")); + keywords.insert(QLatin1String("while")); + } + return keywords; +} + +bool FormWindow::unify(QObject *w, QString &s, bool changeIt) +{ + typedef QSet StringSet; + + QWidget *main = mainContainer(); + if (!main) + return true; + + StringSet existingNames = languageKeywords(); + // build a set of existing names of other widget excluding self + if (!(w->isWidgetType() && isMainContainer(qobject_cast(w)))) + existingNames.insert(main->objectName()); + + const QDesignerMetaDataBaseInterface *metaDataBase = core()->metaDataBase(); + const QWidgetList widgetChildren = main->findChildren(); + if (!widgetChildren.empty()) + insertNames(metaDataBase, widgetChildren.constBegin(), widgetChildren.constEnd(), w, existingNames); + + const QList layoutChildren = main->findChildren(); + if (!layoutChildren.empty()) + insertNames(metaDataBase, layoutChildren.constBegin(), layoutChildren.constEnd(), w, existingNames); + + const QList actionChildren = main->findChildren(); + if (!actionChildren.empty()) + insertNames(metaDataBase, actionChildren.constBegin(), actionChildren.constEnd(), w, existingNames); + + const QList buttonGroupChildren = main->findChildren(); + if (!buttonGroupChildren.empty()) + insertNames(metaDataBase, buttonGroupChildren.constBegin(), buttonGroupChildren.constEnd(), w, existingNames); + + const StringSet::const_iterator enEnd = existingNames.constEnd(); + if (existingNames.constFind(s) == enEnd) + return true; + else + if (!changeIt) + return false; + + // split 'name_number' + qlonglong num = 0; + qlonglong factor = 1; + int idx = s.length()-1; + const ushort zeroUnicode = QLatin1Char('0').unicode(); + for ( ; idx > 0 && s.at(idx).isDigit(); --idx) { + num += (s.at(idx).unicode() - zeroUnicode) * factor; + factor *= 10; + } + // Position index past '_'. + const QChar underscore = QLatin1Char('_'); + if (idx >= 0 && s.at(idx) == underscore) { + idx++; + } else { + num = 1; + s += underscore; + idx = s.length(); + } + // try 'name_n', 'name_n+1' + for (num++ ; ;num++) { + s.truncate(idx); + s += QString::number(num); + if (existingNames.constFind(s) == enEnd) + break; + } + return false; +} +/* already_in_form is true when we are moving a widget from one parent to another inside the same + * form. All this means is that InsertWidgetCommand::undo() must not unmanage it. */ + +void FormWindow::insertWidget(QWidget *w, const QRect &rect, QWidget *container, bool already_in_form) +{ + clearSelection(false); + + beginCommand(tr("Insert widget '%1'").arg(WidgetFactory::classNameOf(m_core, w))); // ### use the WidgetDatabaseItem + + /* Reparenting into a QSplitter automatically adjusts child's geometry. We create the geometry + * command before we push the reparent command, so that the geometry command has the original + * geometry of the widget. */ + QRect r = rect; + Q_ASSERT(r.isValid()); + SetPropertyCommand *geom_cmd = new SetPropertyCommand(this); + geom_cmd->init(w, QLatin1String("geometry"), r); // ### use rc.size() + + if (w->parentWidget() != container) { + ReparentWidgetCommand *cmd = new ReparentWidgetCommand(this); + cmd->init(w, container); + m_undoStack.push(cmd); + } + + m_undoStack.push(geom_cmd); + + InsertWidgetCommand *cmd = new InsertWidgetCommand(this); + cmd->init(w, already_in_form); + m_undoStack.push(cmd); + + endCommand(); + + w->show(); +} + +QWidget *FormWindow::createWidget(DomUI *ui, const QRect &rc, QWidget *target) +{ + QWidget *container = findContainer(target, false); + if (!container) + return 0; + if (isMainContainer(container)) { + if (QMainWindow *mw = qobject_cast(container)) { + Q_ASSERT(mw->centralWidget() != 0); + container = mw->centralWidget(); + } + } + QDesignerResource resource(this); + const FormBuilderClipboard clipboard = resource.paste(ui, container); + if (clipboard.m_widgets.size() != 1) // multiple-paste from DomUI not supported yet + return 0; + QWidget *widget = clipboard.m_widgets.first(); + insertWidget(widget, rc, container); + return widget; +} + +#ifndef QT_NO_DEBUG +static bool isDescendant(const QWidget *parent, const QWidget *child) +{ + for (; child != 0; child = child->parentWidget()) { + if (child == parent) + return true; + } + return false; +} +#endif + +void FormWindow::resizeWidget(QWidget *widget, const QRect &geometry) +{ + Q_ASSERT(isDescendant(this, widget)); + + QRect r = geometry; + SetPropertyCommand *cmd = new SetPropertyCommand(this); + cmd->init(widget, QLatin1String("geometry"), r); + cmd->setText(tr("Resize")); + m_undoStack.push(cmd); +} + +void FormWindow::raiseChildSelections(QWidget *w) +{ + const QWidgetList l = w->findChildren(); + if (l.isEmpty()) + return; + m_selection->raiseList(l); +} + +QWidget *FormWindow::containerAt(const QPoint &pos, QWidget *notParentOf) +{ + QWidget *container = 0; + int depth = -1; + const QWidgetList selected = selectedWidgets(); + if (rect().contains(mapFromGlobal(pos))) { + container = mainContainer(); + depth = widgetDepth(container); + } + + QListIterator it(m_widgets); + while (it.hasNext()) { + QWidget *wit = it.next(); + if (qobject_cast(wit) || qobject_cast(wit)) + continue; + if (!wit->isVisibleTo(this)) + continue; + if (selected.indexOf(wit) != -1) + continue; + if (!core()->widgetDataBase()->isContainer(wit) && + wit != mainContainer()) + continue; + + // the rectangles of all ancestors of the container must contain the insert position + QWidget *w = wit; + while (w && !w->isWindow()) { + if (!w->rect().contains((w->mapFromGlobal(pos)))) + break; + w = w->parentWidget(); + } + if (!(w == 0 || w->isWindow())) + continue; // we did not get through the full while loop + + int wd = widgetDepth(wit); + if (wd == depth && container) { + if (wit->parentWidget()->children().indexOf(wit) > + container->parentWidget()->children().indexOf(container)) + wd++; + } + if (wd > depth && !isChildOf(wit, notParentOf)) { + depth = wd; + container = wit; + } + } + return container; +} + +QWidgetList FormWindow::selectedWidgets() const +{ + return m_selection->selectedWidgets(); +} + +void FormWindow::selectWidgets() +{ + bool selectionChanged = false; + const QWidgetList l = mainContainer()->findChildren(); + QListIterator it(l); + const QRect selRect(mapToGlobal(m_currRect.topLeft()), m_currRect.size()); + while (it.hasNext()) { + QWidget *w = it.next(); + if (w->isVisibleTo(this) && isManaged(w)) { + const QPoint p = w->mapToGlobal(QPoint(0,0)); + const QRect r(p, w->size()); + if (r.intersects(selRect) && !r.contains(selRect) && trySelectWidget(w, true)) + selectionChanged = true; + } + } + + if (selectionChanged) + emitSelectionChanged(); +} + +bool FormWindow::handleKeyPressEvent(QWidget *widget, QWidget *, QKeyEvent *e) +{ + if (qobject_cast(widget) || qobject_cast(widget)) + return false; + + e->accept(); // we always accept! + + switch (e->key()) { + default: break; // we don't care about the other keys + + case Qt::Key_Delete: + case Qt::Key_Backspace: + if (e->modifiers() == Qt::NoModifier) + deleteWidgets(); + break; + + case Qt::Key_Tab: + if (e->modifiers() == Qt::NoModifier) + cursor()->movePosition(QDesignerFormWindowCursorInterface::Next); + break; + + case Qt::Key_Backtab: + if (e->modifiers() == Qt::NoModifier) + cursor()->movePosition(QDesignerFormWindowCursorInterface::Prev); + break; + + case Qt::Key_Left: + case Qt::Key_Right: + case Qt::Key_Up: + case Qt::Key_Down: + handleArrowKeyEvent(e->key(), e->modifiers()); + break; + } + + return true; +} + +int FormWindow::getValue(const QRect &rect, int key, bool size) const +{ + if (size) { + if (key == Qt::Key_Left || key == Qt::Key_Right) + return rect.width(); + return rect.height(); + } + if (key == Qt::Key_Left || key == Qt::Key_Right) + return rect.x(); + return rect.y(); +} + +int FormWindow::calcValue(int val, bool forward, bool snap, int snapOffset) const +{ + if (snap) { + const int rest = val % snapOffset; + if (rest) { + const int offset = forward ? snapOffset : 0; + const int newOffset = rest < 0 ? offset - snapOffset : offset; + return val + newOffset - rest; + } + return (forward ? val + snapOffset : val - snapOffset); + } + return (forward ? val + 1 : val - 1); +} + +// ArrowKeyOperation: Stores a keyboard move or resize (Shift pressed) +// operation. +struct ArrowKeyOperation { + ArrowKeyOperation() : resize(false), distance(0), arrowKey(Qt::Key_Left) {} + + QRect apply(const QRect &in) const; + + bool resize; // Resize: Shift-Key->drag bottom/right corner, else just move + int distance; + int arrowKey; +}; + +} // namespace + +QT_END_NAMESPACE +Q_DECLARE_METATYPE(qdesigner_internal::ArrowKeyOperation) +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +QRect ArrowKeyOperation::apply(const QRect &rect) const +{ + QRect r = rect; + if (resize) { + if (arrowKey == Qt::Key_Left || arrowKey == Qt::Key_Right) + r.setWidth(r.width() + distance); + else + r.setHeight(r.height() + distance); + } else { + if (arrowKey == Qt::Key_Left || arrowKey == Qt::Key_Right) + r.moveLeft(r.x() + distance); + else + r.moveTop(r.y() + distance); + } + return r; +} + +QDebug operator<<(QDebug in, const ArrowKeyOperation &op) +{ + in.nospace() << "Resize=" << op.resize << " dist=" << op.distance << " Key=" << op.arrowKey << ' '; + return in; +} + +// ArrowKeyPropertyHelper: Applies a struct ArrowKeyOperation +// (stored as new value) to a list of widgets using to calculate the +// changed geometry of the widget in setValue(). Thus, the 'newValue' +// of the property command is the relative move distance, which is the same +// for all widgets (although resulting in different geometries for the widgets). +// The command merging can then work as it would when applying the same text +// to all QLabels. + +class ArrowKeyPropertyHelper : public PropertyHelper { +public: + ArrowKeyPropertyHelper(QObject* o, SpecialProperty sp, + QDesignerPropertySheetExtension *s, int i) : + PropertyHelper(o, sp, s, i) {} + + virtual Value setValue(QDesignerFormWindowInterface *fw, const QVariant &value, bool changed, unsigned subPropertyMask); +}; + +PropertyHelper::Value ArrowKeyPropertyHelper::setValue(QDesignerFormWindowInterface *fw, const QVariant &value, bool changed, unsigned subPropertyMask) +{ + // Apply operation to obtain the new geometry value. + QWidget *w = qobject_cast(object()); + const ArrowKeyOperation operation = qvariant_cast(value); + const QRect newGeom = operation.apply(w->geometry()); + return PropertyHelper::setValue(fw, QVariant(newGeom), changed, subPropertyMask); +} + +// ArrowKeyPropertyCommand: Helper factory overwritten to create +// ArrowKeyPropertyHelper and a merge operation that merges values of +// the same direction. +class ArrowKeyPropertyCommand: public SetPropertyCommand { +public: + explicit ArrowKeyPropertyCommand(QDesignerFormWindowInterface *fw, + QUndoCommand *p = 0); + + void init(QWidgetList &l, const ArrowKeyOperation &op); + +protected: + virtual PropertyHelper *createPropertyHelper(QObject *o, SpecialProperty sp, + QDesignerPropertySheetExtension *s, int i) const + { return new ArrowKeyPropertyHelper(o, sp, s, i); } + virtual QVariant mergeValue(const QVariant &newValue); +}; + +ArrowKeyPropertyCommand::ArrowKeyPropertyCommand(QDesignerFormWindowInterface *fw, + QUndoCommand *p) : + SetPropertyCommand(fw, p) +{ + static const int mid = qRegisterMetaType(); + Q_UNUSED(mid) +} + +void ArrowKeyPropertyCommand::init(QWidgetList &l, const ArrowKeyOperation &op) +{ + QObjectList ol; + foreach(QWidget *w, l) + ol.push_back(w); + SetPropertyCommand::init(ol, QLatin1String("geometry"), QVariant::fromValue(op)); + + setText(op.resize ? FormWindow::tr("Key Resize") : FormWindow::tr("Key Move")); +} + +QVariant ArrowKeyPropertyCommand::mergeValue(const QVariant &newMergeValue) +{ + // Merge move operations of the same arrow key + if (!newMergeValue.canConvert()) + return QVariant(); + ArrowKeyOperation mergedOperation = qvariant_cast(newValue()); + const ArrowKeyOperation newMergeOperation = qvariant_cast(newMergeValue); + if (mergedOperation.resize != newMergeOperation.resize || mergedOperation.arrowKey != newMergeOperation.arrowKey) + return QVariant(); + mergedOperation.distance += newMergeOperation.distance; + return QVariant::fromValue(mergedOperation); +} + +void FormWindow::handleArrowKeyEvent(int key, Qt::KeyboardModifiers modifiers) +{ + const QDesignerFormWindowCursorInterface *c = cursor(); + if (!c->hasSelection()) + return; + + QWidgetList selection; + + // check if a laid out widget is selected + const int count = c->selectedWidgetCount(); + for (int index = 0; index < count; ++index) { + QWidget *w = c->selectedWidget(index); + if (!LayoutInfo::isWidgetLaidout(m_core, w)) + selection.append(w); + } + + if (selection.isEmpty()) + return; + + QWidget *current = c->current(); + if (!current || LayoutInfo::isWidgetLaidout(m_core, current)) { + current = selection.first(); + } + + const bool size = modifiers & Qt::ShiftModifier; + + const bool snap = !(modifiers & Qt::ControlModifier); + const bool forward = (key == Qt::Key_Right || key == Qt::Key_Down); + const int snapPoint = (key == Qt::Key_Left || key == Qt::Key_Right) ? grid().x() : grid().y(); + + const int oldValue = getValue(current->geometry(), key, size); + + const int newValue = calcValue(oldValue, forward, snap, snapPoint); + + ArrowKeyOperation operation; + operation.resize = modifiers & Qt::ShiftModifier; + operation.distance = newValue - oldValue; + operation.arrowKey = key; + + ArrowKeyPropertyCommand *cmd = new ArrowKeyPropertyCommand(this); + cmd->init(selection, operation); + m_undoStack.push(cmd); +} + +bool FormWindow::handleKeyReleaseEvent(QWidget *, QWidget *, QKeyEvent *e) +{ + e->accept(); + return true; +} + +void FormWindow::selectAll() +{ + bool selectionChanged = false; + foreach (QWidget *widget, m_widgets) { + if (widget->isVisibleTo(this) && trySelectWidget(widget, true)) + selectionChanged = true; + } + if (selectionChanged) + emitSelectionChanged(); +} + +void FormWindow::createLayout(int type, QWidget *container) +{ + if (container) { + layoutContainer(container, type); + } else { + LayoutCommand *cmd = new LayoutCommand(this); + cmd->init(mainContainer(), selectedWidgets(), static_cast(type)); + commandHistory()->push(cmd); + } +} + +void FormWindow::morphLayout(QWidget *container, int newType) +{ + MorphLayoutCommand *cmd = new MorphLayoutCommand(this); + if (cmd->init(container, newType)) { + commandHistory()->push(cmd); + } else { + qDebug() << "** WARNING Unable to morph layout."; + delete cmd; + } +} + +void FormWindow::deleteWidgets() +{ + QWidgetList selection = selectedWidgets(); + simplifySelection(&selection); + + deleteWidgetList(selection); +} + +QString FormWindow::fileName() const +{ + return m_fileName; +} + +void FormWindow::setFileName(const QString &fileName) +{ + if (m_fileName == fileName) + return; + + m_fileName = fileName; + emit fileNameChanged(fileName); +} + +QString FormWindow::contents() const +{ + QBuffer b; + if (!mainContainer() || !b.open(QIODevice::WriteOnly)) + return QString(); + + QDesignerResource resource(const_cast(this)); + resource.save(&b, mainContainer()); + + return QString::fromUtf8(b.buffer()); +} + +void FormWindow::copy() +{ + QBuffer b; + if (!b.open(QIODevice::WriteOnly)) + return; + + FormBuilderClipboard clipboard; + QDesignerResource resource(this); + resource.setSaveRelative(false); + clipboard.m_widgets = selectedWidgets(); + simplifySelection(&clipboard.m_widgets); + resource.copy(&b, clipboard); + + qApp->clipboard()->setText(QString::fromUtf8(b.buffer()), QClipboard::Clipboard); +} + +void FormWindow::cut() +{ + copy(); + deleteWidgets(); +} + +// for cases like QMainWindow (central widget is an inner container) or QStackedWidget (page is an inner container) +QWidget *FormWindow::innerContainer(QWidget *outerContainer) const +{ + if (m_core->widgetDataBase()->isContainer(outerContainer)) + if (const QDesignerContainerExtension *container = qt_extension(m_core->extensionManager(), outerContainer)) { + const int currentIndex = container->currentIndex(); + return currentIndex >= 0 ? + container->widget(currentIndex) : + static_cast(0); + } + return outerContainer; +} + +QWidget *FormWindow::containerForPaste() const +{ + QWidget *w = mainContainer(); + if (!w) + return 0; + do { + // Try to find a close parent, for example a non-laid-out + // QFrame/QGroupBox when a widget within it is selected. + QWidgetList selection = selectedWidgets(); + if (selection.empty()) + break; + simplifySelection(&selection); + + QWidget *containerOfW = findContainer(selection.first(), /* exclude layouts */ true); + if (!containerOfW || containerOfW == mainContainer()) + break; + // No layouts, must be container. No empty page-based containers. + containerOfW = innerContainer(containerOfW); + if (!containerOfW) + break; + if (LayoutInfo::layoutType(m_core, containerOfW) != LayoutInfo::NoLayout || !m_core->widgetDataBase()->isContainer(containerOfW)) + break; + w = containerOfW; + } while (false); + // First check for layout (note that it does not cover QMainWindow + // and the like as the central widget has the layout). + + w = innerContainer(w); + if (!w) + return 0; + if (LayoutInfo::layoutType(m_core, w) != LayoutInfo::NoLayout) + return 0; + // Go up via container extension (also includes step from QMainWindow to its central widget) + w = m_core->widgetFactory()->containerOfWidget(w); + if (w == 0 || LayoutInfo::layoutType(m_core, w) != LayoutInfo::NoLayout) + return 0; + + if (debugFormWindow) + qDebug() <<"containerForPaste() " << w; + return w; +} + +void FormWindow::paste() +{ + paste(PasteAll); +} + +// Construct DomUI from clipboard (paste) and determine number of widgets/actions. +static inline DomUI *domUIFromClipboard(int *widgetCount, int *actionCount) +{ + *widgetCount = *actionCount = 0; + const QString clipboardText = qApp->clipboard()->text(); + if (clipboardText.isEmpty() || clipboardText.indexOf(QLatin1Char('<')) == -1) + return 0; + + QXmlStreamReader reader(clipboardText); + DomUI *ui = 0; + const QString uiElement = QLatin1String("ui"); + while (!reader.atEnd()) { + if (reader.readNext() == QXmlStreamReader::StartElement) { + if (reader.name().compare(uiElement, Qt::CaseInsensitive) == 0 && !ui) { + ui = new DomUI(); + ui->read(reader); + break; + } else { + reader.raiseError(QCoreApplication::translate("FormWindow", "Unexpected element <%1>").arg(reader.name().toString())); + } + } + } + if (reader.hasError()) { + delete ui; + ui = 0; + designerWarning(QCoreApplication::translate("FormWindow", "Error while pasting clipboard contents at line %1, column %2: %3"). + arg(reader.lineNumber()).arg(reader.columnNumber()).arg(reader.errorString())); + return 0; + } + + if (const DomWidget *topLevel = ui->elementWidget()) { + *widgetCount = topLevel->elementWidget().size(); + *actionCount = topLevel->elementAction().size(); + } + if (*widgetCount == 0 && *actionCount == 0) { + delete ui; + return 0; + } + return ui; +} + +static inline QString pasteCommandDescription(int widgetCount, int actionCount) +{ + if (widgetCount == 0) + return FormWindow::tr("Paste %n action(s)", 0, actionCount); + if (actionCount == 0) + return FormWindow::tr("Paste %n widget(s)", 0, widgetCount); + return FormWindow::tr("Paste (%1 widgets, %2 actions)").arg(widgetCount).arg(actionCount); +} + +static void positionPastedWidgetsAtMousePosition(FormWindow *fw, const QPoint &contextMenuPosition, QWidget *parent, const QWidgetList &l) +{ + // Try to position pasted widgets at mouse position (current mouse position for Ctrl-V or position of context menu) + // if it fits. If it is completely outside, force it to 0,0 + // If it fails, the old coordinates relative to the previous parent will be used. + QPoint currentPos = contextMenuPosition.x() >=0 ? parent->mapFrom(fw, contextMenuPosition) : parent->mapFromGlobal(QCursor::pos()); + const Grid &grid = fw->designerGrid(); + QPoint cursorPos = grid.snapPoint(currentPos); + const QRect parentGeometry = QRect(QPoint(0, 0), parent->size()); + const bool outside = !parentGeometry.contains(cursorPos); + if (outside) + cursorPos = grid.snapPoint(QPoint(0, 0)); + // Determine area of pasted widgets + QRect pasteArea; + const QWidgetList::const_iterator lcend = l.constEnd(); + for (QWidgetList::const_iterator it = l.constBegin(); it != lcend; ++it) + pasteArea =pasteArea.isNull() ? (*it)->geometry() : pasteArea.united((*it)->geometry()); + + // Mouse on some child? (try to position bottomRight on a free spot to + // get the stacked-offset effect of Designer 4.3, that is, offset by grid if Ctrl-V is pressed continuously + do { + const QPoint bottomRight = cursorPos + QPoint(pasteArea.width(), pasteArea.height()) - QPoint(1, 1); + if (bottomRight.y() > parentGeometry.bottom() || parent->childAt(bottomRight) == 0) + break; + cursorPos += QPoint(grid.deltaX(), grid.deltaY()); + } while (true); + // Move. + const QPoint offset = cursorPos - pasteArea.topLeft(); + for (QWidgetList::const_iterator it = l.constBegin(); it != lcend; ++it) + (*it)->move((*it)->pos() + offset); +} + +void FormWindow::paste(PasteMode pasteMode) +{ + // Avoid QDesignerResource constructing widgets that are not used as + // QDesignerResource manages the widgets it creates (creating havoc if one remains unused) + DomUI *ui = 0; + do { + int widgetCount; + int actionCount; + ui = domUIFromClipboard(&widgetCount, &actionCount); + if (!ui) + break; + + // Check for actions + if (pasteMode == PasteActionsOnly) + if (widgetCount != 0 || actionCount == 0) + break; + + // Check for widgets: need a container + QWidget *pasteContainer = widgetCount ? containerForPaste() : 0; + if (widgetCount && pasteContainer == 0) { + + const QString message = tr("Cannot paste widgets. Designer could not find a container " + "without a layout to paste into."); + const QString infoMessage = tr("Break the layout of the " + "container you want to paste into, select this container " + "and then paste again."); + core()->dialogGui()->message(this, QDesignerDialogGuiInterface::FormEditorMessage, QMessageBox::Information, + tr("Paste error"), message, infoMessage, QMessageBox::Ok); + break; + } + + QDesignerResource resource(this); + // Note that the widget factory must be able to locate the + // form window (us) via parent, otherwise, it will not able to construct QLayoutWidgets + // (It will then default to widgets) among other issues. + const FormBuilderClipboard clipboard = resource.paste(ui, pasteContainer, this); + + clearSelection(false); + // Create command sequence + beginCommand(pasteCommandDescription(widgetCount, actionCount)); + + if (widgetCount) { + positionPastedWidgetsAtMousePosition(this, m_contextMenuPosition, pasteContainer, clipboard.m_widgets); + foreach (QWidget *w, clipboard.m_widgets) { + InsertWidgetCommand *cmd = new InsertWidgetCommand(this); + cmd->init(w); + m_undoStack.push(cmd); + selectWidget(w); + } + } + + if (actionCount) + foreach (QAction *a, clipboard.m_actions) { + ensureUniqueObjectName(a); + AddActionCommand *cmd = new AddActionCommand(this); + cmd->init(a); + m_undoStack.push(cmd); + } + endCommand(); + } while (false); + delete ui; +} + +// Draw a dotted frame around containers +bool FormWindow::frameNeeded(QWidget *w) const +{ + if (!core()->widgetDataBase()->isContainer(w)) + return false; + if (qobject_cast(w)) + return false; + if (qobject_cast(w)) + return false; + if (qobject_cast(w)) + return false; + if (qobject_cast(w)) + return false; + if (qobject_cast(w)) + return false; + if (qobject_cast(w)) + return false; + if (qobject_cast(w)) + return false; + if (qobject_cast(w)) + return false; + if (qobject_cast(w)) + return false; + return true; +} + +bool FormWindow::eventFilter(QObject *watched, QEvent *event) +{ + const bool ret = FormWindowBase::eventFilter(watched, event); + if (event->type() != QEvent::Paint) + return ret; + + Q_ASSERT(watched->isWidgetType()); + QWidget *w = static_cast(watched); + QPaintEvent *pe = static_cast(event); + const QRect widgetRect = w->rect(); + const QRect paintRect = pe->rect(); + // Does the paint rectangle touch the borders of the widget rectangle + if (paintRect.x() > widgetRect.x() && paintRect.y() > widgetRect.y() && + paintRect.right() < widgetRect.right() && paintRect.bottom() < widgetRect.bottom()) + return ret; + QPainter p(w); + const QPen pen(QColor(0, 0, 0, 32), 0, Qt::DotLine); + p.setPen(pen); + p.setBrush(QBrush(Qt::NoBrush)); + p.drawRect(widgetRect.adjusted(0, 0, -1, -1)); + return ret; +} + +void FormWindow::manageWidget(QWidget *w) +{ + if (isManaged(w)) + return; + + Q_ASSERT(qobject_cast(w) == 0); + + if (w->hasFocus()) + setFocus(); + + core()->metaDataBase()->add(w); + + m_insertedWidgets.insert(w); + m_widgets.append(w); + +#ifndef QT_NO_CURSOR + setCursorToAll(Qt::ArrowCursor, w); +#endif + + emit changed(); + emit widgetManaged(w); + + if (frameNeeded(w)) + w->installEventFilter(this); +} + +void FormWindow::unmanageWidget(QWidget *w) +{ + if (!isManaged(w)) + return; + + m_selection->removeWidget(w); + + emit aboutToUnmanageWidget(w); + + if (w == m_currentWidget) + setCurrentWidget(mainContainer()); + + core()->metaDataBase()->remove(w); + + m_insertedWidgets.remove(w); + m_widgets.removeAt(m_widgets.indexOf(w)); + + emit changed(); + emit widgetUnmanaged(w); + + if (frameNeeded(w)) + w->removeEventFilter(this); +} + +bool FormWindow::isManaged(QWidget *w) const +{ + return m_insertedWidgets.contains(w); +} + +void FormWindow::breakLayout(QWidget *w) +{ + if (w == this) + w = mainContainer(); + // Find the first-order managed child widgets + QWidgetList widgets; + + const QObjectList children = w->children(); + const QObjectList::const_iterator cend = children.constEnd(); + const QDesignerMetaDataBaseInterface *mdb = core()->metaDataBase(); + for (QObjectList::const_iterator it = children.constBegin(); it != cend; ++it) + if ( (*it)->isWidgetType()) { + QWidget *w = static_cast(*it); + if (mdb->item(w)) + widgets.push_back(w); + } + + BreakLayoutCommand *cmd = new BreakLayoutCommand(this); + cmd->init(widgets, w); + commandHistory()->push(cmd); + clearSelection(false); +} + +void FormWindow::beginCommand(const QString &description) +{ + m_undoStack.beginMacro(description); +} + +void FormWindow::endCommand() +{ + m_undoStack.endMacro(); +} + +void FormWindow::raiseWidgets() +{ + QWidgetList widgets = selectedWidgets(); + simplifySelection(&widgets); + + if (widgets.isEmpty()) + return; + + beginCommand(tr("Raise widgets")); + foreach (QWidget *widget, widgets) { + RaiseWidgetCommand *cmd = new RaiseWidgetCommand(this); + cmd->init(widget); + m_undoStack.push(cmd); + } + endCommand(); +} + +void FormWindow::lowerWidgets() +{ + QWidgetList widgets = selectedWidgets(); + simplifySelection(&widgets); + + if (widgets.isEmpty()) + return; + + beginCommand(tr("Lower widgets")); + foreach (QWidget *widget, widgets) { + LowerWidgetCommand *cmd = new LowerWidgetCommand(this); + cmd->init(widget); + m_undoStack.push(cmd); + } + endCommand(); +} + +bool FormWindow::handleMouseButtonDblClickEvent(QWidget *w, QWidget *managedWidget, QMouseEvent *e) +{ + if (debugFormWindow) + qDebug() << "handleMouseButtonDblClickEvent:" << w << ',' << managedWidget << "state=" << m_mouseState; + + e->accept(); + + // Might be out of sync due cycling of the parent selection + // In that case, do nothing + if (isWidgetSelected(managedWidget)) + emit activated(managedWidget); + + m_mouseState = MouseDoubleClicked; + return true; +} + + +QMenu *FormWindow::initializePopupMenu(QWidget *managedWidget) +{ + if (!isManaged(managedWidget) || currentTool()) + return 0; + + // Make sure the managedWidget is selected and current since + // the SetPropertyCommands must use the right reference + // object obtained from the property editor for the property group + // of a multiselection to be correct. + const bool selected = isWidgetSelected(managedWidget); + bool update = false; + if (selected == false) { + clearObjectInspectorSelection(m_core); // We might have a toolbar or non-widget selected in the object inspector. + clearSelection(false); + update = trySelectWidget(managedWidget, true); + raiseChildSelections(managedWidget); // raise selections and select widget + } else { + update = setCurrentWidget(managedWidget); + } + + if (update) { + emitSelectionChanged(); + QMetaObject::invokeMethod(core()->formWindowManager(), "slotUpdateActions"); + } + + QWidget *contextMenuWidget = 0; + + if (isMainContainer(managedWidget)) { // press on a child widget + contextMenuWidget = mainContainer(); + } else { // press on a child widget + // if widget is laid out, find the first non-laid out super-widget + QWidget *realWidget = managedWidget; // but store the original one + QMainWindow *mw = qobject_cast(mainContainer()); + + if (mw && mw->centralWidget() == realWidget) { + contextMenuWidget = managedWidget; + } else { + contextMenuWidget = realWidget; + } + } + + if (!contextMenuWidget) + return 0; + + QMenu *contextMenu = createPopupMenu(contextMenuWidget); + if (!contextMenu) + return 0; + + emit contextMenuRequested(contextMenu, contextMenuWidget); + return contextMenu; +} + +bool FormWindow::handleContextMenu(QWidget *, QWidget *managedWidget, QContextMenuEvent *e) +{ + QMenu *contextMenu = initializePopupMenu(managedWidget); + if (!contextMenu) + return false; + const QPoint globalPos = e->globalPos(); + m_contextMenuPosition = mapFromGlobal (globalPos); + contextMenu->exec(globalPos); + delete contextMenu; + e->accept(); + m_contextMenuPosition = QPoint(-1, -1); + return true; +} + +void FormWindow::setContents(QIODevice *dev) +{ + UpdateBlocker ub(this); + clearSelection(); + m_selection->clearSelectionPool(); + m_insertedWidgets.clear(); + m_widgets.clear(); + // The main container is cleared as otherwise + // the names of the newly loaded objects will be unified. + clearMainContainer(); + emit changed(); + + QDesignerResource r(this); + QWidget *w = r.load(dev, formContainer()); + setMainContainer(w); + emit changed(); +} + +void FormWindow::setContents(const QString &contents) +{ + QByteArray data = contents.toUtf8(); + QBuffer b(&data); + if (b.open(QIODevice::ReadOnly)) + setContents(&b); +} + +void FormWindow::layoutContainer(QWidget *w, int type) +{ + if (w == this) + w = mainContainer(); + + w = core()->widgetFactory()->containerOfWidget(w); + + const QObjectList l = w->children(); + if (l.isEmpty()) + return; + // find managed widget children + QWidgetList widgets; + const QObjectList::const_iterator ocend = l.constEnd(); + for (QObjectList::const_iterator it = l.constBegin(); it != l.constEnd(); ++it) + if ( (*it)->isWidgetType() ) { + QWidget *widget = static_cast(*it); + if (widget->isVisibleTo(this) && isManaged(widget)) + widgets.append(widget); + } + + LayoutCommand *cmd = new LayoutCommand(this); + cmd->init(mainContainer(), widgets, static_cast(type), w); + clearSelection(false); + commandHistory()->push(cmd); +} + +bool FormWindow::hasInsertedChildren(QWidget *widget) const // ### move +{ + if (QDesignerContainerExtension *container = qt_extension(core()->extensionManager(), widget)) { + const int index = container->currentIndex(); + if (index < 0) + return false; + widget = container->widget(index); + } + + const QWidgetList l = widgets(widget); + + foreach (QWidget *child, l) { + if (isManaged(child) && !LayoutInfo::isWidgetLaidout(core(), child) && child->isVisibleTo(const_cast(this))) + return true; + } + + return false; +} + +// "Select Ancestor" sub menu code +void FormWindow::slotSelectWidget(QAction *a) +{ + if (QWidget *w = qvariant_cast(a->data())) + selectSingleWidget(w); +} + +static inline QString objectNameOf(const QWidget *w) +{ + if (const QLayoutWidget *lw = qobject_cast(w)) { + const QLayout *layout = lw->layout(); + const QString rc = layout->objectName(); + if (!rc.isEmpty()) + return rc; + // Fall thru for 4.3 forms which have a name on the widget: Display the class name + return QString::fromUtf8(layout->metaObject()->className()); + } + return w->objectName(); +} + +QAction *FormWindow::createSelectAncestorSubMenu(QWidget *w) +{ + // Find the managed, unselected parents + QWidgetList parents; + QWidget *mc = mainContainer(); + for (QWidget *p = w->parentWidget(); p && p != mc; p = p->parentWidget()) + if (isManaged(p) && !isWidgetSelected(p)) + parents.push_back(p); + if (parents.empty()) + return 0; + // Create a submenu listing the managed, unselected parents + QMenu *menu = new QMenu; + QActionGroup *ag = new QActionGroup(menu); + QObject::connect(ag, SIGNAL(triggered(QAction*)), this, SLOT(slotSelectWidget(QAction*))); + const int size = parents.size(); + for (int i = 0; i < size; i++) { + QWidget *w = parents.at(i); + QAction *a = ag->addAction(objectNameOf(w)); + a->setData(QVariant::fromValue(w)); + menu->addAction(a); + } + QAction *ma = new QAction(tr("Select Ancestor"), 0); + ma->setMenu(menu); + return ma; +} + +QMenu *FormWindow::createPopupMenu(QWidget *w) +{ + QMenu *popup = createExtensionTaskMenu(this, w, true); + if (!popup) + popup = new QMenu; + // if w doesn't have a QDesignerTaskMenu as a child create one and make it a child. + // insert actions from QDesignerTaskMenu + + QDesignerFormWindowManagerInterface *manager = core()->formWindowManager(); + const bool isFormWindow = qobject_cast(w); + + // Check for special containers and obtain the page menu from them to add layout actions. + if (!isFormWindow) { + if (QStackedWidget *stackedWidget = qobject_cast(w)) { + QStackedWidgetEventFilter::addStackedWidgetContextMenuActions(stackedWidget, popup); + } else if (QTabWidget *tabWidget = qobject_cast(w)) { + QTabWidgetEventFilter::addTabWidgetContextMenuActions(tabWidget, popup); + } else if (QToolBox *toolBox = qobject_cast(w)) { + QToolBoxHelper::addToolBoxContextMenuActions(toolBox, popup); + } + + if (manager->actionLower()->isEnabled()) { + popup->addAction(manager->actionLower()); + popup->addAction(manager->actionRaise()); + popup->addSeparator(); + } + popup->addAction(manager->actionCut()); + popup->addAction(manager->actionCopy()); + } + + popup->addAction(manager->actionPaste()); + + if (QAction *selectAncestorAction = createSelectAncestorSubMenu(w)) + popup->addAction(selectAncestorAction); + popup->addAction(manager->actionSelectAll()); + + if (!isFormWindow) { + popup->addAction(manager->actionDelete()); + } + + popup->addSeparator(); + QMenu *layoutMenu = popup->addMenu(tr("Lay out")); + layoutMenu->addAction(manager->actionAdjustSize()); + layoutMenu->addAction(manager->actionHorizontalLayout()); + layoutMenu->addAction(manager->actionVerticalLayout()); + if (!isFormWindow) { + layoutMenu->addAction(manager->actionSplitHorizontal()); + layoutMenu->addAction(manager->actionSplitVertical()); + } + layoutMenu->addAction(manager->actionGridLayout()); + layoutMenu->addAction(manager->actionFormLayout()); + layoutMenu->addAction(manager->actionBreakLayout()); + layoutMenu->addAction(manager->actionSimplifyLayout()); + + return popup; +} + +void FormWindow::resizeEvent(QResizeEvent *e) +{ + m_geometryChangedTimer->start(10); + + QWidget::resizeEvent(e); +} + +/*! + Maps \a pos in \a w's coordinates to the form's coordinate system. + + This is the equivalent to mapFromGlobal(w->mapToGlobal(pos)) but + avoids the two roundtrips to the X-Server on Unix/X11. + */ +QPoint FormWindow::mapToForm(const QWidget *w, const QPoint &pos) const +{ + QPoint p = pos; + const QWidget* i = w; + while (i && !i->isWindow() && !isMainContainer(i)) { + p = i->mapToParent(p); + i = i->parentWidget(); + } + + return mapFromGlobal(w->mapToGlobal(pos)); +} + +bool FormWindow::canBeBuddy(QWidget *w) const // ### rename me. +{ + if (QDesignerPropertySheetExtension *sheet = qt_extension(core()->extensionManager(), w)) { + const int index = sheet->indexOf(QLatin1String("focusPolicy")); + if (index != -1) { + bool ok = false; + const Qt::FocusPolicy q = static_cast(Utils::valueOf(sheet->property(index), &ok)); + return ok && q != Qt::NoFocus; + } + } + + return false; +} + +QWidget *FormWindow::findContainer(QWidget *w, bool excludeLayout) const +{ + if (!isChildOf(w, this) + || const_cast(w) == this) + return 0; + + QDesignerWidgetFactoryInterface *widgetFactory = core()->widgetFactory(); + QDesignerWidgetDataBaseInterface *widgetDataBase = core()->widgetDataBase(); + QDesignerMetaDataBaseInterface *metaDataBase = core()->metaDataBase(); + + QWidget *container = widgetFactory->containerOfWidget(mainContainer()); // default parent for new widget is the formwindow + if (!isMainContainer(w)) { // press was not on formwindow, check if we can find another parent + while (w) { + if (qobject_cast(w) || !metaDataBase->item(w)) { + w = w->parentWidget(); + continue; + } + + const bool isContainer = widgetDataBase->isContainer(w, true) || w == mainContainer(); + + if (!isContainer || (excludeLayout && qobject_cast(w))) { // ### skip QSplitter + w = w->parentWidget(); + } else { + container = w; + break; + } + } + } + + return container; +} + +void FormWindow::simplifySelection(QWidgetList *sel) const +{ + if (sel->size() < 2) + return; + // Figure out which widgets should be removed from selection. + // We want to remove those whose parent widget is also in the + // selection (because the child widgets are contained by + // their parent, they shouldn't be in the selection -- + // they are "implicitly" selected). + QWidget *mainC = mainContainer(); // Quick check for main container first + if (sel->contains(mainC)) { + sel->clear(); + sel->push_back(mainC); + return; + } + typedef QVector WidgetVector; + WidgetVector toBeRemoved; + toBeRemoved.reserve(sel->size()); + const QWidgetList::const_iterator scend = sel->constEnd(); + for (QWidgetList::const_iterator it = sel->constBegin(); it != scend; ++it) { + QWidget *child = *it; + for (QWidget *w = child; true ; ) { // Is any of the parents also selected? + QWidget *parent = w->parentWidget(); + if (!parent || parent == mainC) + break; + if (sel->contains(parent)) { + toBeRemoved.append(child); + break; + } + w = parent; + } + } + // Now we can actually remove the widgets that were marked + // for removal in the previous pass. + if (!toBeRemoved.isEmpty()) { + const WidgetVector::const_iterator rcend = toBeRemoved.constEnd(); + for (WidgetVector::const_iterator it = toBeRemoved.constBegin(); it != rcend; ++it) + sel->removeAll(*it); + } +} + +FormWindow *FormWindow::findFormWindow(QWidget *w) +{ + return qobject_cast(QDesignerFormWindowInterface::findFormWindow(w)); +} + +bool FormWindow::isDirty() const +{ + return m_undoStack.isDirty(); +} + +void FormWindow::setDirty(bool dirty) +{ + m_undoStack.setDirty(dirty); +} + +QWidget *FormWindow::containerAt(const QPoint &pos) +{ + QWidget *widget = widgetAt(pos); + return findContainer(widget, true); +} + +static QWidget *childAt_SkipDropLine(QWidget *w, QPoint pos) +{ + const QObjectList child_list = w->children(); + for (int i = child_list.size() - 1; i >= 0; --i) { + QObject *child_obj = child_list[i]; + if (qobject_cast(child_obj) != 0) + continue; + QWidget *child = qobject_cast(child_obj); + if (!child || child->isWindow() || !child->isVisible() || + !child->geometry().contains(pos) || child->testAttribute(Qt::WA_TransparentForMouseEvents)) + continue; + const QPoint childPos = child->mapFromParent(pos); + if (QWidget *res = childAt_SkipDropLine(child, childPos)) + return res; + if (child->testAttribute(Qt::WA_MouseNoMask) || child->mask().contains(pos) + || child->mask().isEmpty()) + return child; + } + + return 0; +} + +QWidget *FormWindow::widgetAt(const QPoint &pos) +{ + QWidget *w = childAt(pos); + if (qobject_cast(w) != 0) + w = childAt_SkipDropLine(this, pos); + return (w == 0 || w == formContainer()) ? this : w; +} + +void FormWindow::highlightWidget(QWidget *widget, const QPoint &pos, HighlightMode mode) +{ + Q_ASSERT(widget); + + if (QMainWindow *mainWindow = qobject_cast (widget)) { + widget = mainWindow->centralWidget(); + } + + QWidget *container = findContainer(widget, false); + + if (container == 0 || core()->metaDataBase()->item(container) == 0) + return; + + if (QDesignerActionProviderExtension *g = qt_extension(core()->extensionManager(), container)) { + if (mode == Restore) { + g->adjustIndicator(QPoint()); + } else { + const QPoint pt = widget->mapTo(container, pos); + g->adjustIndicator(pt); + } + } else if (QDesignerLayoutDecorationExtension *g = qt_extension(core()->extensionManager(), container)) { + if (mode == Restore) { + g->adjustIndicator(QPoint(), -1); + } else { + const QPoint pt = widget->mapTo(container, pos); + const int index = g->findItemAt(pt); + g->adjustIndicator(pt, index); + } + } + + QMainWindow *mw = qobject_cast (container); + if (container == mainContainer() || (mw && mw->centralWidget() && mw->centralWidget() == container)) + return; + + if (mode == Restore) { + const WidgetPaletteMap::iterator pit = m_palettesBeforeHighlight.find(container); + if (pit != m_palettesBeforeHighlight.end()) { + container->setPalette(pit.value().first); + container->setAutoFillBackground(pit.value().second); + m_palettesBeforeHighlight.erase(pit); + } + } else { + QPalette p = container->palette(); + if (!m_palettesBeforeHighlight.contains(container)) { + PaletteAndFill paletteAndFill; + if (container->testAttribute(Qt::WA_SetPalette)) + paletteAndFill.first = p; + paletteAndFill.second = container->autoFillBackground(); + m_palettesBeforeHighlight.insert(container, paletteAndFill); + } + + p.setColor(backgroundRole(), p.midlight().color()); + container->setPalette(p); + container->setAutoFillBackground(true); + } +} + +QWidgetList FormWindow::widgets(QWidget *widget) const +{ + const QObjectList children = widget->children(); + if (children.empty()) + return QWidgetList(); + QWidgetList rc; + const QObjectList::const_iterator cend = children.constEnd(); + for (QObjectList::const_iterator it = children.constBegin(); it != cend; ++it) + if ((*it)->isWidgetType()) { + QWidget *w = qobject_cast(*it); + if (isManaged(w)) + rc.push_back(w); + } + return rc; +} + +int FormWindow::toolCount() const +{ + return m_widgetStack->count(); +} + +QDesignerFormWindowToolInterface *FormWindow::tool(int index) const +{ + return m_widgetStack->tool(index); +} + +void FormWindow::registerTool(QDesignerFormWindowToolInterface *tool) +{ + Q_ASSERT(tool != 0); + + m_widgetStack->addTool(tool); + + if (m_mainContainer) + m_mainContainer->update(); +} + +void FormWindow::setCurrentTool(int index) +{ + m_widgetStack->setCurrentTool(index); +} + +int FormWindow::currentTool() const +{ + return m_widgetStack->currentIndex(); +} + +bool FormWindow::handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event) +{ + if (m_widgetStack == 0) + return false; + + QDesignerFormWindowToolInterface *tool = m_widgetStack->currentTool(); + if (tool == 0) + return false; + + return tool->handleEvent(widget, managedWidget, event); +} + +void FormWindow::initializeCoreTools() +{ + m_widgetEditor = new WidgetEditorTool(this); + registerTool(m_widgetEditor); +} + +void FormWindow::checkSelection() +{ + m_checkSelectionTimer->start(0); +} + +void FormWindow::checkSelectionNow() +{ + m_checkSelectionTimer->stop(); + + foreach (QWidget *widget, selectedWidgets()) { + updateSelection(widget); + + if (LayoutInfo::layoutType(core(), widget) != LayoutInfo::NoLayout) + updateChildSelections(widget); + } +} + +QString FormWindow::author() const +{ + return m_author; +} + +QString FormWindow::comment() const +{ + return m_comment; +} + +void FormWindow::setAuthor(const QString &author) +{ + m_author = author; +} + +void FormWindow::setComment(const QString &comment) +{ + m_comment = comment; +} + +void FormWindow::editWidgets() +{ + m_widgetEditor->action()->trigger(); +} + +QStringList FormWindow::resourceFiles() const +{ + return m_resourceFiles; +} + +void FormWindow::addResourceFile(const QString &path) +{ + if (!m_resourceFiles.contains(path)) { + m_resourceFiles.append(path); + setDirty(true); + emit resourceFilesChanged(); + } +} + +void FormWindow::removeResourceFile(const QString &path) +{ + if (m_resourceFiles.removeAll(path) > 0) { + setDirty(true); + emit resourceFilesChanged(); + } +} + +bool FormWindow::blockSelectionChanged(bool b) +{ + const bool blocked = m_blockSelectionChanged; + m_blockSelectionChanged = b; + return blocked; +} + +void FormWindow::editContents() +{ + const QWidgetList sel = selectedWidgets(); + if (sel.count() == 1) { + QWidget *widget = sel.first(); + + if (QAction *a = preferredEditAction(core(), widget)) + a->trigger(); + } +} + +void FormWindow::dragWidgetWithinForm(QWidget *widget, const QRect &targetGeometry, QWidget *targetContainer) +{ + const bool fromLayout = canDragWidgetInLayout(core(), widget); + const QDesignerLayoutDecorationExtension *targetDeco = qt_extension(core()->extensionManager(), targetContainer); + const bool toLayout = targetDeco != 0; + + if (fromLayout) { + // Drag from Layout: We need to delete the widget properly to store the layout state + // Do not simplify the layout when dragging onto a layout + // as this might invalidate the insertion position if it is the same layout + DeleteWidgetCommand *cmd = new DeleteWidgetCommand(this); + unsigned deleteFlags = DeleteWidgetCommand::DoNotUnmanage; + if (toLayout) + deleteFlags |= DeleteWidgetCommand::DoNotSimplifyLayout; + cmd->init(widget, deleteFlags); + commandHistory()->push(cmd); + } + + if (toLayout) { + // Drag from form to layout: just insert. Do not manage + insertWidget(widget, targetGeometry, targetContainer, true); + } else { + // into container without layout + if (targetContainer != widget->parent()) { // different parent + ReparentWidgetCommand *cmd = new ReparentWidgetCommand(this); + cmd->init(widget, targetContainer ); + commandHistory()->push(cmd); + } + resizeWidget(widget, targetGeometry); + selectWidget(widget, true); + widget->show(); + } +} + +static Qt::DockWidgetArea detectDropArea(QMainWindow *mainWindow, const QRect &area, const QPoint &drop) +{ + QPoint offset = area.topLeft(); + QRect rect = area; + rect.moveTopLeft(QPoint(0, 0)); + QPoint point = drop - offset; + const int x = point.x(); + const int y = point.y(); + const int w = rect.width(); + const int h = rect.height(); + + if (rect.contains(point)) { + bool topRight = false; + bool topLeft = false; + if (w * y < h * x) // top and right, oterwise bottom and left + topRight = true; + if (w * y < h * (w - x)) // top and left, otherwise bottom and right + topLeft = true; + + if (topRight && topLeft) + return Qt::TopDockWidgetArea; + else if (topRight && !topLeft) + return Qt::RightDockWidgetArea; + else if (!topRight && topLeft) + return Qt::LeftDockWidgetArea; + return Qt::BottomDockWidgetArea; + } + + if (x < 0) { + if (y < 0) + return mainWindow->corner(Qt::TopLeftCorner); + else if (y > h) + return mainWindow->corner(Qt::BottomLeftCorner); + else + return Qt::LeftDockWidgetArea; + } else if (x > w) { + if (y < 0) + return mainWindow->corner(Qt::TopRightCorner); + else if (y > h) + return mainWindow->corner(Qt::BottomRightCorner); + else + return Qt::RightDockWidgetArea; + } else { + if (y < 0) + return Qt::TopDockWidgetArea; + else + return Qt::BottomDockWidgetArea; + } + return Qt::LeftDockWidgetArea; +} + +bool FormWindow::dropDockWidget(QDesignerDnDItemInterface *item, const QPoint &global_mouse_pos) +{ + DomUI *dom_ui = item->domUi(); + + QMainWindow *mw = qobject_cast(mainContainer()); + if (!mw) + return false; + + QDesignerResource resource(this); + const FormBuilderClipboard clipboard = resource.paste(dom_ui, mw); + if (clipboard.m_widgets.size() != 1) // multiple-paste from DomUI not supported yet + return false; + + QWidget *centralWidget = mw->centralWidget(); + QPoint localPos = centralWidget->mapFromGlobal(global_mouse_pos); + const QRect centralWidgetAreaRect = centralWidget->rect(); + Qt::DockWidgetArea area = detectDropArea(mw, centralWidgetAreaRect, localPos); + + beginCommand(tr("Drop widget")); + + clearSelection(false); + highlightWidget(mw, QPoint(0, 0), FormWindow::Restore); + + QWidget *widget = clipboard.m_widgets.first(); + + insertWidget(widget, QRect(0, 0, 1, 1), mw); + + selectWidget(widget, true); + mw->setFocus(Qt::MouseFocusReason); // in case focus was in e.g. object inspector + + core()->formWindowManager()->setActiveFormWindow(this); + mainContainer()->activateWindow(); + + QDesignerPropertySheetExtension *propertySheet = qobject_cast(m_core->extensionManager()->extension(widget, Q_TYPEID(QDesignerPropertySheetExtension))); + if (propertySheet) { + const QString dockWidgetAreaName = QLatin1String("dockWidgetArea"); + PropertySheetEnumValue e = qvariant_cast(propertySheet->property(propertySheet->indexOf(dockWidgetAreaName))); + e.value = area; + QVariant v; + v.setValue(e); + SetPropertyCommand *cmd = new SetPropertyCommand(this); + cmd->init(widget, dockWidgetAreaName, v); + m_undoStack.push(cmd); + } + + endCommand(); + return true; +} + +bool FormWindow::dropWidgets(const QList &item_list, QWidget *target, + const QPoint &global_mouse_pos) +{ + + QWidget *parent = target; + if (parent == 0) + parent = mainContainer(); + // You can only drop stuff onto the central widget of a QMainWindow + // ### generalize to use container extension + if (QMainWindow *main_win = qobject_cast(target)) { + if (!main_win->centralWidget()) { + designerWarning(tr("A QMainWindow-based form does not contain a central widget.")); + return false; + } + const QPoint main_win_pos = main_win->mapFromGlobal(global_mouse_pos); + const QRect central_wgt_geo = main_win->centralWidget()->geometry(); + if (!central_wgt_geo.contains(main_win_pos)) + return false; + } + + QWidget *container = findContainer(parent, false); + if (container == 0) + return false; + + beginCommand(tr("Drop widget")); + + clearSelection(false); + highlightWidget(target, target->mapFromGlobal(global_mouse_pos), FormWindow::Restore); + + QPoint offset; + QDesignerDnDItemInterface *current = 0; + QDesignerFormWindowCursorInterface *c = cursor(); + foreach (QDesignerDnDItemInterface *item, item_list) { + QWidget *w = item->widget(); + if (!current) + current = item; + if (c->current() == w) { + current = item; + break; + } + } + if (current) { + QRect geom = current->decoration()->geometry(); + QPoint topLeft = container->mapFromGlobal(geom.topLeft()); + offset = designerGrid().snapPoint(topLeft) - topLeft; + } + + foreach (QDesignerDnDItemInterface *item, item_list) { + DomUI *dom_ui = item->domUi(); + QRect geometry = item->decoration()->geometry(); + Q_ASSERT(dom_ui != 0); + + geometry.moveTopLeft(container->mapFromGlobal(geometry.topLeft()) + offset); + if (item->type() == QDesignerDnDItemInterface::CopyDrop) { // from widget box or CTRL + mouse move + QWidget *widget = createWidget(dom_ui, geometry, parent); + if (!widget) { + endCommand(); + return false; + } + selectWidget(widget, true); + mainContainer()->setFocus(Qt::MouseFocusReason); // in case focus was in e.g. object inspector + } else { // same form move + QWidget *widget = item->widget(); + Q_ASSERT(widget != 0); + QDesignerFormWindowInterface *dest = findFormWindow(widget); + if (dest == this) { + dragWidgetWithinForm(widget, geometry, container); + } else { // from other form + FormWindow *source = qobject_cast(item->source()); + Q_ASSERT(source != 0); + + source->deleteWidgetList(QWidgetList() << widget); + QWidget *new_widget = createWidget(dom_ui, geometry, parent); + + selectWidget(new_widget, true); + } + } + } + + core()->formWindowManager()->setActiveFormWindow(this); + mainContainer()->activateWindow(); + endCommand(); + return true; +} + +QDir FormWindow::absoluteDir() const +{ + if (fileName().isEmpty()) + return QDir::current(); + + return QFileInfo(fileName()).absoluteDir(); +} + +void FormWindow::layoutDefault(int *margin, int *spacing) +{ + *margin = m_defaultMargin; + *spacing = m_defaultSpacing; +} + +void FormWindow::setLayoutDefault(int margin, int spacing) +{ + m_defaultMargin = margin; + m_defaultSpacing = spacing; +} + +void FormWindow::layoutFunction(QString *margin, QString *spacing) +{ + *margin = m_marginFunction; + *spacing = m_spacingFunction; +} + +void FormWindow::setLayoutFunction(const QString &margin, const QString &spacing) +{ + m_marginFunction = margin; + m_spacingFunction = spacing; +} + +QString FormWindow::pixmapFunction() const +{ + return m_pixmapFunction; +} + +void FormWindow::setPixmapFunction(const QString &pixmapFunction) +{ + m_pixmapFunction = pixmapFunction; +} + +QStringList FormWindow::includeHints() const +{ + return m_includeHints; +} + +void FormWindow::setIncludeHints(const QStringList &includeHints) +{ + m_includeHints = includeHints; +} + +QString FormWindow::exportMacro() const +{ + return m_exportMacro; +} + +void FormWindow::setExportMacro(const QString &exportMacro) +{ + m_exportMacro = exportMacro; +} + +QEditorFormBuilder *FormWindow::createFormBuilder() +{ + return new QDesignerResource(this); +} + +QWidget *FormWindow::formContainer() const +{ + return m_widgetStack->formContainer(); +} + +QUndoStack *FormWindow::commandHistory() const +{ + return const_cast(m_undoStack).qundoStack(); +} + +} // namespace + +QT_END_NAMESPACE + diff --git a/src/designer/src/components/formeditor/formwindow.h b/src/designer/src/components/formeditor/formwindow.h new file mode 100644 index 000000000..ff862d863 --- /dev/null +++ b/src/designer/src/components/formeditor/formwindow.h @@ -0,0 +1,374 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FORMWINDOW_H +#define FORMWINDOW_H + +#include "formeditor_global.h" +#include "qdesignerundostack.h" +#include + +// Qt +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerDnDItemInterface; +class QDesignerTaskMenuExtension; +class DomConnections; + +class QWidget; +class QAction; +class QLabel; +class QTimer; +class QAction; +class QMenu; +class QRubberBand; + +namespace qdesigner_internal { + +class FormEditor; +class FormWindowCursor; +class WidgetEditorTool; +class FormWindowWidgetStack; +class FormWindowManager; +class FormWindowDnDItem; +class SetPropertyCommand; + +class QT_FORMEDITOR_EXPORT FormWindow: public FormWindowBase +{ + Q_OBJECT + +public: + explicit FormWindow(FormEditor *core, QWidget *parent = 0, Qt::WindowFlags flags = 0); + virtual ~FormWindow(); + + virtual QDesignerFormEditorInterface *core() const; + + virtual QDesignerFormWindowCursorInterface *cursor() const; + + // Overwritten: FormWindowBase + virtual QWidget *formContainer() const; + + virtual int toolCount() const; + virtual int currentTool() const; + virtual void setCurrentTool(int index); + virtual QDesignerFormWindowToolInterface *tool(int index) const; + virtual void registerTool(QDesignerFormWindowToolInterface *tool); + + virtual QString author() const; + virtual void setAuthor(const QString &author); + + virtual QString comment() const; + virtual void setComment(const QString &comment); + + virtual void layoutDefault(int *margin, int *spacing); + virtual void setLayoutDefault(int margin, int spacing); + + virtual void layoutFunction(QString *margin, QString *spacing); + virtual void setLayoutFunction(const QString &margin, const QString &spacing); + + virtual QString pixmapFunction() const; + virtual void setPixmapFunction(const QString &pixmapFunction); + + virtual QString exportMacro() const; + virtual void setExportMacro(const QString &exportMacro); + + virtual QStringList includeHints() const; + virtual void setIncludeHints(const QStringList &includeHints); + + virtual QString fileName() const; + virtual void setFileName(const QString &fileName); + + virtual QString contents() const; + virtual void setContents(const QString &contents); + virtual void setContents(QIODevice *dev); + + virtual QDir absoluteDir() const; + + virtual void simplifySelection(QWidgetList *sel) const; + + virtual void ensureUniqueObjectName(QObject *object); + + virtual QWidget *mainContainer() const; + void setMainContainer(QWidget *mainContainer); + bool isMainContainer(const QWidget *w) const; + + QWidget *currentWidget() const; + + bool hasInsertedChildren(QWidget *w) const; + + QList selectedWidgets() const; + void clearSelection(bool changePropertyDisplay=true); + bool isWidgetSelected(QWidget *w) const; + void selectWidget(QWidget *w, bool select=true); + + void selectWidgets(); + void repaintSelection(); + void updateSelection(QWidget *w); + void updateChildSelections(QWidget *w); + void raiseChildSelections(QWidget *w); + void raiseSelection(QWidget *w); + + inline const QList& widgets() const { return m_widgets; } + inline int widgetCount() const { return m_widgets.count(); } + inline QWidget *widgetAt(int index) const { return m_widgets.at(index); } + + QList widgets(QWidget *widget) const; + + QWidget *createWidget(DomUI *ui, const QRect &rect, QWidget *target); + + bool isManaged(QWidget *w) const; + + void manageWidget(QWidget *w); + void unmanageWidget(QWidget *w); + + virtual QUndoStack *commandHistory() const; + void beginCommand(const QString &description); + void endCommand(); + + virtual bool blockSelectionChanged(bool blocked); + virtual void emitSelectionChanged(); + + bool unify(QObject *w, QString &s, bool changeIt); + + bool isDirty() const; + void setDirty(bool dirty); + + static FormWindow *findFormWindow(QWidget *w); + + virtual QWidget *containerAt(const QPoint &pos); + virtual QWidget *widgetAt(const QPoint &pos); + virtual void highlightWidget(QWidget *w, const QPoint &pos, + HighlightMode mode = Highlight); + + void updateOrderIndicators(); + + bool handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event); + + QStringList resourceFiles() const; + void addResourceFile(const QString &path); + void removeResourceFile(const QString &path); + + void resizeWidget(QWidget *widget, const QRect &geometry); + + bool dropDockWidget(QDesignerDnDItemInterface *item, const QPoint &global_mouse_pos); + bool dropWidgets(const QList &item_list, QWidget *target, + const QPoint &global_mouse_pos); + + virtual QWidget *findContainer(QWidget *w, bool excludeLayout) const; + // for WidgetSelection only. + QWidget *designerWidget(QWidget *w) const; + + // Initialize and return a popup menu for a managed widget + QMenu *initializePopupMenu(QWidget *managedWidget); + + virtual void paste(PasteMode pasteMode); + virtual QEditorFormBuilder *createFormBuilder(); + + bool eventFilter(QObject *watched, QEvent *event); + +signals: + void contextMenuRequested(QMenu *menu, QWidget *widget); + +public slots: + void deleteWidgets(); + void raiseWidgets(); + void lowerWidgets(); + void copy(); + void cut(); + void paste(); + void selectAll(); + + void createLayout(int type, QWidget *container = 0); + void morphLayout(QWidget *container, int newType); + void breakLayout(QWidget *w); + + void editContents(); + +protected: + virtual QMenu *createPopupMenu(QWidget *w); + virtual void resizeEvent(QResizeEvent *e); + + void insertWidget(QWidget *w, const QRect &rect, QWidget *target, bool already_in_form = false); + +private slots: + void selectionChangedTimerDone(); + void checkSelection(); + void checkSelectionNow(); + void slotSelectWidget(QAction *); + +private: + enum MouseState { + NoMouseState, + // Double click received + MouseDoubleClicked, + // Drawing selection rubber band rectangle + MouseDrawRubber, + // Started a move operation + MouseMoveDrag, + // Click on a widget whose parent is selected. Defer selection to release + MouseDeferredSelection + }; + MouseState m_mouseState; + QPointer m_lastClickedWidget; + + void init(); + void initializeCoreTools(); + + int getValue(const QRect &rect, int key, bool size) const; + int calcValue(int val, bool forward, bool snap, int snapOffset) const; + void handleClickSelection(QWidget *managedWidget, unsigned mouseFlags); + + bool frameNeeded(QWidget *w) const; + + enum RectType { Insert, Rubber }; + + void startRectDraw(const QPoint &global, QWidget *, RectType t); + void continueRectDraw(const QPoint &global, QWidget *, RectType t); + void endRectDraw(); + + QWidget *containerAt(const QPoint &pos, QWidget *notParentOf); + + void checkPreviewGeometry(QRect &r); + + bool handleContextMenu(QWidget *widget, QWidget *managedWidget, QContextMenuEvent *e); + bool handleMouseButtonDblClickEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e); + bool handleMousePressEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e); + bool handleMouseMoveEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e); + bool handleMouseReleaseEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e); + bool handleKeyPressEvent(QWidget *widget, QWidget *managedWidget, QKeyEvent *e); + bool handleKeyReleaseEvent(QWidget *widget, QWidget *managedWidget, QKeyEvent *e); + + bool isCentralWidget(QWidget *w) const; + + bool setCurrentWidget(QWidget *currentWidget); + bool trySelectWidget(QWidget *w, bool select); + + void dragWidgetWithinForm(QWidget *widget, const QRect &targetGeometry, QWidget *targetContainer); + + void setCursorToAll(const QCursor &c, QWidget *start); + + QPoint mapToForm(const QWidget *w, const QPoint &pos) const; + bool canBeBuddy(QWidget *w) const; + + QWidget *findTargetContainer(QWidget *widget) const; + + void clearMainContainer(); + + static int widgetDepth(const QWidget *w); + static bool isChildOf(const QWidget *c, const QWidget *p); + + void editWidgets(); + + void updateWidgets(); + + void handleArrowKeyEvent(int key, Qt::KeyboardModifiers modifiers); + + void layoutSelection(int type); + void layoutContainer(QWidget *w, int type); + +private: + QWidget *innerContainer(QWidget *outerContainer) const; + QWidget *containerForPaste() const; + QAction *createSelectAncestorSubMenu(QWidget *w); + void selectSingleWidget(QWidget *w); + + FormEditor *m_core; + FormWindowCursor *m_cursor; + QWidget *m_mainContainer; + QWidget *m_currentWidget; + + bool m_blockSelectionChanged; + + QPoint m_rectAnchor; + QRect m_currRect; + + QWidgetList m_widgets; + QSet m_insertedWidgets; + + class Selection; + Selection *m_selection; + + QPoint m_startPos; + + QDesignerUndoStack m_undoStack; + + QString m_fileName; + + typedef QPair PaletteAndFill; + typedef QMap WidgetPaletteMap; + WidgetPaletteMap m_palettesBeforeHighlight; + + QRubberBand *m_rubberBand; + + QTimer *m_selectionChangedTimer; + QTimer *m_checkSelectionTimer; + QTimer *m_geometryChangedTimer; + + FormWindowWidgetStack *m_widgetStack; + WidgetEditorTool *m_widgetEditor; + + QStringList m_resourceFiles; + + QString m_comment; + QString m_author; + QString m_pixmapFunction; + int m_defaultMargin, m_defaultSpacing; + QString m_marginFunction, m_spacingFunction; + QString m_exportMacro; + QStringList m_includeHints; + + QPoint m_contextMenuPosition; + +private: + friend class WidgetEditorTool; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // FORMWINDOW_H diff --git a/src/designer/src/components/formeditor/formwindow_dnditem.cpp b/src/designer/src/components/formeditor/formwindow_dnditem.cpp new file mode 100644 index 000000000..5b8f86b0f --- /dev/null +++ b/src/designer/src/components/formeditor/formwindow_dnditem.cpp @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "formwindow_dnditem.h" +#include "formwindow.h" + +#include +#include +#include + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +static QWidget *decorationFromWidget(QWidget *w) +{ + QLabel *label = new QLabel(0, Qt::ToolTip); + QPixmap pm = QPixmap::grabWidget(w); + label->setPixmap(pm); + label->resize(pm.size()); + + return label; +} + +static DomUI *widgetToDom(QWidget *widget, FormWindow *form) +{ + QDesignerResource builder(form); + builder.setSaveRelative(false); + return builder.copy(FormBuilderClipboard(widget)); +} + +FormWindowDnDItem::FormWindowDnDItem(QDesignerDnDItemInterface::DropType type, FormWindow *form, + QWidget *widget, const QPoint &global_mouse_pos) + : QDesignerDnDItem(type, form) +{ + QWidget *decoration = decorationFromWidget(widget); + QPoint pos = widget->mapToGlobal(QPoint(0, 0)); + decoration->move(pos); + + init(0, widget, decoration, global_mouse_pos); +} + +DomUI *FormWindowDnDItem::domUi() const +{ + DomUI *result = QDesignerDnDItem::domUi(); + if (result != 0) + return result; + FormWindow *form = qobject_cast(source()); + if (widget() == 0 || form == 0) + return 0; + + QtResourceModel *resourceModel = form->core()->resourceModel(); + QtResourceSet *currentResourceSet = resourceModel->currentResourceSet(); + /* Short: + * We need to activate the original resourceSet associated with a form + * to properly generate the dom resource includes. + * Long: + * widgetToDom() calls copy() on QDesignerResource. It generates the + * Dom structure. In order to create DomResources properly we need to + * have the associated ResourceSet active (QDesignerResource::saveResources() + * queries the resource model for a qrc path for the given resource file: + * qrcFile = m_core->resourceModel()->qrcPath(ri->text()); + * This works only when the resource file comes from the active + * resourceSet */ + resourceModel->setCurrentResourceSet(form->resourceSet()); + + result = widgetToDom(widget(), form); + const_cast(this)->setDomUi(result); + resourceModel->setCurrentResourceSet(currentResourceSet); + return result; +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/formwindow_dnditem.h b/src/designer/src/components/formeditor/formwindow_dnditem.h new file mode 100644 index 000000000..4911c16b5 --- /dev/null +++ b/src/designer/src/components/formeditor/formwindow_dnditem.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FORMWINDOW_DNDITEM_H +#define FORMWINDOW_DNDITEM_H + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class FormWindow; + +class FormWindowDnDItem : public QDesignerDnDItem +{ +public: + FormWindowDnDItem(QDesignerDnDItemInterface::DropType type, FormWindow *form, + QWidget *widget, const QPoint &global_mouse_pos); + virtual DomUI *domUi() const; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // FORMWINDOW_DNDITEM_H diff --git a/src/designer/src/components/formeditor/formwindow_widgetstack.cpp b/src/designer/src/components/formeditor/formwindow_widgetstack.cpp new file mode 100644 index 000000000..ac20e8ac1 --- /dev/null +++ b/src/designer/src/components/formeditor/formwindow_widgetstack.cpp @@ -0,0 +1,217 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "formwindow_widgetstack.h" +#include + +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +FormWindowWidgetStack::FormWindowWidgetStack(QObject *parent) : + QObject(parent), + m_formContainer(new QWidget), + m_formContainerLayout(new QStackedLayout), + m_layout(new QStackedLayout) +{ + m_layout->setMargin(0); + m_layout->setSpacing(0); + m_layout->setStackingMode(QStackedLayout::StackAll); + + // We choose a QStackedLayout as immediate layout for + // the form windows as it ignores the sizePolicy of + // its child (for example, Fixed would cause undesired side effects). + m_formContainerLayout->setMargin(0); + m_formContainer->setObjectName(QLatin1String("formContainer")); + m_formContainer->setLayout(m_formContainerLayout); + m_formContainerLayout->setStackingMode(QStackedLayout::StackAll); + // System settings might have different background colors, autofill them + // (affects for example mainwindow status bars) + m_formContainer->setAutoFillBackground(true); +} + +FormWindowWidgetStack::~FormWindowWidgetStack() +{ +} + +int FormWindowWidgetStack::count() const +{ + return m_tools.count(); +} + +QDesignerFormWindowToolInterface *FormWindowWidgetStack::currentTool() const +{ + return tool(currentIndex()); +} + +void FormWindowWidgetStack::setCurrentTool(int index) +{ + const int cnt = count(); + if (index < 0 || index >= cnt) { + qDebug("FormWindowWidgetStack::setCurrentTool(): invalid index: %d", index); + return; + } + + const int cur = currentIndex(); + if (index == cur) + return; + + if (cur != -1) + m_tools.at(cur)->deactivated(); + + + m_layout->setCurrentIndex(index); + // Show the widget editor and the current tool + for (int i = 0; i < cnt; i++) + m_tools.at(i)->editor()->setVisible(i == 0 || i == index); + + QDesignerFormWindowToolInterface *tool = m_tools.at(index); + tool->activated(); + + emit currentToolChanged(index); +} + +void FormWindowWidgetStack::setSenderAsCurrentTool() +{ + QDesignerFormWindowToolInterface *tool = 0; + QAction *action = qobject_cast(sender()); + if (action == 0) { + qDebug("FormWindowWidgetStack::setSenderAsCurrentTool(): sender is not a QAction"); + return; + } + + foreach (QDesignerFormWindowToolInterface *t, m_tools) { + if (action == t->action()) { + tool = t; + break; + } + } + + if (tool == 0) { + qDebug("FormWindowWidgetStack::setSenderAsCurrentTool(): unknown tool"); + return; + } + + setCurrentTool(tool); +} + +int FormWindowWidgetStack::indexOf(QDesignerFormWindowToolInterface *tool) const +{ + return m_tools.indexOf(tool); +} + +void FormWindowWidgetStack::setCurrentTool(QDesignerFormWindowToolInterface *tool) +{ + int index = indexOf(tool); + if (index == -1) { + qDebug("FormWindowWidgetStack::setCurrentTool(): unknown tool"); + return; + } + + setCurrentTool(index); +} + +void FormWindowWidgetStack::setMainContainer(QWidget *w) +{ + // This code is triggered once by the formwindow and + // by integrations doing "revert to saved". Anything changing? + const int previousCount = m_formContainerLayout->count(); + QWidget *previousMainContainer = previousCount ? m_formContainerLayout->itemAt(0)->widget() : static_cast(0); + if (previousMainContainer == w) + return; + // Swap + if (previousCount) + delete m_formContainerLayout->takeAt(0); + if (w) + m_formContainerLayout->addWidget(w); +} + +void FormWindowWidgetStack::addTool(QDesignerFormWindowToolInterface *tool) +{ + if (QWidget *w = tool->editor()) { + w->setVisible(m_layout->count() == 0); // Initially only form editor is visible + m_layout->addWidget(w); + } else { + // The form editor might not have a tool initially, use dummy. Assert on anything else + Q_ASSERT(m_tools.empty()); + m_layout->addWidget(m_formContainer); + } + + m_tools.append(tool); + + connect(tool->action(), SIGNAL(triggered()), this, SLOT(setSenderAsCurrentTool())); +} + +QDesignerFormWindowToolInterface *FormWindowWidgetStack::tool(int index) const +{ + if (index < 0 || index >= count()) + return 0; + + return m_tools.at(index); +} + +int FormWindowWidgetStack::currentIndex() const +{ + return m_layout->currentIndex(); +} + +QWidget *FormWindowWidgetStack::defaultEditor() const +{ + if (m_tools.isEmpty()) + return 0; + + return m_tools.at(0)->editor(); +} + +QLayout *FormWindowWidgetStack::layout() const +{ + return m_layout; +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/formwindow_widgetstack.h b/src/designer/src/components/formeditor/formwindow_widgetstack.h new file mode 100644 index 000000000..56f9743bb --- /dev/null +++ b/src/designer/src/components/formeditor/formwindow_widgetstack.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FORMWINDOW_WIDGETSTACK_H +#define FORMWINDOW_WIDGETSTACK_H + +#include "formeditor_global.h" + +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowToolInterface; + +class QStackedLayout; +class QWidget; + +namespace qdesigner_internal { + +class QT_FORMEDITOR_EXPORT FormWindowWidgetStack: public QObject +{ + Q_OBJECT +public: + FormWindowWidgetStack(QObject *parent = 0); + virtual ~FormWindowWidgetStack(); + + QLayout *layout() const; + + int count() const; + QDesignerFormWindowToolInterface *tool(int index) const; + QDesignerFormWindowToolInterface *currentTool() const; + int currentIndex() const; + int indexOf(QDesignerFormWindowToolInterface *tool) const; + + void setMainContainer(QWidget *w = 0); + + // Return the widget containing the form which can be used to apply embedded design settings to. + // These settings should not affect the other editing tools. + QWidget *formContainer() const { return m_formContainer; } + +signals: + void currentToolChanged(int index); + +public slots: + void addTool(QDesignerFormWindowToolInterface *tool); + void setCurrentTool(QDesignerFormWindowToolInterface *tool); + void setCurrentTool(int index); + void setSenderAsCurrentTool(); + +protected: + QWidget *defaultEditor() const; + +private: + QList m_tools; + QWidget *m_formContainer; + QStackedLayout *m_formContainerLayout; + QStackedLayout *m_layout; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // FORMWINDOW_WIDGETSTACK_H diff --git a/src/designer/src/components/formeditor/formwindowcursor.cpp b/src/designer/src/components/formeditor/formwindowcursor.cpp new file mode 100644 index 000000000..51d563001 --- /dev/null +++ b/src/designer/src/components/formeditor/formwindowcursor.cpp @@ -0,0 +1,211 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "formwindowcursor.h" +#include "formwindow.h" + +// sdk +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +FormWindowCursor::FormWindowCursor(FormWindow *fw, QObject *parent) + : QObject(parent), + m_formWindow(fw) +{ + update(); + connect(fw, SIGNAL(changed()), this, SLOT(update())); +} + +FormWindowCursor::~FormWindowCursor() +{ +} + +QDesignerFormWindowInterface *FormWindowCursor::formWindow() const +{ + return m_formWindow; +} + +bool FormWindowCursor::movePosition(MoveOperation op, MoveMode mode) +{ + if (widgetCount() == 0) + return false; + + int iterator = position(); + + if (mode == MoveAnchor) + m_formWindow->clearSelection(false); + + switch (op) { + case Next: + ++iterator; + if (iterator >= widgetCount()) + iterator = 0; + + m_formWindow->selectWidget(m_formWindow->widgetAt(iterator), true); + return true; + + case Prev: + --iterator; + if (iterator < 0) + iterator = widgetCount() - 1; + + if (iterator < 0) + return false; + + m_formWindow->selectWidget(m_formWindow->widgetAt(iterator), true); + return true; + + default: + return false; + } +} + +int FormWindowCursor::position() const +{ + const int index = m_formWindow->widgets().indexOf(current()); + return index == -1 ? 0 : index; +} + +void FormWindowCursor::setPosition(int pos, MoveMode mode) +{ + if (!widgetCount()) + return; + + if (mode == MoveAnchor) + m_formWindow->clearSelection(false); + + if (pos >= widgetCount()) + pos = 0; + + m_formWindow->selectWidget(m_formWindow->widgetAt(pos), true); +} + +QWidget *FormWindowCursor::current() const +{ + return m_formWindow->currentWidget(); +} + +bool FormWindowCursor::hasSelection() const +{ + return !m_formWindow->selectedWidgets().isEmpty(); +} + +int FormWindowCursor::selectedWidgetCount() const +{ + int N = m_formWindow->selectedWidgets().count(); + return N ? N : 1; +} + +QWidget *FormWindowCursor::selectedWidget(int index) const +{ + return hasSelection() + ? m_formWindow->selectedWidgets().at(index) + : m_formWindow->mainContainer(); +} + +void FormWindowCursor::update() +{ + // ### todo +} + +int FormWindowCursor::widgetCount() const +{ + return m_formWindow->widgetCount(); +} + +QWidget *FormWindowCursor::widget(int index) const +{ + return m_formWindow->widgetAt(index); +} + +void FormWindowCursor::setProperty(const QString &name, const QVariant &value) +{ + + // build selection + const int N = selectedWidgetCount(); + Q_ASSERT(N); + + SetPropertyCommand::ObjectList selection; + for (int i=0; iinit(selection, name, value, current())) { + m_formWindow->commandHistory()->push(setPropertyCommand); + } else { + delete setPropertyCommand; + qDebug() << "Unable to set property " << name << '.'; + } +} + +void FormWindowCursor::setWidgetProperty(QWidget *widget, const QString &name, const QVariant &value) +{ + SetPropertyCommand *cmd = new SetPropertyCommand(m_formWindow); + if (cmd->init(widget, name, value)) { + m_formWindow->commandHistory()->push(cmd); + } else { + delete cmd; + qDebug() << "Unable to set property " << name << '.'; + } +} + +void FormWindowCursor::resetWidgetProperty(QWidget *widget, const QString &name) +{ + ResetPropertyCommand *cmd = new ResetPropertyCommand(m_formWindow); + if (cmd->init(widget, name)) { + m_formWindow->commandHistory()->push(cmd); + } else { + delete cmd; + qDebug() << "Unable to reset property " << name << '.'; + } +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/formwindowcursor.h b/src/designer/src/components/formeditor/formwindowcursor.h new file mode 100644 index 000000000..797aab446 --- /dev/null +++ b/src/designer/src/components/formeditor/formwindowcursor.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FORMWINDOWCURSOR_H +#define FORMWINDOWCURSOR_H + +#include "formeditor_global.h" +#include "formwindow.h" +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QT_FORMEDITOR_EXPORT FormWindowCursor: public QObject, public QDesignerFormWindowCursorInterface +{ + Q_OBJECT +public: + explicit FormWindowCursor(FormWindow *fw, QObject *parent = 0); + virtual ~FormWindowCursor(); + + virtual QDesignerFormWindowInterface *formWindow() const; + + virtual bool movePosition(MoveOperation op, MoveMode mode); + + virtual int position() const; + virtual void setPosition(int pos, MoveMode mode); + + virtual QWidget *current() const; + + virtual int widgetCount() const; + virtual QWidget *widget(int index) const; + + virtual bool hasSelection() const; + virtual int selectedWidgetCount() const; + virtual QWidget *selectedWidget(int index) const; + + virtual void setProperty(const QString &name, const QVariant &value); + virtual void setWidgetProperty(QWidget *widget, const QString &name, const QVariant &value); + virtual void resetWidgetProperty(QWidget *widget, const QString &name); + +public slots: + void update(); + +private: + FormWindow *m_formWindow; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // FORMWINDOWCURSOR_H diff --git a/src/designer/src/components/formeditor/formwindowmanager.cpp b/src/designer/src/components/formeditor/formwindowmanager.cpp new file mode 100644 index 000000000..1d662b27c --- /dev/null +++ b/src/designer/src/components/formeditor/formwindowmanager.cpp @@ -0,0 +1,1036 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// components/formeditor +#include "formwindowmanager.h" +#include "formwindow_dnditem.h" +#include "formwindow.h" +#include "formeditor.h" +#include "widgetselection.h" +#include "previewactiongroup.h" +#include "formwindowsettings.h" + +// shared +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// SDK +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace { + enum { debugFWM = 0 }; +} + +static inline QString whatsThisFrom(const QString &str) { /// ### implement me! + return str; +} + +// find the first child of w in a sequence +template +static inline Iterator findFirstChildOf(Iterator it,Iterator end, const QWidget *w) +{ + for (;it != end; ++it) { + if (w->isAncestorOf(*it)) + return it; + } + return it; +} + +namespace qdesigner_internal { + +FormWindowManager::FormWindowManager(QDesignerFormEditorInterface *core, QObject *parent) : + QDesignerFormWindowManager(parent), + m_core(core), + m_activeFormWindow(0), + m_previewManager(new PreviewManager(PreviewManager::SingleFormNonModalPreview, this)), + m_createLayoutContext(LayoutContainer), + m_morphLayoutContainer(0), + m_actionGroupPreviewInStyle(0), + m_actionShowFormWindowSettingsDialog(0) +{ + setupActions(); + qApp->installEventFilter(this); +} + +FormWindowManager::~FormWindowManager() +{ + qDeleteAll(m_formWindows); +} + +QDesignerFormEditorInterface *FormWindowManager::core() const +{ + return m_core; +} + +QDesignerFormWindowInterface *FormWindowManager::activeFormWindow() const +{ + return m_activeFormWindow; +} + +int FormWindowManager::formWindowCount() const +{ + return m_formWindows.size(); +} + +QDesignerFormWindowInterface *FormWindowManager::formWindow(int index) const +{ + return m_formWindows.at(index); +} + +bool FormWindowManager::eventFilter(QObject *o, QEvent *e) +{ + if (!o->isWidgetType()) + return false; + + // If we don't have an active form, we only listen for WindowActivate to speed up integrations + const QEvent::Type eventType = e->type(); + if (m_activeFormWindow == 0 && eventType != QEvent::WindowActivate) + return false; + + switch (eventType) { // Uninteresting events + case QEvent::Create: + case QEvent::Destroy: + case QEvent::AccessibilityDescription: + case QEvent::AccessibilityHelp: + case QEvent::AccessibilityPrepare: + case QEvent::ActionAdded: + case QEvent::ActionChanged: + case QEvent::ActionRemoved: + case QEvent::ChildAdded: + case QEvent::ChildPolished: + case QEvent::ChildRemoved: + case QEvent::Clipboard: + case QEvent::ContentsRectChange: + case QEvent::DeferredDelete: + case QEvent::FileOpen: + case QEvent::LanguageChange: + case QEvent::MetaCall: + case QEvent::ModifiedChange: + case QEvent::Paint: + case QEvent::PaletteChange: + case QEvent::ParentAboutToChange: + case QEvent::ParentChange: + case QEvent::Polish: + case QEvent::PolishRequest: + case QEvent::QueryWhatsThis: + case QEvent::StatusTip: + case QEvent::StyleChange: + case QEvent::Timer: + case QEvent::ToolBarChange: + case QEvent::ToolTip: + case QEvent::WhatsThis: + case QEvent::WhatsThisClicked: + case QEvent::WinIdChange: + case QEvent::DynamicPropertyChange: + case QEvent::HoverEnter: + case QEvent::HoverLeave: + case QEvent::HoverMove: + case QEvent::AcceptDropsChange: + return false; + default: + break; + } + + QWidget *widget = static_cast(o); + + if (qobject_cast(widget)) { // ### remove me + return false; + } + + FormWindow *fw = FormWindow::findFormWindow(widget); + if (fw == 0) { + return false; + } + + if (QWidget *managedWidget = findManagedWidget(fw, widget)) { + // Prevent MDI and QWorkspace subwindows from being closed by clicking at the title bar + if (managedWidget != widget && eventType == QEvent::Close) { + e->ignore(); + return true; + } + switch (eventType) { + + case QEvent::WindowActivate: { + if (fw->parentWidget()->isWindow() && fw->isMainContainer(managedWidget) && activeFormWindow() != fw) { + setActiveFormWindow(fw); + } + } break; + + case QEvent::WindowDeactivate: { + if (o == fw && o == activeFormWindow()) + fw->repaintSelection(); + } break; + + case QEvent::KeyPress: { + QKeyEvent *ke = static_cast(e); + if (ke->key() == Qt::Key_Escape) { + ke->accept(); + return true; + } + } + // don't break... + // Embedded Design: Drop on different form: Make sure the right form + // window/device is active before having the widget created by the factory + case QEvent::Drop: + if (activeFormWindow() != fw) + setActiveFormWindow(fw); + // don't break... + default: { + if (fw->handleEvent(widget, managedWidget, e)) { + return true; + } + } break; + + } // end switch + } + + return false; +} + +void FormWindowManager::addFormWindow(QDesignerFormWindowInterface *w) +{ + FormWindow *formWindow = qobject_cast(w); + if (!formWindow || m_formWindows.contains(formWindow)) + return; + + connect(formWindow, SIGNAL(selectionChanged()), this, SLOT(slotUpdateActions())); + connect(formWindow->commandHistory(), SIGNAL(indexChanged(int)), this, SLOT(slotUpdateActions())); + connect(formWindow, SIGNAL(toolChanged(int)), this, SLOT(slotUpdateActions())); + + if (ActionEditor *ae = qobject_cast(m_core->actionEditor())) + connect(w, SIGNAL(mainContainerChanged(QWidget*)), ae, SLOT(mainContainerChanged())); + if (QDesignerObjectInspector *oi = qobject_cast(m_core->objectInspector())) + connect(w, SIGNAL(mainContainerChanged(QWidget*)), oi, SLOT(mainContainerChanged())); + + m_formWindows.append(formWindow); + emit formWindowAdded(formWindow); +} + +void FormWindowManager::removeFormWindow(QDesignerFormWindowInterface *w) +{ + FormWindow *formWindow = qobject_cast(w); + + int idx = m_formWindows.indexOf(formWindow); + if (!formWindow || idx == -1) + return; + + formWindow->disconnect(this); + m_formWindows.removeAt(idx); + emit formWindowRemoved(formWindow); + + if (formWindow == m_activeFormWindow) + setActiveFormWindow(0); + + if (m_formWindows.size() == 0 + && m_core->widgetBox()) { + // Make sure that widget box is enabled by default + m_core->widgetBox()->setEnabled(true); + } + +} + +void FormWindowManager::setActiveFormWindow(QDesignerFormWindowInterface *w) +{ + FormWindow *formWindow = qobject_cast(w); + + if (formWindow == m_activeFormWindow) + return; + + FormWindow *old = m_activeFormWindow; + + m_activeFormWindow = formWindow; + + QtResourceSet *resourceSet = 0; + if (formWindow) + resourceSet = formWindow->resourceSet(); + m_core->resourceModel()->setCurrentResourceSet(resourceSet); + + slotUpdateActions(); + + if (m_activeFormWindow) { + m_activeFormWindow->repaintSelection(); + if (old) + old->repaintSelection(); + } + + emit activeFormWindowChanged(m_activeFormWindow); + + if (m_activeFormWindow) { + m_activeFormWindow->emitSelectionChanged(); + m_activeFormWindow->commandHistory()->setActive(); + // Trigger setActiveSubWindow on mdi area unless we are in toplevel mode + QMdiSubWindow *mdiSubWindow = 0; + if (QWidget *formwindow = m_activeFormWindow->parentWidget()) { + mdiSubWindow = qobject_cast(formwindow->parentWidget()); + } + if (mdiSubWindow) { + for (QWidget *parent = mdiSubWindow->parentWidget(); parent; parent = parent->parentWidget()) { + if (QMdiArea *mdiArea = qobject_cast(parent)) { + mdiArea->setActiveSubWindow(mdiSubWindow); + break; + } + } + } + } +} + +void FormWindowManager::closeAllPreviews() +{ + m_previewManager->closeAllPreviews(); +} + +QWidget *FormWindowManager::findManagedWidget(FormWindow *fw, QWidget *w) +{ + while (w && w != fw) { + if (fw->isManaged(w)) + break; + w = w->parentWidget(); + } + return w; +} + +void FormWindowManager::setupActions() +{ + m_actionCut = new QAction(createIconSet(QLatin1String("editcut.png")), tr("Cu&t"), this); + m_actionCut->setObjectName(QLatin1String("__qt_cut_action")); + m_actionCut->setShortcut(QKeySequence::Cut); + m_actionCut->setStatusTip(tr("Cuts the selected widgets and puts them on the clipboard")); + m_actionCut->setWhatsThis(whatsThisFrom(QLatin1String("Edit|Cut"))); + connect(m_actionCut, SIGNAL(triggered()), this, SLOT(slotActionCutActivated())); + m_actionCut->setEnabled(false); + + m_actionCopy = new QAction(createIconSet(QLatin1String("editcopy.png")), tr("&Copy"), this); + m_actionCopy->setObjectName(QLatin1String("__qt_copy_action")); + m_actionCopy->setShortcut(QKeySequence::Copy); + m_actionCopy->setStatusTip(tr("Copies the selected widgets to the clipboard")); + m_actionCopy->setWhatsThis(whatsThisFrom(QLatin1String("Edit|Copy"))); + connect(m_actionCopy, SIGNAL(triggered()), this, SLOT(slotActionCopyActivated())); + m_actionCopy->setEnabled(false); + + m_actionPaste = new QAction(createIconSet(QLatin1String("editpaste.png")), tr("&Paste"), this); + m_actionPaste->setObjectName(QLatin1String("__qt_paste_action")); + m_actionPaste->setShortcut(QKeySequence::Paste); + m_actionPaste->setStatusTip(tr("Pastes the clipboard's contents")); + m_actionPaste->setWhatsThis(whatsThisFrom(QLatin1String("Edit|Paste"))); + connect(m_actionPaste, SIGNAL(triggered()), this, SLOT(slotActionPasteActivated())); + m_actionPaste->setEnabled(false); + + m_actionDelete = new QAction(tr("&Delete"), this); + m_actionDelete->setObjectName(QLatin1String("__qt_delete_action")); + m_actionDelete->setStatusTip(tr("Deletes the selected widgets")); + m_actionDelete->setWhatsThis(whatsThisFrom(QLatin1String("Edit|Delete"))); + connect(m_actionDelete, SIGNAL(triggered()), this, SLOT(slotActionDeleteActivated())); + m_actionDelete->setEnabled(false); + + m_actionSelectAll = new QAction(tr("Select &All"), this); + m_actionSelectAll->setObjectName(QLatin1String("__qt_select_all_action")); + m_actionSelectAll->setShortcut(QKeySequence::SelectAll); + m_actionSelectAll->setStatusTip(tr("Selects all widgets")); + m_actionSelectAll->setWhatsThis(whatsThisFrom(QLatin1String("Edit|Select All"))); + connect(m_actionSelectAll, SIGNAL(triggered()), this, SLOT(slotActionSelectAllActivated())); + m_actionSelectAll->setEnabled(false); + + m_actionRaise = new QAction(createIconSet(QLatin1String("editraise.png")), tr("Bring to &Front"), this); + m_actionRaise->setObjectName(QLatin1String("__qt_raise_action")); + m_actionRaise->setShortcut(Qt::CTRL + Qt::Key_L); + m_actionRaise->setStatusTip(tr("Raises the selected widgets")); + m_actionRaise->setWhatsThis(tr("Raises the selected widgets")); + connect(m_actionRaise, SIGNAL(triggered()), this, SLOT(slotActionRaiseActivated())); + m_actionRaise->setEnabled(false); + + m_actionLower = new QAction(createIconSet(QLatin1String("editlower.png")), tr("Send to &Back"), this); + m_actionLower->setObjectName(QLatin1String("__qt_lower_action")); + m_actionLower->setShortcut(Qt::CTRL + Qt::Key_K); + m_actionLower->setStatusTip(tr("Lowers the selected widgets")); + m_actionLower->setWhatsThis(tr("Lowers the selected widgets")); + connect(m_actionLower, SIGNAL(triggered()), this, SLOT(slotActionLowerActivated())); + m_actionLower->setEnabled(false); + + m_actionAdjustSize = new QAction(createIconSet(QLatin1String("adjustsize.png")), tr("Adjust &Size"), this); + m_actionAdjustSize->setObjectName(QLatin1String("__qt_adjust_size_action")); + m_actionAdjustSize->setShortcut(Qt::CTRL + Qt::Key_J); + m_actionAdjustSize->setStatusTip(tr("Adjusts the size of the selected widget")); + m_actionAdjustSize->setWhatsThis(whatsThisFrom(QLatin1String("Layout|Adjust Size"))); + connect(m_actionAdjustSize, SIGNAL(triggered()), this, SLOT(slotActionAdjustSizeActivated())); + m_actionAdjustSize->setEnabled(false); + + + m_actionHorizontalLayout = new QAction(createIconSet(QLatin1String("edithlayout.png")), tr("Lay Out &Horizontally"), this); + m_actionHorizontalLayout->setObjectName(QLatin1String("__qt_horizontal_layout_action")); + m_actionHorizontalLayout->setShortcut(Qt::CTRL + Qt::Key_1); + m_actionHorizontalLayout->setStatusTip(tr("Lays out the selected widgets horizontally")); + m_actionHorizontalLayout->setWhatsThis(whatsThisFrom(QLatin1String("Layout|Lay Out Horizontally"))); + m_actionHorizontalLayout->setData(LayoutInfo::HBox); + m_actionHorizontalLayout->setEnabled(false); + connect(m_actionHorizontalLayout, SIGNAL(triggered()), this, SLOT(createLayout())); + + m_actionVerticalLayout = new QAction(createIconSet(QLatin1String("editvlayout.png")), tr("Lay Out &Vertically"), this); + m_actionVerticalLayout->setObjectName(QLatin1String("__qt_vertical_layout_action")); + m_actionVerticalLayout->setShortcut(Qt::CTRL + Qt::Key_2); + m_actionVerticalLayout->setStatusTip(tr("Lays out the selected widgets vertically")); + m_actionVerticalLayout->setWhatsThis(whatsThisFrom(QLatin1String("Layout|Lay Out Vertically"))); + m_actionVerticalLayout->setData(LayoutInfo::VBox); + m_actionVerticalLayout->setEnabled(false); + connect(m_actionVerticalLayout, SIGNAL(triggered()), this, SLOT(createLayout())); + + QIcon formIcon = QIcon::fromTheme("designer-form-layout", createIconSet(QLatin1String("editform.png"))); + QAction *actionFormLayout = new QAction(formIcon, tr("Lay Out in a &Form Layout"), this); + actionFormLayout->setObjectName(QLatin1String("__qt_form_layout_action")); + actionFormLayout->setShortcut(Qt::CTRL + Qt::Key_6); + actionFormLayout->setStatusTip(tr("Lays out the selected widgets in a form layout")); + actionFormLayout->setWhatsThis(whatsThisFrom(QLatin1String("Layout|Lay Out in a Form"))); + actionFormLayout->setData(LayoutInfo::Form); + actionFormLayout->setEnabled(false); + setActionFormLayout(actionFormLayout); + connect(actionFormLayout, SIGNAL(triggered()), this, SLOT(createLayout())); + + m_actionGridLayout = new QAction(createIconSet(QLatin1String("editgrid.png")), tr("Lay Out in a &Grid"), this); + m_actionGridLayout->setObjectName(QLatin1String("__qt_grid_layout_action")); + m_actionGridLayout->setShortcut(Qt::CTRL + Qt::Key_5); + m_actionGridLayout->setStatusTip(tr("Lays out the selected widgets in a grid")); + m_actionGridLayout->setWhatsThis(whatsThisFrom(QLatin1String("Layout|Lay Out in a Grid"))); + m_actionGridLayout->setData(LayoutInfo::Grid); + m_actionGridLayout->setEnabled(false); + connect(m_actionGridLayout, SIGNAL(triggered()), this, SLOT(createLayout())); + + m_actionSplitHorizontal = new QAction(createIconSet(QLatin1String("edithlayoutsplit.png")), + tr("Lay Out Horizontally in S&plitter"), this); + m_actionSplitHorizontal->setObjectName(QLatin1String("__qt_split_horizontal_action")); + m_actionSplitHorizontal->setShortcut(Qt::CTRL + Qt::Key_3); + m_actionSplitHorizontal->setStatusTip(tr("Lays out the selected widgets horizontally in a splitter")); + m_actionSplitHorizontal->setWhatsThis(whatsThisFrom(QLatin1String("Layout|Lay Out Horizontally in Splitter"))); + m_actionSplitHorizontal->setData(LayoutInfo::HSplitter); + m_actionSplitHorizontal->setEnabled(false); + connect(m_actionSplitHorizontal, SIGNAL(triggered()), this, SLOT(createLayout())); + + m_actionSplitVertical = new QAction(createIconSet(QLatin1String("editvlayoutsplit.png")), + tr("Lay Out Vertically in Sp&litter"), this); + m_actionSplitVertical->setObjectName(QLatin1String("__qt_split_vertical_action")); + m_actionSplitVertical->setShortcut(Qt::CTRL + Qt::Key_4); + m_actionSplitVertical->setStatusTip(tr("Lays out the selected widgets vertically in a splitter")); + m_actionSplitVertical->setWhatsThis(whatsThisFrom(QLatin1String("Layout|Lay Out Vertically in Splitter"))); + connect(m_actionSplitVertical, SIGNAL(triggered()), this, SLOT(createLayout())); + m_actionSplitVertical->setData(LayoutInfo::VSplitter); + + m_actionSplitVertical->setEnabled(false); + + m_actionBreakLayout = new QAction(createIconSet(QLatin1String("editbreaklayout.png")), tr("&Break Layout"), this); + m_actionBreakLayout->setObjectName(QLatin1String("__qt_break_layout_action")); + m_actionBreakLayout->setShortcut(Qt::CTRL + Qt::Key_0); + m_actionBreakLayout->setStatusTip(tr("Breaks the selected layout")); + m_actionBreakLayout->setWhatsThis(whatsThisFrom(QLatin1String("Layout|Break Layout"))); + connect(m_actionBreakLayout, SIGNAL(triggered()), this, SLOT(slotActionBreakLayoutActivated())); + m_actionBreakLayout->setEnabled(false); + + QAction *simplifyLayoutAction = new QAction(tr("Si&mplify Grid Layout"), this); + simplifyLayoutAction->setObjectName(QLatin1String("__qt_simplify_layout_action")); + simplifyLayoutAction->setStatusTip(tr("Removes empty columns and rows")); + simplifyLayoutAction->setWhatsThis(whatsThisFrom(QLatin1String("Layout|Simplify Layout"))); + connect(simplifyLayoutAction, SIGNAL(triggered()), this, SLOT(slotActionSimplifyLayoutActivated())); + simplifyLayoutAction->setEnabled(false); + setActionSimplifyLayout(simplifyLayoutAction); + + m_actionDefaultPreview = new QAction(tr("&Preview..."), this); + m_actionDefaultPreview->setObjectName(QLatin1String("__qt_default_preview_action")); + m_actionDefaultPreview->setStatusTip(tr("Preview current form")); + m_actionDefaultPreview->setWhatsThis(whatsThisFrom(QLatin1String("Form|Preview"))); + connect(m_actionDefaultPreview, SIGNAL(triggered()), + this, SLOT(slotActionDefaultPreviewActivated())); + + m_undoGroup = new QUndoGroup(this); + + m_actionUndo = m_undoGroup->createUndoAction(this); + m_actionUndo->setEnabled(false); + + m_actionUndo->setIcon(QIcon::fromTheme("edit-undo", createIconSet(QLatin1String("undo.png")))); + m_actionRedo = m_undoGroup->createRedoAction(this); + m_actionRedo->setEnabled(false); + m_actionRedo->setIcon(QIcon::fromTheme("edit-redo", createIconSet(QLatin1String("redo.png")))); + + m_actionShowFormWindowSettingsDialog = new QAction(tr("Form &Settings..."), this); + m_actionShowFormWindowSettingsDialog->setObjectName(QLatin1String("__qt_form_settings_action")); + connect(m_actionShowFormWindowSettingsDialog, SIGNAL(triggered()), this, SLOT(slotActionShowFormWindowSettingsDialog())); + m_actionShowFormWindowSettingsDialog->setEnabled(false); + +#ifdef Q_WS_X11 + m_actionCopy->setIcon(QIcon::fromTheme("edit-copy", m_actionCopy->icon())); + m_actionCut->setIcon(QIcon::fromTheme("edit-cut", m_actionCut->icon())); + m_actionPaste->setIcon(QIcon::fromTheme("edit-paste", m_actionPaste->icon())); + m_actionDelete->setIcon(QIcon::fromTheme("edit-delete", m_actionDelete->icon())); + + // These do not currently exist, but will allow theme authors to fill in the gaps + m_actionBreakLayout->setIcon(QIcon::fromTheme("designer-break-layout", m_actionBreakLayout->icon())); + m_actionGridLayout->setIcon(QIcon::fromTheme("designer-grid-layout", m_actionGridLayout->icon())); + m_actionHorizontalLayout->setIcon(QIcon::fromTheme("designer-horizontal-layout", m_actionHorizontalLayout->icon())); + m_actionVerticalLayout->setIcon(QIcon::fromTheme("designer-vertical-layout", m_actionVerticalLayout->icon())); + m_actionSplitHorizontal->setIcon(QIcon::fromTheme("designer-split-horizontal", m_actionSplitHorizontal->icon())); + m_actionSplitVertical->setIcon(QIcon::fromTheme("designer-split-vertical", m_actionSplitVertical->icon())); + m_actionAdjustSize->setIcon(QIcon::fromTheme("designer-adjust-size", m_actionAdjustSize->icon())); +#endif +} + +void FormWindowManager::slotActionCutActivated() +{ + m_activeFormWindow->cut(); +} + +void FormWindowManager::slotActionCopyActivated() +{ + m_activeFormWindow->copy(); + slotUpdateActions(); +} + +void FormWindowManager::slotActionPasteActivated() +{ + m_activeFormWindow->paste(); +} + +void FormWindowManager::slotActionDeleteActivated() +{ + m_activeFormWindow->deleteWidgets(); +} + +void FormWindowManager::slotActionLowerActivated() +{ + m_activeFormWindow->lowerWidgets(); +} + +void FormWindowManager::slotActionRaiseActivated() +{ + m_activeFormWindow->raiseWidgets(); +} + +static inline QWidget *findLayoutContainer(const FormWindow *fw) +{ + QList l(fw->selectedWidgets()); + fw->simplifySelection(&l); + return l.empty() ? fw->mainContainer() : l.front(); +} + +void FormWindowManager::createLayout() +{ + QAction *a = qobject_cast(sender()); + if (!a) + return; + const int type = a->data().toInt(); + switch (m_createLayoutContext) { + case LayoutContainer: + // Cannot create a splitter on a container + if (type != LayoutInfo::HSplitter && type != LayoutInfo::VSplitter) + m_activeFormWindow->createLayout(type, findLayoutContainer(m_activeFormWindow)); + break; + case LayoutSelection: + m_activeFormWindow->createLayout(type); + break; + case MorphLayout: + m_activeFormWindow->morphLayout(m_morphLayoutContainer, type); + break; + } +} + +void FormWindowManager::slotActionBreakLayoutActivated() +{ + const QList layouts = layoutsToBeBroken(); + if (layouts.isEmpty()) + return; + + if (debugFWM) { + qDebug() << "slotActionBreakLayoutActivated: " << layouts.size(); + foreach (QWidget *w, layouts) { + qDebug() << w; + } + } + + m_activeFormWindow->beginCommand(tr("Break Layout")); + foreach (QWidget *layout, layouts) { + m_activeFormWindow->breakLayout(layout); + } + m_activeFormWindow->endCommand(); +} + +void FormWindowManager::slotActionSimplifyLayoutActivated() +{ + Q_ASSERT(m_activeFormWindow != 0); + QWidgetList selectedWidgets = m_activeFormWindow->selectedWidgets(); + m_activeFormWindow->simplifySelection(&selectedWidgets); + if (selectedWidgets.size() != 1) + return; + SimplifyLayoutCommand *cmd = new SimplifyLayoutCommand(m_activeFormWindow); + if (cmd->init(selectedWidgets.front())) { + m_activeFormWindow->commandHistory()->push(cmd); + } else { + delete cmd; + } +} + +void FormWindowManager::slotActionAdjustSizeActivated() +{ + Q_ASSERT(m_activeFormWindow != 0); + + m_activeFormWindow->beginCommand(tr("Adjust Size")); + + QList selectedWidgets = m_activeFormWindow->selectedWidgets(); + m_activeFormWindow->simplifySelection(&selectedWidgets); + + if (selectedWidgets.isEmpty()) { + Q_ASSERT(m_activeFormWindow->mainContainer() != 0); + selectedWidgets.append(m_activeFormWindow->mainContainer()); + } + + // Always count the main container as unlaid-out + foreach (QWidget *widget, selectedWidgets) { + bool unlaidout = LayoutInfo::layoutType(core(), widget->parentWidget()) == LayoutInfo::NoLayout; + bool isMainContainer = m_activeFormWindow->isMainContainer(widget); + + if (unlaidout || isMainContainer) { + AdjustWidgetSizeCommand *cmd = new AdjustWidgetSizeCommand(m_activeFormWindow); + cmd->init(widget); + m_activeFormWindow->commandHistory()->push(cmd); + } + } + + m_activeFormWindow->endCommand(); +} + +void FormWindowManager::slotActionSelectAllActivated() +{ + m_activeFormWindow->selectAll(); +} + +void FormWindowManager::slotActionDefaultPreviewActivated() +{ + slotActionGroupPreviewInStyle(QString(), -1); +} + +void FormWindowManager::slotActionGroupPreviewInStyle(const QString &style, int deviceProfileIndex) +{ + QDesignerFormWindowInterface *fw = activeFormWindow(); + if (!fw) + return; + + QString errorMessage; + if (!m_previewManager->showPreview(fw, style, deviceProfileIndex, &errorMessage)) { + const QString title = tr("Could not create form preview", "Title of warning message box"); + core()->dialogGui()->message(fw, QDesignerDialogGuiInterface::FormEditorMessage, QMessageBox::Warning, + title, errorMessage); + } +} + +// The user might click on a layout child or the actual layout container. +QWidgetList FormWindowManager::layoutsToBeBroken(QWidget *w) const +{ + if (!w) + return QList(); + + if (debugFWM) + qDebug() << "layoutsToBeBroken: " << w; + + QWidget *parent = w->parentWidget(); + if (m_activeFormWindow->isMainContainer(w)) + parent = 0; + + QWidget *widget = core()->widgetFactory()->containerOfWidget(w); + + // maybe we want to remove following block + const QDesignerWidgetDataBaseInterface *db = m_core->widgetDataBase(); + const QDesignerWidgetDataBaseItemInterface *item = db->item(db->indexOfObject(widget)); + if (!item) { + if (debugFWM) + qDebug() << "layoutsToBeBroken: Don't have an item, recursing for parent"; + return layoutsToBeBroken(parent); + } + + const bool layoutContainer = (item->isContainer() || m_activeFormWindow->isMainContainer(widget)); + + if (!layoutContainer) { + if (debugFWM) + qDebug() << "layoutsToBeBroken: Not a container, recursing for parent"; + return layoutsToBeBroken(parent); + } + + QLayout *widgetLayout = widget->layout(); + QLayout *managedLayout = LayoutInfo::managedLayout(m_core, widgetLayout); + if (!managedLayout) { + if (qobject_cast(widget)) { + if (debugFWM) + qDebug() << "layoutsToBeBroken: Splitter special"; + QList list = layoutsToBeBroken(parent); + list.append(widget); + return list; + } + if (debugFWM) + qDebug() << "layoutsToBeBroken: Is a container but doesn't have a managed layout (has an internal layout), returning 0"; + return QList(); + } + + if (managedLayout) { + QList list; + if (debugFWM) + qDebug() << "layoutsToBeBroken: Is a container and has a layout"; + if (qobject_cast(widget)) { + if (debugFWM) + qDebug() << "layoutsToBeBroken: red layout special case"; + list = layoutsToBeBroken(parent); + } + list.append(widget); + return list; + } + if (debugFWM) + qDebug() << "layoutsToBeBroken: Is a container but doesn't have a layout at all, returning 0"; + return QList(); + +} + +QMap FormWindowManager::getUnsortedLayoutsToBeBroken(bool firstOnly) const +{ + // Return a set of layouts to be broken. + QMap layouts; + + QList selection = m_activeFormWindow->selectedWidgets(); + if (selection.isEmpty() && m_activeFormWindow->mainContainer()) + selection.append(m_activeFormWindow->mainContainer()); + + const QList::const_iterator scend = selection.constEnd(); + for (QList::const_iterator sit = selection.constBegin(); sit != scend; ++sit) { + // find all layouts + const QList list = layoutsToBeBroken(*sit); + if (!list.empty()) { + const QList::const_iterator lbcend = list.constEnd(); + for (QList::const_iterator lbit = list.constBegin(); lbit != lbcend; ++lbit) { + layouts.insert(*lbit, true); + } + if (firstOnly) + return layouts; + } + } + return layouts; +} + +bool FormWindowManager::hasLayoutsToBeBroken() const +{ + // Quick check for layouts to be broken + return !getUnsortedLayoutsToBeBroken(true).isEmpty(); +} + +QWidgetList FormWindowManager::layoutsToBeBroken() const +{ + // Get all layouts. This is a list of all 'red' layouts (QLayoutWidgets) + // up to the first 'real' widget with a layout in hierarchy order. + QMap unsortedLayouts = getUnsortedLayoutsToBeBroken(false); + // Sort in order of hierarchy + QList orderedLayoutList; + const QMap::const_iterator lscend = unsortedLayouts.constEnd(); + for (QMap::const_iterator itLay = unsortedLayouts.constBegin(); itLay != lscend; ++itLay) { + QWidget *wToBeInserted = itLay.key(); + if (!orderedLayoutList.contains(wToBeInserted)) { + // try to find first child, use as insertion position, else append + const QList::iterator firstChildPos = findFirstChildOf(orderedLayoutList.begin(), orderedLayoutList.end(), wToBeInserted); + if (firstChildPos == orderedLayoutList.end()) { + orderedLayoutList.push_back(wToBeInserted); + } else { + orderedLayoutList.insert(firstChildPos, wToBeInserted); + } + } + } + return orderedLayoutList; +} + +static inline bool hasManagedLayoutItems(const QDesignerFormEditorInterface *core, QWidget *w) +{ + if (const QLayout *ml = LayoutInfo::managedLayout(core, w)) { + // Try to find managed items, ignore dummy grid spacers + const int count = ml->count(); + for (int i = 0; i < count; i++) + if (!LayoutInfo::isEmptyItem(ml->itemAt(i))) + return true; + } + return false; +} + +void FormWindowManager::slotUpdateActions() +{ + m_createLayoutContext = LayoutSelection; + m_morphLayoutContainer = 0; + bool canMorphIntoVBoxLayout = false; + bool canMorphIntoHBoxLayout = false; + bool canMorphIntoGridLayout = false; + bool canMorphIntoFormLayout = false; + int selectedWidgetCount = 0; + int laidoutWidgetCount = 0; + int unlaidoutWidgetCount = 0; + bool pasteAvailable = false; + bool layoutAvailable = false; + bool breakAvailable = false; + bool simplifyAvailable = false; + bool layoutContainer = false; + bool canChangeZOrder = true; + + do { + if (m_activeFormWindow == 0 || m_activeFormWindow->currentTool() != 0) + break; + + breakAvailable = hasLayoutsToBeBroken(); + + QWidgetList simplifiedSelection = m_activeFormWindow->selectedWidgets(); + + selectedWidgetCount = simplifiedSelection.count(); + pasteAvailable = qApp->clipboard()->mimeData() && qApp->clipboard()->mimeData()->hasText(); + + m_activeFormWindow->simplifySelection(&simplifiedSelection); + QWidget *mainContainer = m_activeFormWindow->mainContainer(); + if (simplifiedSelection.isEmpty() && mainContainer) + simplifiedSelection.append(mainContainer); + + // Always count the main container as unlaid-out + const QWidgetList::const_iterator cend = simplifiedSelection.constEnd(); + for (QWidgetList::const_iterator it = simplifiedSelection.constBegin(); it != cend; ++it) { + if (*it != mainContainer && LayoutInfo::isWidgetLaidout(m_core, *it)) { + ++laidoutWidgetCount; + } else { + ++unlaidoutWidgetCount; + } + if (qobject_cast(*it) || qobject_cast(*it)) + canChangeZOrder = false; + } + + // Figure out layouts: Looking at a group of dangling widgets + if (simplifiedSelection.count() != 1) { + layoutAvailable = unlaidoutWidgetCount > 1; + //breakAvailable = false; + break; + } + // Manipulate layout of a single widget + m_createLayoutContext = LayoutSelection; + QWidget *widget = core()->widgetFactory()->containerOfWidget(simplifiedSelection.first()); + if (widget == 0) // We are looking at a page-based container with 0 pages + break; + + const QDesignerWidgetDataBaseInterface *db = m_core->widgetDataBase(); + const QDesignerWidgetDataBaseItemInterface *item = db->item(db->indexOfObject(widget)); + if (!item) + break; + + QLayout *widgetLayout = LayoutInfo::internalLayout(widget); + QLayout *managedLayout = LayoutInfo::managedLayout(m_core, widgetLayout); + // We don't touch a layout createds by a custom widget + if (widgetLayout && !managedLayout) + break; + + layoutContainer = (item->isContainer() || m_activeFormWindow->isMainContainer(widget)); + + layoutAvailable = layoutContainer && m_activeFormWindow->hasInsertedChildren(widget) && managedLayout == 0; + simplifyAvailable = SimplifyLayoutCommand::canSimplify(m_core, widget); + if (layoutAvailable) { + m_createLayoutContext = LayoutContainer; + } else { + /* Cannot create a layout, have some layouts to be broken and + * exactly one, non-empty layout with selected: check the morph layout options + * (Note that there might be > 1 layouts to broken if the selection + * is a red layout, however, we want the inner-most layout here). */ + if (breakAvailable && simplifiedSelection.size() == 1 + && hasManagedLayoutItems(m_core, widget)) { + int type; + m_morphLayoutContainer = widget; // Was: page of first selected + m_createLayoutContext = MorphLayout; + if (MorphLayoutCommand::canMorph(m_activeFormWindow, m_morphLayoutContainer, &type)) { + canMorphIntoVBoxLayout = type != LayoutInfo::VBox; + canMorphIntoHBoxLayout = type != LayoutInfo::HBox; + canMorphIntoGridLayout = type != LayoutInfo::Grid; + canMorphIntoFormLayout = type != LayoutInfo::Form; + } + } + } + } while(false); + + m_actionCut->setEnabled(selectedWidgetCount > 0); + m_actionCopy->setEnabled(selectedWidgetCount > 0); + m_actionDelete->setEnabled(selectedWidgetCount > 0); + m_actionLower->setEnabled(canChangeZOrder && selectedWidgetCount > 0); + m_actionRaise->setEnabled(canChangeZOrder && selectedWidgetCount > 0); + + m_actionPaste->setEnabled(pasteAvailable); + + m_actionSelectAll->setEnabled(m_activeFormWindow != 0); + + m_actionAdjustSize->setEnabled(unlaidoutWidgetCount > 0); + + m_actionHorizontalLayout->setEnabled(layoutAvailable || canMorphIntoHBoxLayout); + m_actionVerticalLayout->setEnabled(layoutAvailable || canMorphIntoVBoxLayout); + m_actionSplitHorizontal->setEnabled(layoutAvailable && !layoutContainer); + m_actionSplitVertical->setEnabled(layoutAvailable && !layoutContainer); + actionFormLayout()->setEnabled(layoutAvailable || canMorphIntoFormLayout); + m_actionGridLayout->setEnabled(layoutAvailable || canMorphIntoGridLayout); + + m_actionBreakLayout->setEnabled(breakAvailable); + actionSimplifyLayout()->setEnabled(simplifyAvailable); + m_actionShowFormWindowSettingsDialog->setEnabled(m_activeFormWindow != 0); +} + +QDesignerFormWindowInterface *FormWindowManager::createFormWindow(QWidget *parentWidget, Qt::WindowFlags flags) +{ + FormWindow *formWindow = new FormWindow(qobject_cast(core()), parentWidget, flags); + formWindow->setProperty(WidgetFactory::disableStyleCustomPaintingPropertyC, QVariant(true)); + addFormWindow(formWindow); + return formWindow; +} + +QPixmap FormWindowManager::createPreviewPixmap(QString *errorMessage) +{ + QPixmap pixmap; + QDesignerFormWindowInterface *fw = activeFormWindow(); + if (!fw) + return pixmap; + + pixmap = m_previewManager->createPreviewPixmap(fw, QString(), errorMessage); + return pixmap; +} + +QAction *FormWindowManager::actionUndo() const +{ + return m_actionUndo; +} + +QAction *FormWindowManager::actionRedo() const +{ + return m_actionRedo; +} + +QActionGroup *FormWindowManager::actionGroupPreviewInStyle() const +{ + if (m_actionGroupPreviewInStyle == 0) { + // Wish we could make the 'this' pointer mutable ;-) + QObject *parent = const_cast(this); + m_actionGroupPreviewInStyle = new PreviewActionGroup(m_core, parent); + connect(m_actionGroupPreviewInStyle, SIGNAL(preview(QString,int)), + this, SLOT(slotActionGroupPreviewInStyle(QString,int))); + } + return m_actionGroupPreviewInStyle; +} + +void FormWindowManager::deviceProfilesChanged() +{ + if (m_actionGroupPreviewInStyle) + m_actionGroupPreviewInStyle->updateDeviceProfiles(); +} + +// DnD stuff + +void FormWindowManager::dragItems(const QList &item_list) +{ + QDesignerMimeData::execDrag(item_list, m_core->topLevel()); +} + +QUndoGroup *FormWindowManager::undoGroup() const +{ + return m_undoGroup; +} + +QAction *FormWindowManager::actionShowFormWindowSettingsDialog() const +{ + return m_actionShowFormWindowSettingsDialog; +} + +void FormWindowManager::slotActionShowFormWindowSettingsDialog() +{ + QDesignerFormWindowInterface *fw = activeFormWindow(); + if (!fw) + return; + + QDialog *settingsDialog = 0; + const bool wasDirty = fw->isDirty(); + + // Ask the language extension for a dialog. If not, create our own + if (QDesignerLanguageExtension *lang = qt_extension(m_core->extensionManager(), m_core)) + settingsDialog = lang->createFormWindowSettingsDialog(fw, /*parent=*/ 0); + + if (!settingsDialog) + settingsDialog = new FormWindowSettings(fw); + + QString title = QFileInfo(fw->fileName()).fileName(); + if (title.isEmpty()) // Grab the title from the outer window if no filename + if (const QWidget *window = m_core->integration()->containerWindow(fw)) + title = window->windowTitle(); + + settingsDialog->setWindowTitle(tr("Form Settings - %1").arg(title)); + if (settingsDialog->exec()) + if (fw->isDirty() != wasDirty) + emit formWindowSettingsChanged(fw); + + delete settingsDialog; +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/formwindowmanager.h b/src/designer/src/components/formeditor/formwindowmanager.h new file mode 100644 index 000000000..dfd421522 --- /dev/null +++ b/src/designer/src/components/formeditor/formwindowmanager.h @@ -0,0 +1,200 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FORMWINDOWMANAGER_H +#define FORMWINDOWMANAGER_H + +#include "formeditor_global.h" + +#include + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QAction; +class QActionGroup; +class QUndoGroup; +class QDesignerFormEditorInterface; +class QDesignerWidgetBoxInterface; + +namespace qdesigner_internal { + +class FormWindow; +class PreviewManager; +class PreviewActionGroup; + +class QT_FORMEDITOR_EXPORT FormWindowManager + : public QDesignerFormWindowManager +{ + Q_OBJECT +public: + explicit FormWindowManager(QDesignerFormEditorInterface *core, QObject *parent = 0); + virtual ~FormWindowManager(); + + virtual QDesignerFormEditorInterface *core() const; + + inline QAction *actionCut() const { return m_actionCut; } + inline QAction *actionCopy() const { return m_actionCopy; } + inline QAction *actionPaste() const { return m_actionPaste; } + inline QAction *actionDelete() const { return m_actionDelete; } + inline QAction *actionSelectAll() const { return m_actionSelectAll; } + inline QAction *actionLower() const { return m_actionLower; } + inline QAction *actionRaise() const { return m_actionRaise; } + QAction *actionUndo() const; + QAction *actionRedo() const; + + inline QAction *actionHorizontalLayout() const { return m_actionHorizontalLayout; } + inline QAction *actionVerticalLayout() const { return m_actionVerticalLayout; } + inline QAction *actionSplitHorizontal() const { return m_actionSplitHorizontal; } + inline QAction *actionSplitVertical() const { return m_actionSplitVertical; } + inline QAction *actionGridLayout() const { return m_actionGridLayout; } + inline QAction *actionBreakLayout() const { return m_actionBreakLayout; } + inline QAction *actionAdjustSize() const { return m_actionAdjustSize; } + + inline QAction *actionDefaultPreview() const { return m_actionDefaultPreview; } + QActionGroup *actionGroupPreviewInStyle() const; + virtual QAction *actionShowFormWindowSettingsDialog() const; + + QDesignerFormWindowInterface *activeFormWindow() const; + + int formWindowCount() const; + QDesignerFormWindowInterface *formWindow(int index) const; + + QDesignerFormWindowInterface *createFormWindow(QWidget *parentWidget = 0, Qt::WindowFlags flags = 0); + + QPixmap createPreviewPixmap(QString *errorMessage); + + bool eventFilter(QObject *o, QEvent *e); + + void dragItems(const QList &item_list); + + QUndoGroup *undoGroup() const; + + virtual PreviewManager *previewManager() const { return m_previewManager; } + +public slots: + void addFormWindow(QDesignerFormWindowInterface *formWindow); + void removeFormWindow(QDesignerFormWindowInterface *formWindow); + void setActiveFormWindow(QDesignerFormWindowInterface *formWindow); + void closeAllPreviews(); + void deviceProfilesChanged(); + +private slots: + void slotActionCutActivated(); + void slotActionCopyActivated(); + void slotActionPasteActivated(); + void slotActionDeleteActivated(); + void slotActionSelectAllActivated(); + void slotActionLowerActivated(); + void slotActionRaiseActivated(); + void createLayout(); + void slotActionBreakLayoutActivated(); + void slotActionAdjustSizeActivated(); + void slotActionSimplifyLayoutActivated(); + void slotActionDefaultPreviewActivated(); + void slotActionGroupPreviewInStyle(const QString &style, int deviceProfileIndex); + void slotActionShowFormWindowSettingsDialog(); + + void slotUpdateActions(); + +private: + void setupActions(); + FormWindow *findFormWindow(QWidget *w); + QWidget *findManagedWidget(FormWindow *fw, QWidget *w); + + void setCurrentUndoStack(QUndoStack *stack); + +private: + enum CreateLayoutContext { LayoutContainer, LayoutSelection, MorphLayout }; + + QDesignerFormEditorInterface *m_core; + FormWindow *m_activeFormWindow; + QList m_formWindows; + + PreviewManager *m_previewManager; + + /* Context of the layout actions and base for morphing layouts. Determined + * in slotUpdateActions() and used later on in the action slots. */ + CreateLayoutContext m_createLayoutContext; + QWidget *m_morphLayoutContainer; + + // edit actions + QAction *m_actionCut; + QAction *m_actionCopy; + QAction *m_actionPaste; + QAction *m_actionSelectAll; + QAction *m_actionDelete; + QAction *m_actionLower; + QAction *m_actionRaise; + // layout actions + QAction *m_actionHorizontalLayout; + QAction *m_actionVerticalLayout; + QAction *m_actionSplitHorizontal; + QAction *m_actionSplitVertical; + QAction *m_actionGridLayout; + QAction *m_actionBreakLayout; + QAction *m_actionAdjustSize; + // preview actions + QAction *m_actionDefaultPreview; + mutable PreviewActionGroup *m_actionGroupPreviewInStyle; + QAction *m_actionShowFormWindowSettingsDialog; + + QAction *m_actionUndo; + QAction *m_actionRedo; + + QMap getUnsortedLayoutsToBeBroken(bool firstOnly) const; + bool hasLayoutsToBeBroken() const; + QWidgetList layoutsToBeBroken(QWidget *w) const; + QWidgetList layoutsToBeBroken() const; + + QUndoGroup *m_undoGroup; + +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // FORMWINDOWMANAGER_H diff --git a/src/designer/src/components/formeditor/formwindowsettings.cpp b/src/designer/src/components/formeditor/formwindowsettings.cpp new file mode 100644 index 000000000..04d5f8ca5 --- /dev/null +++ b/src/designer/src/components/formeditor/formwindowsettings.cpp @@ -0,0 +1,282 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "formwindowsettings.h" +#include "ui_formwindowsettings.h" + +#include +#include + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// Data structure containing form dialog data providing comparison +struct FormWindowData { + FormWindowData(); + + bool equals(const FormWindowData&) const; + + void fromFormWindow(FormWindowBase* fw); + void applyToFormWindow(FormWindowBase* fw) const; + + bool layoutDefaultEnabled; + int defaultMargin; + int defaultSpacing; + + bool layoutFunctionsEnabled; + QString marginFunction; + QString spacingFunction; + + QString pixFunction; + + QString author; + + QStringList includeHints; + + bool hasFormGrid; + Grid grid; +}; + +inline bool operator==(const FormWindowData &fd1, const FormWindowData &fd2) { return fd1.equals(fd2); } +inline bool operator!=(const FormWindowData &fd1, const FormWindowData &fd2) { return !fd1.equals(fd2); } + +QDebug operator<<(QDebug str, const FormWindowData &d) +{ + str.nospace() << "LayoutDefault=" << d.layoutDefaultEnabled << ',' << d.defaultMargin + << ',' << d.defaultSpacing << " LayoutFunctions=" << d.layoutFunctionsEnabled << ',' + << d.marginFunction << ',' << d.spacingFunction << " PixFunction=" + << d.pixFunction << " Author=" << d.author << " Hints=" << d.includeHints + << " Grid=" << d.hasFormGrid << d.grid.deltaX() << d.grid.deltaY() << '\n'; + return str; +} + +FormWindowData::FormWindowData() : + layoutDefaultEnabled(false), + defaultMargin(0), + defaultSpacing(0), + layoutFunctionsEnabled(false), + hasFormGrid(false) +{ +} + +bool FormWindowData::equals(const FormWindowData &rhs) const +{ + return layoutDefaultEnabled == rhs.layoutDefaultEnabled && + defaultMargin == rhs.defaultMargin && + defaultSpacing == rhs.defaultSpacing && + layoutFunctionsEnabled == rhs.layoutFunctionsEnabled && + marginFunction == rhs.marginFunction && + spacingFunction == rhs.spacingFunction && + pixFunction == rhs.pixFunction && + author == rhs.author && + includeHints == rhs.includeHints && + hasFormGrid == rhs.hasFormGrid && + grid == rhs.grid; +} + +void FormWindowData::fromFormWindow(FormWindowBase* fw) +{ + defaultMargin = defaultSpacing = INT_MIN; + fw->layoutDefault(&defaultMargin, &defaultSpacing); + + QStyle *style = fw->formContainer()->style(); + layoutDefaultEnabled = defaultMargin != INT_MIN || defaultMargin != INT_MIN; + if (defaultMargin == INT_MIN) + defaultMargin = style->pixelMetric(QStyle::PM_DefaultChildMargin, 0); + if (defaultSpacing == INT_MIN) + defaultSpacing = style->pixelMetric(QStyle::PM_DefaultLayoutSpacing, 0); + + + marginFunction.clear(); + spacingFunction.clear(); + fw->layoutFunction(&marginFunction, &spacingFunction); + layoutFunctionsEnabled = !marginFunction.isEmpty() || !spacingFunction.isEmpty(); + + pixFunction = fw->pixmapFunction(); + + author = fw->author(); + + includeHints = fw->includeHints(); + includeHints.removeAll(QString()); + + hasFormGrid = fw->hasFormGrid(); + grid = hasFormGrid ? fw->designerGrid() : FormWindowBase::defaultDesignerGrid(); +} + +void FormWindowData::applyToFormWindow(FormWindowBase* fw) const +{ + fw->setAuthor(author); + fw->setPixmapFunction(pixFunction); + + if (layoutDefaultEnabled) { + fw->setLayoutDefault(defaultMargin, defaultSpacing); + } else { + fw->setLayoutDefault(INT_MIN, INT_MIN); + } + + if (layoutFunctionsEnabled) { + fw->setLayoutFunction(marginFunction, spacingFunction); + } else { + fw->setLayoutFunction(QString(), QString()); + } + + fw->setIncludeHints(includeHints); + + const bool hadFormGrid = fw->hasFormGrid(); + fw->setHasFormGrid(hasFormGrid); + if (hasFormGrid || hadFormGrid != hasFormGrid) + fw->setDesignerGrid(hasFormGrid ? grid : FormWindowBase::defaultDesignerGrid()); +} + +// -------------------------- FormWindowSettings + +FormWindowSettings::FormWindowSettings(QDesignerFormWindowInterface *parent) : + QDialog(parent), + m_ui(new ::Ui::FormWindowSettings), + m_formWindow(qobject_cast(parent)), + m_oldData(new FormWindowData) +{ + Q_ASSERT(m_formWindow); + + m_ui->setupUi(this); + m_ui->gridPanel->setCheckable(true); + m_ui->gridPanel->setResetButtonVisible(false); + + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + QString deviceProfileName = m_formWindow->deviceProfileName(); + if (deviceProfileName.isEmpty()) + deviceProfileName = tr("None"); + m_ui->deviceProfileLabel->setText(tr("Device Profile: %1").arg(deviceProfileName)); + + m_oldData->fromFormWindow(m_formWindow); + setData(*m_oldData); +} + +FormWindowSettings::~FormWindowSettings() +{ + delete m_oldData; + delete m_ui; +} + +FormWindowData FormWindowSettings::data() const +{ + FormWindowData rc; + rc.author = m_ui->authorLineEdit->text(); + + if (m_ui->pixmapFunctionGroupBox->isChecked()) { + rc.pixFunction = m_ui->pixmapFunctionLineEdit->text(); + } else { + rc.pixFunction.clear(); + } + + rc.layoutDefaultEnabled = m_ui->layoutDefaultGroupBox->isChecked(); + rc.defaultMargin = m_ui->defaultMarginSpinBox->value(); + rc.defaultSpacing = m_ui->defaultSpacingSpinBox->value(); + + rc.layoutFunctionsEnabled = m_ui->layoutFunctionGroupBox->isChecked(); + rc.marginFunction = m_ui->marginFunctionLineEdit->text(); + rc.spacingFunction = m_ui->spacingFunctionLineEdit->text(); + + const QString hints = m_ui->includeHintsTextEdit->toPlainText(); + if (!hints.isEmpty()) { + rc.includeHints = hints.split(QString(QLatin1Char('\n'))); + // Purge out any lines consisting of blanks only + const QRegExp blankLine = QRegExp(QLatin1String("^\\s*$")); + Q_ASSERT(blankLine.isValid()); + for (QStringList::iterator it = rc.includeHints.begin(); it != rc.includeHints.end(); ) + if (blankLine.exactMatch(*it)) { + it = rc.includeHints.erase(it); + } else { + ++it; + } + rc.includeHints.removeAll(QString()); + } + + rc.hasFormGrid = m_ui->gridPanel->isChecked(); + rc.grid = m_ui->gridPanel->grid(); + return rc; +} + +void FormWindowSettings::setData(const FormWindowData &data) +{ + m_ui->layoutDefaultGroupBox->setChecked(data.layoutDefaultEnabled); + m_ui->defaultMarginSpinBox->setValue(data.defaultMargin); + m_ui->defaultSpacingSpinBox->setValue(data.defaultSpacing); + + m_ui->layoutFunctionGroupBox->setChecked(data.layoutFunctionsEnabled); + m_ui->marginFunctionLineEdit->setText(data.marginFunction); + m_ui->spacingFunctionLineEdit->setText(data.spacingFunction); + + m_ui->pixmapFunctionLineEdit->setText(data.pixFunction); + m_ui->pixmapFunctionGroupBox->setChecked(!data.pixFunction.isEmpty()); + + m_ui->authorLineEdit->setText(data.author); + + if (data.includeHints.empty()) { + m_ui->includeHintsTextEdit->clear(); + } else { + m_ui->includeHintsTextEdit->setText(data.includeHints.join(QLatin1String("\n"))); + } + + m_ui->gridPanel->setChecked(data.hasFormGrid); + m_ui->gridPanel->setGrid(data.grid); +} + +void FormWindowSettings::accept() +{ + // Anything changed? -> Apply and set dirty + const FormWindowData newData = data(); + if (newData != *m_oldData) { + newData.applyToFormWindow(m_formWindow); + m_formWindow->setDirty(true); + } + + QDialog::accept(); +} +} +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/formwindowsettings.h b/src/designer/src/components/formeditor/formwindowsettings.h new file mode 100644 index 000000000..f5c6f53e3 --- /dev/null +++ b/src/designer/src/components/formeditor/formwindowsettings.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FORMWINDOWSETTINGS_H +#define FORMWINDOWSETTINGS_H + +#include + +QT_BEGIN_NAMESPACE + +namespace Ui { + class FormWindowSettings; +} + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +struct FormWindowData; +class FormWindowBase; + +/* Dialog to edit the settings of a QDesignerFormWindowInterface. + * It sets the dirty flag on the form window if something was changed. */ + +class FormWindowSettings: public QDialog +{ + Q_DISABLE_COPY(FormWindowSettings) + Q_OBJECT +public: + explicit FormWindowSettings(QDesignerFormWindowInterface *formWindow); + virtual ~FormWindowSettings(); + + virtual void accept(); + +private: + FormWindowData data() const; + void setData(const FormWindowData&); + + Ui::FormWindowSettings *m_ui; + FormWindowBase *m_formWindow; + FormWindowData *m_oldData; +}; +} + +QT_END_NAMESPACE + +#endif // FORMWINDOWSETTINGS_H diff --git a/src/designer/src/components/formeditor/formwindowsettings.ui b/src/designer/src/components/formeditor/formwindowsettings.ui new file mode 100644 index 000000000..1a607b263 --- /dev/null +++ b/src/designer/src/components/formeditor/formwindowsettings.ui @@ -0,0 +1,328 @@ + + + ********************************************************************* +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +********************************************************************* + FormWindowSettings + + + + 0 + 0 + 470 + 466 + + + + Form Settings + + + + + + 6 + + + 0 + + + + + Layout &Default + + + true + + + + 8 + + + 6 + + + + + &Spacing: + + + defaultSpacingSpinBox + + + + + + + &Margin: + + + defaultMarginSpinBox + + + + + + + + + + + + + + + + &Layout Function + + + true + + + + 8 + + + 6 + + + + + + + + + + + Ma&rgin: + + + marginFunctionLineEdit + + + + + + + Spa&cing: + + + spacingFunctionLineEdit + + + + + + + + + + + + 6 + + + 0 + + + + + &Pixmap Function + + + true + + + + 6 + + + 8 + + + + + + + + + + + + + Qt::Vertical + + + + 111 + 115 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Qt::Horizontal + + + + + + + &Include Hints + + + + 6 + + + 8 + + + + + + + + + + + Grid + + + + + + + Embedded Design + + + + + + TextLabel + + + + + + + + + + &Author + + + + 6 + + + 8 + + + + + + + + + + + + qdesigner_internal::GridPanel + QGroupBox +
gridpanel_p.h
+ 1 +
+
+ + authorLineEdit + defaultMarginSpinBox + defaultSpacingSpinBox + marginFunctionLineEdit + spacingFunctionLineEdit + pixmapFunctionLineEdit + + + + + buttonBox + accepted() + FormWindowSettings + accept() + + + 294 + 442 + + + 150 + 459 + + + + + buttonBox + rejected() + FormWindowSettings + reject() + + + 373 + 444 + + + 357 + 461 + + + + +
diff --git a/src/designer/src/components/formeditor/iconcache.cpp b/src/designer/src/components/formeditor/iconcache.cpp new file mode 100644 index 000000000..3fceeeade --- /dev/null +++ b/src/designer/src/components/formeditor/iconcache.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "iconcache.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +IconCache::IconCache(QObject *parent) + : QDesignerIconCacheInterface(parent) +{ +} + +QIcon IconCache::nameToIcon(const QString &path, const QString &resourcePath) +{ + Q_UNUSED(path) + Q_UNUSED(resourcePath) + qWarning() << "IconCache::nameToIcon(): IconCache is obsoleted"; + return QIcon(); +} + +QString IconCache::iconToFilePath(const QIcon &pm) const +{ + Q_UNUSED(pm) + qWarning() << "IconCache::iconToFilePath(): IconCache is obsoleted"; + return QString(); +} + +QString IconCache::iconToQrcPath(const QIcon &pm) const +{ + Q_UNUSED(pm) + qWarning() << "IconCache::iconToQrcPath(): IconCache is obsoleted"; + return QString(); +} + +QPixmap IconCache::nameToPixmap(const QString &path, const QString &resourcePath) +{ + Q_UNUSED(path) + Q_UNUSED(resourcePath) + qWarning() << "IconCache::nameToPixmap(): IconCache is obsoleted"; + return QPixmap(); +} + +QString IconCache::pixmapToFilePath(const QPixmap &pm) const +{ + Q_UNUSED(pm) + qWarning() << "IconCache::pixmapToFilePath(): IconCache is obsoleted"; + return QString(); +} + +QString IconCache::pixmapToQrcPath(const QPixmap &pm) const +{ + Q_UNUSED(pm) + qWarning() << "IconCache::pixmapToQrcPath(): IconCache is obsoleted"; + return QString(); +} + +QList IconCache::pixmapList() const +{ + qWarning() << "IconCache::pixmapList(): IconCache is obsoleted"; + return QList(); +} + +QList IconCache::iconList() const +{ + qWarning() << "IconCache::iconList(): IconCache is obsoleted"; + return QList(); +} + +QString IconCache::resolveQrcPath(const QString &filePath, const QString &qrcPath, const QString &wd) const +{ + Q_UNUSED(filePath) + Q_UNUSED(qrcPath) + Q_UNUSED(wd) + qWarning() << "IconCache::resolveQrcPath(): IconCache is obsoleted"; + return QString(); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/iconcache.h b/src/designer/src/components/formeditor/iconcache.h new file mode 100644 index 000000000..5d9cc6580 --- /dev/null +++ b/src/designer/src/components/formeditor/iconcache.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ICONCACHE_H +#define ICONCACHE_H + +#include "formeditor_global.h" + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QT_FORMEDITOR_EXPORT IconCache : public QDesignerIconCacheInterface +{ + Q_OBJECT +public: + explicit IconCache(QObject *parent); + + virtual QIcon nameToIcon(const QString &path, const QString &resourcePath = QString()); + virtual QString iconToFilePath(const QIcon &pm) const; + virtual QString iconToQrcPath(const QIcon &pm) const; + virtual QPixmap nameToPixmap(const QString &path, const QString &resourcePath = QString()); + virtual QString pixmapToFilePath(const QPixmap &pm) const; + virtual QString pixmapToQrcPath(const QPixmap &pm) const; + + virtual QList pixmapList() const; + virtual QList iconList() const; + + virtual QString resolveQrcPath(const QString &filePath, const QString &qrcPath, const QString &workingDirectory = QString()) const; + +private: +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // ICONCACHE_H diff --git a/src/designer/src/components/formeditor/images/cleartext.png b/src/designer/src/components/formeditor/images/cleartext.png new file mode 100644 index 000000000..74133baff Binary files /dev/null and b/src/designer/src/components/formeditor/images/cleartext.png differ diff --git a/src/designer/src/components/formeditor/images/color.png b/src/designer/src/components/formeditor/images/color.png new file mode 100644 index 000000000..54b7ebcde Binary files /dev/null and b/src/designer/src/components/formeditor/images/color.png differ diff --git a/src/designer/src/components/formeditor/images/configure.png b/src/designer/src/components/formeditor/images/configure.png new file mode 100644 index 000000000..d9f2fd8c0 Binary files /dev/null and b/src/designer/src/components/formeditor/images/configure.png differ diff --git a/src/designer/src/components/formeditor/images/cursors/arrow.png b/src/designer/src/components/formeditor/images/cursors/arrow.png new file mode 100644 index 000000000..a69ef4eb6 Binary files /dev/null and b/src/designer/src/components/formeditor/images/cursors/arrow.png differ diff --git a/src/designer/src/components/formeditor/images/cursors/busy.png b/src/designer/src/components/formeditor/images/cursors/busy.png new file mode 100644 index 000000000..53717e499 Binary files /dev/null and b/src/designer/src/components/formeditor/images/cursors/busy.png differ diff --git a/src/designer/src/components/formeditor/images/cursors/closedhand.png b/src/designer/src/components/formeditor/images/cursors/closedhand.png new file mode 100644 index 000000000..b78dd1dac Binary files /dev/null and b/src/designer/src/components/formeditor/images/cursors/closedhand.png differ diff --git a/src/designer/src/components/formeditor/images/cursors/cross.png b/src/designer/src/components/formeditor/images/cursors/cross.png new file mode 100644 index 000000000..fe38e7448 Binary files /dev/null and b/src/designer/src/components/formeditor/images/cursors/cross.png differ diff --git a/src/designer/src/components/formeditor/images/cursors/hand.png b/src/designer/src/components/formeditor/images/cursors/hand.png new file mode 100644 index 000000000..d2004aefa Binary files /dev/null and b/src/designer/src/components/formeditor/images/cursors/hand.png differ diff --git a/src/designer/src/components/formeditor/images/cursors/hsplit.png b/src/designer/src/components/formeditor/images/cursors/hsplit.png new file mode 100644 index 000000000..a5667e3ff Binary files /dev/null and b/src/designer/src/components/formeditor/images/cursors/hsplit.png differ diff --git a/src/designer/src/components/formeditor/images/cursors/ibeam.png b/src/designer/src/components/formeditor/images/cursors/ibeam.png new file mode 100644 index 000000000..097fc5fa7 Binary files /dev/null and b/src/designer/src/components/formeditor/images/cursors/ibeam.png differ diff --git a/src/designer/src/components/formeditor/images/cursors/no.png b/src/designer/src/components/formeditor/images/cursors/no.png new file mode 100644 index 000000000..2b08c4e2a Binary files /dev/null and b/src/designer/src/components/formeditor/images/cursors/no.png differ diff --git a/src/designer/src/components/formeditor/images/cursors/openhand.png b/src/designer/src/components/formeditor/images/cursors/openhand.png new file mode 100644 index 000000000..9181c859e Binary files /dev/null and b/src/designer/src/components/formeditor/images/cursors/openhand.png differ diff --git a/src/designer/src/components/formeditor/images/cursors/sizeall.png b/src/designer/src/components/formeditor/images/cursors/sizeall.png new file mode 100644 index 000000000..69f13eb34 Binary files /dev/null and b/src/designer/src/components/formeditor/images/cursors/sizeall.png differ diff --git a/src/designer/src/components/formeditor/images/cursors/sizeb.png b/src/designer/src/components/formeditor/images/cursors/sizeb.png new file mode 100644 index 000000000..3b127a05d Binary files /dev/null and b/src/designer/src/components/formeditor/images/cursors/sizeb.png differ diff --git a/src/designer/src/components/formeditor/images/cursors/sizef.png b/src/designer/src/components/formeditor/images/cursors/sizef.png new file mode 100644 index 000000000..f37d7b91e Binary files /dev/null and b/src/designer/src/components/formeditor/images/cursors/sizef.png differ diff --git a/src/designer/src/components/formeditor/images/cursors/sizeh.png b/src/designer/src/components/formeditor/images/cursors/sizeh.png new file mode 100644 index 000000000..a9f40cbc3 Binary files /dev/null and b/src/designer/src/components/formeditor/images/cursors/sizeh.png differ diff --git a/src/designer/src/components/formeditor/images/cursors/sizev.png b/src/designer/src/components/formeditor/images/cursors/sizev.png new file mode 100644 index 000000000..1edbab27a Binary files /dev/null and b/src/designer/src/components/formeditor/images/cursors/sizev.png differ diff --git a/src/designer/src/components/formeditor/images/cursors/uparrow.png b/src/designer/src/components/formeditor/images/cursors/uparrow.png new file mode 100644 index 000000000..d3e70ef4c Binary files /dev/null and b/src/designer/src/components/formeditor/images/cursors/uparrow.png differ diff --git a/src/designer/src/components/formeditor/images/cursors/vsplit.png b/src/designer/src/components/formeditor/images/cursors/vsplit.png new file mode 100644 index 000000000..1beda2570 Binary files /dev/null and b/src/designer/src/components/formeditor/images/cursors/vsplit.png differ diff --git a/src/designer/src/components/formeditor/images/cursors/wait.png b/src/designer/src/components/formeditor/images/cursors/wait.png new file mode 100644 index 000000000..69056c479 Binary files /dev/null and b/src/designer/src/components/formeditor/images/cursors/wait.png differ diff --git a/src/designer/src/components/formeditor/images/cursors/whatsthis.png b/src/designer/src/components/formeditor/images/cursors/whatsthis.png new file mode 100644 index 000000000..b47601c37 Binary files /dev/null and b/src/designer/src/components/formeditor/images/cursors/whatsthis.png differ diff --git a/src/designer/src/components/formeditor/images/downplus.png b/src/designer/src/components/formeditor/images/downplus.png new file mode 100644 index 000000000..1e384a72d Binary files /dev/null and b/src/designer/src/components/formeditor/images/downplus.png differ diff --git a/src/designer/src/components/formeditor/images/dropdownbutton.png b/src/designer/src/components/formeditor/images/dropdownbutton.png new file mode 100644 index 000000000..5dd964946 Binary files /dev/null and b/src/designer/src/components/formeditor/images/dropdownbutton.png differ diff --git a/src/designer/src/components/formeditor/images/edit.png b/src/designer/src/components/formeditor/images/edit.png new file mode 100644 index 000000000..a5e49adf9 Binary files /dev/null and b/src/designer/src/components/formeditor/images/edit.png differ diff --git a/src/designer/src/components/formeditor/images/editdelete-16.png b/src/designer/src/components/formeditor/images/editdelete-16.png new file mode 100644 index 000000000..ef5c799c1 Binary files /dev/null and b/src/designer/src/components/formeditor/images/editdelete-16.png differ diff --git a/src/designer/src/components/formeditor/images/emptyicon.png b/src/designer/src/components/formeditor/images/emptyicon.png new file mode 100644 index 000000000..897220e21 Binary files /dev/null and b/src/designer/src/components/formeditor/images/emptyicon.png differ diff --git a/src/designer/src/components/formeditor/images/filenew-16.png b/src/designer/src/components/formeditor/images/filenew-16.png new file mode 100644 index 000000000..eefb3c520 Binary files /dev/null and b/src/designer/src/components/formeditor/images/filenew-16.png differ diff --git a/src/designer/src/components/formeditor/images/fileopen-16.png b/src/designer/src/components/formeditor/images/fileopen-16.png new file mode 100644 index 000000000..d832c621c Binary files /dev/null and b/src/designer/src/components/formeditor/images/fileopen-16.png differ diff --git a/src/designer/src/components/formeditor/images/leveldown.png b/src/designer/src/components/formeditor/images/leveldown.png new file mode 100644 index 000000000..742b7fb84 Binary files /dev/null and b/src/designer/src/components/formeditor/images/leveldown.png differ diff --git a/src/designer/src/components/formeditor/images/levelup.png b/src/designer/src/components/formeditor/images/levelup.png new file mode 100644 index 000000000..48b3e8922 Binary files /dev/null and b/src/designer/src/components/formeditor/images/levelup.png differ diff --git a/src/designer/src/components/formeditor/images/mac/adjustsize.png b/src/designer/src/components/formeditor/images/mac/adjustsize.png new file mode 100644 index 000000000..c4d884c8b Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/adjustsize.png differ diff --git a/src/designer/src/components/formeditor/images/mac/back.png b/src/designer/src/components/formeditor/images/mac/back.png new file mode 100644 index 000000000..e58177f43 Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/back.png differ diff --git a/src/designer/src/components/formeditor/images/mac/buddytool.png b/src/designer/src/components/formeditor/images/mac/buddytool.png new file mode 100644 index 000000000..2a4287089 Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/buddytool.png differ diff --git a/src/designer/src/components/formeditor/images/mac/down.png b/src/designer/src/components/formeditor/images/mac/down.png new file mode 100644 index 000000000..29d1d4439 Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/down.png differ diff --git a/src/designer/src/components/formeditor/images/mac/editbreaklayout.png b/src/designer/src/components/formeditor/images/mac/editbreaklayout.png new file mode 100644 index 000000000..dc005590b Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/editbreaklayout.png differ diff --git a/src/designer/src/components/formeditor/images/mac/editcopy.png b/src/designer/src/components/formeditor/images/mac/editcopy.png new file mode 100644 index 000000000..f55136446 Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/editcopy.png differ diff --git a/src/designer/src/components/formeditor/images/mac/editcut.png b/src/designer/src/components/formeditor/images/mac/editcut.png new file mode 100644 index 000000000..a784fd570 Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/editcut.png differ diff --git a/src/designer/src/components/formeditor/images/mac/editdelete.png b/src/designer/src/components/formeditor/images/mac/editdelete.png new file mode 100644 index 000000000..201b31cdb Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/editdelete.png differ diff --git a/src/designer/src/components/formeditor/images/mac/editform.png b/src/designer/src/components/formeditor/images/mac/editform.png new file mode 100644 index 000000000..4fc2e40dc Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/editform.png differ diff --git a/src/designer/src/components/formeditor/images/mac/editgrid.png b/src/designer/src/components/formeditor/images/mac/editgrid.png new file mode 100644 index 000000000..bba4a695b Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/editgrid.png differ diff --git a/src/designer/src/components/formeditor/images/mac/edithlayout.png b/src/designer/src/components/formeditor/images/mac/edithlayout.png new file mode 100644 index 000000000..ec880bb5c Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/edithlayout.png differ diff --git a/src/designer/src/components/formeditor/images/mac/edithlayoutsplit.png b/src/designer/src/components/formeditor/images/mac/edithlayoutsplit.png new file mode 100644 index 000000000..227d0115f Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/edithlayoutsplit.png differ diff --git a/src/designer/src/components/formeditor/images/mac/editlower.png b/src/designer/src/components/formeditor/images/mac/editlower.png new file mode 100644 index 000000000..347806fc0 Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/editlower.png differ diff --git a/src/designer/src/components/formeditor/images/mac/editpaste.png b/src/designer/src/components/formeditor/images/mac/editpaste.png new file mode 100644 index 000000000..64c0b2d6a Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/editpaste.png differ diff --git a/src/designer/src/components/formeditor/images/mac/editraise.png b/src/designer/src/components/formeditor/images/mac/editraise.png new file mode 100644 index 000000000..09cbbd7d5 Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/editraise.png differ diff --git a/src/designer/src/components/formeditor/images/mac/editvlayout.png b/src/designer/src/components/formeditor/images/mac/editvlayout.png new file mode 100644 index 000000000..63b26cdb2 Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/editvlayout.png differ diff --git a/src/designer/src/components/formeditor/images/mac/editvlayoutsplit.png b/src/designer/src/components/formeditor/images/mac/editvlayoutsplit.png new file mode 100644 index 000000000..5a02c944e Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/editvlayoutsplit.png differ diff --git a/src/designer/src/components/formeditor/images/mac/filenew.png b/src/designer/src/components/formeditor/images/mac/filenew.png new file mode 100644 index 000000000..9dcba4284 Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/filenew.png differ diff --git a/src/designer/src/components/formeditor/images/mac/fileopen.png b/src/designer/src/components/formeditor/images/mac/fileopen.png new file mode 100644 index 000000000..c12bcd507 Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/fileopen.png differ diff --git a/src/designer/src/components/formeditor/images/mac/filesave.png b/src/designer/src/components/formeditor/images/mac/filesave.png new file mode 100644 index 000000000..b41ecf531 Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/filesave.png differ diff --git a/src/designer/src/components/formeditor/images/mac/forward.png b/src/designer/src/components/formeditor/images/mac/forward.png new file mode 100644 index 000000000..34b91f09f Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/forward.png differ diff --git a/src/designer/src/components/formeditor/images/mac/insertimage.png b/src/designer/src/components/formeditor/images/mac/insertimage.png new file mode 100644 index 000000000..b8673e13b Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/insertimage.png differ diff --git a/src/designer/src/components/formeditor/images/mac/minus.png b/src/designer/src/components/formeditor/images/mac/minus.png new file mode 100644 index 000000000..8d2eaed52 Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/minus.png differ diff --git a/src/designer/src/components/formeditor/images/mac/plus.png b/src/designer/src/components/formeditor/images/mac/plus.png new file mode 100644 index 000000000..1ee45423e Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/plus.png differ diff --git a/src/designer/src/components/formeditor/images/mac/redo.png b/src/designer/src/components/formeditor/images/mac/redo.png new file mode 100644 index 000000000..8875bf246 Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/redo.png differ diff --git a/src/designer/src/components/formeditor/images/mac/resetproperty.png b/src/designer/src/components/formeditor/images/mac/resetproperty.png new file mode 100644 index 000000000..9048252ec Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/resetproperty.png differ diff --git a/src/designer/src/components/formeditor/images/mac/resourceeditortool.png b/src/designer/src/components/formeditor/images/mac/resourceeditortool.png new file mode 100644 index 000000000..7ef511c2b Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/resourceeditortool.png differ diff --git a/src/designer/src/components/formeditor/images/mac/signalslottool.png b/src/designer/src/components/formeditor/images/mac/signalslottool.png new file mode 100644 index 000000000..71c9b07a8 Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/signalslottool.png differ diff --git a/src/designer/src/components/formeditor/images/mac/simplifyrichtext.png b/src/designer/src/components/formeditor/images/mac/simplifyrichtext.png new file mode 100644 index 000000000..a48e974bf Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/simplifyrichtext.png differ diff --git a/src/designer/src/components/formeditor/images/mac/tabordertool.png b/src/designer/src/components/formeditor/images/mac/tabordertool.png new file mode 100644 index 000000000..f54faf9ab Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/tabordertool.png differ diff --git a/src/designer/src/components/formeditor/images/mac/textanchor.png b/src/designer/src/components/formeditor/images/mac/textanchor.png new file mode 100644 index 000000000..baa9dda52 Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/textanchor.png differ diff --git a/src/designer/src/components/formeditor/images/mac/textbold.png b/src/designer/src/components/formeditor/images/mac/textbold.png new file mode 100644 index 000000000..38400bd1f Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/textbold.png differ diff --git a/src/designer/src/components/formeditor/images/mac/textcenter.png b/src/designer/src/components/formeditor/images/mac/textcenter.png new file mode 100644 index 000000000..2ef5b2ee6 Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/textcenter.png differ diff --git a/src/designer/src/components/formeditor/images/mac/textitalic.png b/src/designer/src/components/formeditor/images/mac/textitalic.png new file mode 100644 index 000000000..0170ee26a Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/textitalic.png differ diff --git a/src/designer/src/components/formeditor/images/mac/textjustify.png b/src/designer/src/components/formeditor/images/mac/textjustify.png new file mode 100644 index 000000000..39cd6c1a9 Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/textjustify.png differ diff --git a/src/designer/src/components/formeditor/images/mac/textleft.png b/src/designer/src/components/formeditor/images/mac/textleft.png new file mode 100644 index 000000000..83a66d553 Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/textleft.png differ diff --git a/src/designer/src/components/formeditor/images/mac/textright.png b/src/designer/src/components/formeditor/images/mac/textright.png new file mode 100644 index 000000000..e7c04645c Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/textright.png differ diff --git a/src/designer/src/components/formeditor/images/mac/textsubscript.png b/src/designer/src/components/formeditor/images/mac/textsubscript.png new file mode 100644 index 000000000..ff431f396 Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/textsubscript.png differ diff --git a/src/designer/src/components/formeditor/images/mac/textsuperscript.png b/src/designer/src/components/formeditor/images/mac/textsuperscript.png new file mode 100644 index 000000000..cb67a33d0 Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/textsuperscript.png differ diff --git a/src/designer/src/components/formeditor/images/mac/textunder.png b/src/designer/src/components/formeditor/images/mac/textunder.png new file mode 100644 index 000000000..968bac5e9 Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/textunder.png differ diff --git a/src/designer/src/components/formeditor/images/mac/undo.png b/src/designer/src/components/formeditor/images/mac/undo.png new file mode 100644 index 000000000..a3bd5e0bf Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/undo.png differ diff --git a/src/designer/src/components/formeditor/images/mac/up.png b/src/designer/src/components/formeditor/images/mac/up.png new file mode 100644 index 000000000..e43731221 Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/up.png differ diff --git a/src/designer/src/components/formeditor/images/mac/widgettool.png b/src/designer/src/components/formeditor/images/mac/widgettool.png new file mode 100644 index 000000000..e1aa353db Binary files /dev/null and b/src/designer/src/components/formeditor/images/mac/widgettool.png differ diff --git a/src/designer/src/components/formeditor/images/minus-16.png b/src/designer/src/components/formeditor/images/minus-16.png new file mode 100644 index 000000000..745b44572 Binary files /dev/null and b/src/designer/src/components/formeditor/images/minus-16.png differ diff --git a/src/designer/src/components/formeditor/images/plus-16.png b/src/designer/src/components/formeditor/images/plus-16.png new file mode 100644 index 000000000..ef43788e6 Binary files /dev/null and b/src/designer/src/components/formeditor/images/plus-16.png differ diff --git a/src/designer/src/components/formeditor/images/prefix-add.png b/src/designer/src/components/formeditor/images/prefix-add.png new file mode 100644 index 000000000..cfbb053f4 Binary files /dev/null and b/src/designer/src/components/formeditor/images/prefix-add.png differ diff --git a/src/designer/src/components/formeditor/images/qt3logo.png b/src/designer/src/components/formeditor/images/qt3logo.png new file mode 100644 index 000000000..720285001 Binary files /dev/null and b/src/designer/src/components/formeditor/images/qt3logo.png differ diff --git a/src/designer/src/components/formeditor/images/qtlogo.png b/src/designer/src/components/formeditor/images/qtlogo.png new file mode 100644 index 000000000..038fa2cc3 Binary files /dev/null and b/src/designer/src/components/formeditor/images/qtlogo.png differ diff --git a/src/designer/src/components/formeditor/images/reload.png b/src/designer/src/components/formeditor/images/reload.png new file mode 100644 index 000000000..18c752e14 Binary files /dev/null and b/src/designer/src/components/formeditor/images/reload.png differ diff --git a/src/designer/src/components/formeditor/images/resetproperty.png b/src/designer/src/components/formeditor/images/resetproperty.png new file mode 100644 index 000000000..9048252ec Binary files /dev/null and b/src/designer/src/components/formeditor/images/resetproperty.png differ diff --git a/src/designer/src/components/formeditor/images/sort.png b/src/designer/src/components/formeditor/images/sort.png new file mode 100644 index 000000000..883bfa9de Binary files /dev/null and b/src/designer/src/components/formeditor/images/sort.png differ diff --git a/src/designer/src/components/formeditor/images/submenu.png b/src/designer/src/components/formeditor/images/submenu.png new file mode 100644 index 000000000..3deb28e3a Binary files /dev/null and b/src/designer/src/components/formeditor/images/submenu.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/calendarwidget.png b/src/designer/src/components/formeditor/images/widgets/calendarwidget.png new file mode 100644 index 000000000..26737b883 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/calendarwidget.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/checkbox.png b/src/designer/src/components/formeditor/images/widgets/checkbox.png new file mode 100644 index 000000000..ab6f53e02 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/checkbox.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/columnview.png b/src/designer/src/components/formeditor/images/widgets/columnview.png new file mode 100644 index 000000000..4132ee6b1 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/columnview.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/combobox.png b/src/designer/src/components/formeditor/images/widgets/combobox.png new file mode 100644 index 000000000..bf3ed79f7 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/combobox.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/commandlinkbutton.png b/src/designer/src/components/formeditor/images/widgets/commandlinkbutton.png new file mode 100644 index 000000000..6bbd84a97 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/commandlinkbutton.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/dateedit.png b/src/designer/src/components/formeditor/images/widgets/dateedit.png new file mode 100644 index 000000000..6827fa742 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/dateedit.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/datetimeedit.png b/src/designer/src/components/formeditor/images/widgets/datetimeedit.png new file mode 100644 index 000000000..7d8e6fe6d Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/datetimeedit.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/dial.png b/src/designer/src/components/formeditor/images/widgets/dial.png new file mode 100644 index 000000000..050d1dbd0 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/dial.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/dialogbuttonbox.png b/src/designer/src/components/formeditor/images/widgets/dialogbuttonbox.png new file mode 100644 index 000000000..b1f89fbb3 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/dialogbuttonbox.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/dockwidget.png b/src/designer/src/components/formeditor/images/widgets/dockwidget.png new file mode 100644 index 000000000..9eee04f70 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/dockwidget.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/doublespinbox.png b/src/designer/src/components/formeditor/images/widgets/doublespinbox.png new file mode 100644 index 000000000..5686ac89b Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/doublespinbox.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/fontcombobox.png b/src/designer/src/components/formeditor/images/widgets/fontcombobox.png new file mode 100644 index 000000000..6848f15c2 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/fontcombobox.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/frame.png b/src/designer/src/components/formeditor/images/widgets/frame.png new file mode 100644 index 000000000..68f5da0a3 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/frame.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/graphicsview.png b/src/designer/src/components/formeditor/images/widgets/graphicsview.png new file mode 100644 index 000000000..93fe7603a Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/graphicsview.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/groupbox.png b/src/designer/src/components/formeditor/images/widgets/groupbox.png new file mode 100644 index 000000000..4025b4dc5 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/groupbox.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/groupboxcollapsible.png b/src/designer/src/components/formeditor/images/widgets/groupboxcollapsible.png new file mode 100644 index 000000000..62fd1ad56 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/groupboxcollapsible.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/hscrollbar.png b/src/designer/src/components/formeditor/images/widgets/hscrollbar.png new file mode 100644 index 000000000..466c58de5 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/hscrollbar.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/hslider.png b/src/designer/src/components/formeditor/images/widgets/hslider.png new file mode 100644 index 000000000..525bd1cab Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/hslider.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/hsplit.png b/src/designer/src/components/formeditor/images/widgets/hsplit.png new file mode 100644 index 000000000..1ea8f2ac0 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/hsplit.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/label.png b/src/designer/src/components/formeditor/images/widgets/label.png new file mode 100644 index 000000000..5d7d7b4cc Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/label.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/lcdnumber.png b/src/designer/src/components/formeditor/images/widgets/lcdnumber.png new file mode 100644 index 000000000..c3cac1826 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/lcdnumber.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/line.png b/src/designer/src/components/formeditor/images/widgets/line.png new file mode 100644 index 000000000..5c64dfb59 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/line.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/lineedit.png b/src/designer/src/components/formeditor/images/widgets/lineedit.png new file mode 100644 index 000000000..75fc890f4 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/lineedit.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/listbox.png b/src/designer/src/components/formeditor/images/widgets/listbox.png new file mode 100644 index 000000000..367e67ff5 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/listbox.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/listview.png b/src/designer/src/components/formeditor/images/widgets/listview.png new file mode 100644 index 000000000..d1308d575 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/listview.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/mdiarea.png b/src/designer/src/components/formeditor/images/widgets/mdiarea.png new file mode 100644 index 000000000..7783dd527 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/mdiarea.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/plaintextedit.png b/src/designer/src/components/formeditor/images/widgets/plaintextedit.png new file mode 100644 index 000000000..077bf16cb Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/plaintextedit.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/progress.png b/src/designer/src/components/formeditor/images/widgets/progress.png new file mode 100644 index 000000000..44ae094e7 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/progress.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/pushbutton.png b/src/designer/src/components/formeditor/images/widgets/pushbutton.png new file mode 100644 index 000000000..61f779ce2 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/pushbutton.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/radiobutton.png b/src/designer/src/components/formeditor/images/widgets/radiobutton.png new file mode 100644 index 000000000..10c1d8c3e Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/radiobutton.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/scrollarea.png b/src/designer/src/components/formeditor/images/widgets/scrollarea.png new file mode 100644 index 000000000..651ea24c0 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/scrollarea.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/spacer.png b/src/designer/src/components/formeditor/images/widgets/spacer.png new file mode 100644 index 000000000..8a0931bf8 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/spacer.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/spinbox.png b/src/designer/src/components/formeditor/images/widgets/spinbox.png new file mode 100644 index 000000000..cdd9fe141 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/spinbox.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/tabbar.png b/src/designer/src/components/formeditor/images/widgets/tabbar.png new file mode 100644 index 000000000..d5d37836b Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/tabbar.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/table.png b/src/designer/src/components/formeditor/images/widgets/table.png new file mode 100644 index 000000000..4bbd9c2d0 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/table.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/tabwidget.png b/src/designer/src/components/formeditor/images/widgets/tabwidget.png new file mode 100644 index 000000000..1254bb63a Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/tabwidget.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/textedit.png b/src/designer/src/components/formeditor/images/widgets/textedit.png new file mode 100644 index 000000000..32e897d97 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/textedit.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/timeedit.png b/src/designer/src/components/formeditor/images/widgets/timeedit.png new file mode 100644 index 000000000..c66d91b2f Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/timeedit.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/toolbox.png b/src/designer/src/components/formeditor/images/widgets/toolbox.png new file mode 100644 index 000000000..2ab71dc74 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/toolbox.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/toolbutton.png b/src/designer/src/components/formeditor/images/widgets/toolbutton.png new file mode 100644 index 000000000..0bff069a5 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/toolbutton.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/vline.png b/src/designer/src/components/formeditor/images/widgets/vline.png new file mode 100644 index 000000000..35a7300a5 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/vline.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/vscrollbar.png b/src/designer/src/components/formeditor/images/widgets/vscrollbar.png new file mode 100644 index 000000000..28b7c40c6 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/vscrollbar.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/vslider.png b/src/designer/src/components/formeditor/images/widgets/vslider.png new file mode 100644 index 000000000..59f06bae4 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/vslider.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/vspacer.png b/src/designer/src/components/formeditor/images/widgets/vspacer.png new file mode 100644 index 000000000..ce5e8bd7d Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/vspacer.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/widget.png b/src/designer/src/components/formeditor/images/widgets/widget.png new file mode 100644 index 000000000..1cf960e61 Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/widget.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/widgetstack.png b/src/designer/src/components/formeditor/images/widgets/widgetstack.png new file mode 100644 index 000000000..2c6964e3e Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/widgetstack.png differ diff --git a/src/designer/src/components/formeditor/images/widgets/wizard.png b/src/designer/src/components/formeditor/images/widgets/wizard.png new file mode 100644 index 000000000..7c0e107ae Binary files /dev/null and b/src/designer/src/components/formeditor/images/widgets/wizard.png differ diff --git a/src/designer/src/components/formeditor/images/win/adjustsize.png b/src/designer/src/components/formeditor/images/win/adjustsize.png new file mode 100644 index 000000000..3cda33371 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/adjustsize.png differ diff --git a/src/designer/src/components/formeditor/images/win/back.png b/src/designer/src/components/formeditor/images/win/back.png new file mode 100644 index 000000000..e58177f43 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/back.png differ diff --git a/src/designer/src/components/formeditor/images/win/buddytool.png b/src/designer/src/components/formeditor/images/win/buddytool.png new file mode 100644 index 000000000..4cd968bbf Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/buddytool.png differ diff --git a/src/designer/src/components/formeditor/images/win/down.png b/src/designer/src/components/formeditor/images/win/down.png new file mode 100644 index 000000000..29d1d4439 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/down.png differ diff --git a/src/designer/src/components/formeditor/images/win/editbreaklayout.png b/src/designer/src/components/formeditor/images/win/editbreaklayout.png new file mode 100644 index 000000000..07c5fae69 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/editbreaklayout.png differ diff --git a/src/designer/src/components/formeditor/images/win/editcopy.png b/src/designer/src/components/formeditor/images/win/editcopy.png new file mode 100644 index 000000000..1121b47d8 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/editcopy.png differ diff --git a/src/designer/src/components/formeditor/images/win/editcut.png b/src/designer/src/components/formeditor/images/win/editcut.png new file mode 100644 index 000000000..4b6c82c7a Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/editcut.png differ diff --git a/src/designer/src/components/formeditor/images/win/editdelete.png b/src/designer/src/components/formeditor/images/win/editdelete.png new file mode 100644 index 000000000..5a4251402 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/editdelete.png differ diff --git a/src/designer/src/components/formeditor/images/win/editform.png b/src/designer/src/components/formeditor/images/win/editform.png new file mode 100644 index 000000000..452fcd887 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/editform.png differ diff --git a/src/designer/src/components/formeditor/images/win/editgrid.png b/src/designer/src/components/formeditor/images/win/editgrid.png new file mode 100644 index 000000000..789bf7d96 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/editgrid.png differ diff --git a/src/designer/src/components/formeditor/images/win/edithlayout.png b/src/designer/src/components/formeditor/images/win/edithlayout.png new file mode 100644 index 000000000..4dd3f0ce4 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/edithlayout.png differ diff --git a/src/designer/src/components/formeditor/images/win/edithlayoutsplit.png b/src/designer/src/components/formeditor/images/win/edithlayoutsplit.png new file mode 100644 index 000000000..2dcc69029 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/edithlayoutsplit.png differ diff --git a/src/designer/src/components/formeditor/images/win/editlower.png b/src/designer/src/components/formeditor/images/win/editlower.png new file mode 100644 index 000000000..ba630944c Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/editlower.png differ diff --git a/src/designer/src/components/formeditor/images/win/editpaste.png b/src/designer/src/components/formeditor/images/win/editpaste.png new file mode 100644 index 000000000..ffab15aaf Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/editpaste.png differ diff --git a/src/designer/src/components/formeditor/images/win/editraise.png b/src/designer/src/components/formeditor/images/win/editraise.png new file mode 100644 index 000000000..bb8362c1f Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/editraise.png differ diff --git a/src/designer/src/components/formeditor/images/win/editvlayout.png b/src/designer/src/components/formeditor/images/win/editvlayout.png new file mode 100644 index 000000000..7ad28fdea Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/editvlayout.png differ diff --git a/src/designer/src/components/formeditor/images/win/editvlayoutsplit.png b/src/designer/src/components/formeditor/images/win/editvlayoutsplit.png new file mode 100644 index 000000000..720e18bb3 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/editvlayoutsplit.png differ diff --git a/src/designer/src/components/formeditor/images/win/filenew.png b/src/designer/src/components/formeditor/images/win/filenew.png new file mode 100644 index 000000000..af5d12214 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/filenew.png differ diff --git a/src/designer/src/components/formeditor/images/win/fileopen.png b/src/designer/src/components/formeditor/images/win/fileopen.png new file mode 100644 index 000000000..fc6f17e97 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/fileopen.png differ diff --git a/src/designer/src/components/formeditor/images/win/filesave.png b/src/designer/src/components/formeditor/images/win/filesave.png new file mode 100644 index 000000000..8feec99be Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/filesave.png differ diff --git a/src/designer/src/components/formeditor/images/win/forward.png b/src/designer/src/components/formeditor/images/win/forward.png new file mode 100644 index 000000000..34b91f09f Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/forward.png differ diff --git a/src/designer/src/components/formeditor/images/win/insertimage.png b/src/designer/src/components/formeditor/images/win/insertimage.png new file mode 100644 index 000000000..cfab6375f Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/insertimage.png differ diff --git a/src/designer/src/components/formeditor/images/win/minus.png b/src/designer/src/components/formeditor/images/win/minus.png new file mode 100644 index 000000000..c0dc274bb Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/minus.png differ diff --git a/src/designer/src/components/formeditor/images/win/plus.png b/src/designer/src/components/formeditor/images/win/plus.png new file mode 100644 index 000000000..ecf058941 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/plus.png differ diff --git a/src/designer/src/components/formeditor/images/win/redo.png b/src/designer/src/components/formeditor/images/win/redo.png new file mode 100644 index 000000000..686ad141c Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/redo.png differ diff --git a/src/designer/src/components/formeditor/images/win/resourceeditortool.png b/src/designer/src/components/formeditor/images/win/resourceeditortool.png new file mode 100644 index 000000000..cc9cb5851 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/resourceeditortool.png differ diff --git a/src/designer/src/components/formeditor/images/win/signalslottool.png b/src/designer/src/components/formeditor/images/win/signalslottool.png new file mode 100644 index 000000000..e80fd1caa Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/signalslottool.png differ diff --git a/src/designer/src/components/formeditor/images/win/simplifyrichtext.png b/src/designer/src/components/formeditor/images/win/simplifyrichtext.png new file mode 100644 index 000000000..e251cf7b9 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/simplifyrichtext.png differ diff --git a/src/designer/src/components/formeditor/images/win/tabordertool.png b/src/designer/src/components/formeditor/images/win/tabordertool.png new file mode 100644 index 000000000..7e6e2de71 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/tabordertool.png differ diff --git a/src/designer/src/components/formeditor/images/win/textanchor.png b/src/designer/src/components/formeditor/images/win/textanchor.png new file mode 100644 index 000000000..1911ab0d5 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/textanchor.png differ diff --git a/src/designer/src/components/formeditor/images/win/textbold.png b/src/designer/src/components/formeditor/images/win/textbold.png new file mode 100644 index 000000000..9cbc7138b Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/textbold.png differ diff --git a/src/designer/src/components/formeditor/images/win/textcenter.png b/src/designer/src/components/formeditor/images/win/textcenter.png new file mode 100644 index 000000000..11efb4b85 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/textcenter.png differ diff --git a/src/designer/src/components/formeditor/images/win/textitalic.png b/src/designer/src/components/formeditor/images/win/textitalic.png new file mode 100644 index 000000000..b30ce14c1 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/textitalic.png differ diff --git a/src/designer/src/components/formeditor/images/win/textjustify.png b/src/designer/src/components/formeditor/images/win/textjustify.png new file mode 100644 index 000000000..9de0c8808 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/textjustify.png differ diff --git a/src/designer/src/components/formeditor/images/win/textleft.png b/src/designer/src/components/formeditor/images/win/textleft.png new file mode 100644 index 000000000..16f80bc32 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/textleft.png differ diff --git a/src/designer/src/components/formeditor/images/win/textright.png b/src/designer/src/components/formeditor/images/win/textright.png new file mode 100644 index 000000000..16872df62 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/textright.png differ diff --git a/src/designer/src/components/formeditor/images/win/textsubscript.png b/src/designer/src/components/formeditor/images/win/textsubscript.png new file mode 100644 index 000000000..d86347d83 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/textsubscript.png differ diff --git a/src/designer/src/components/formeditor/images/win/textsuperscript.png b/src/designer/src/components/formeditor/images/win/textsuperscript.png new file mode 100644 index 000000000..910996560 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/textsuperscript.png differ diff --git a/src/designer/src/components/formeditor/images/win/textunder.png b/src/designer/src/components/formeditor/images/win/textunder.png new file mode 100644 index 000000000..c72eff53f Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/textunder.png differ diff --git a/src/designer/src/components/formeditor/images/win/undo.png b/src/designer/src/components/formeditor/images/win/undo.png new file mode 100644 index 000000000..c3b8c5136 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/undo.png differ diff --git a/src/designer/src/components/formeditor/images/win/up.png b/src/designer/src/components/formeditor/images/win/up.png new file mode 100644 index 000000000..e43731221 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/up.png differ diff --git a/src/designer/src/components/formeditor/images/win/widgettool.png b/src/designer/src/components/formeditor/images/win/widgettool.png new file mode 100644 index 000000000..a52224e06 Binary files /dev/null and b/src/designer/src/components/formeditor/images/win/widgettool.png differ diff --git a/src/designer/src/components/formeditor/itemview_propertysheet.cpp b/src/designer/src/components/formeditor/itemview_propertysheet.cpp new file mode 100644 index 000000000..e04c55d5a --- /dev/null +++ b/src/designer/src/components/formeditor/itemview_propertysheet.cpp @@ -0,0 +1,270 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "itemview_propertysheet.h" + +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +struct Property { + Property() : m_sheet(0),m_id(-1) {} + Property(QDesignerPropertySheetExtension *sheet, int id) + : m_sheet(sheet), m_id(id) {} + + QDesignerPropertySheetExtension *m_sheet; + int m_id; +}; + +typedef QMap FakePropertyMap; + +struct ItemViewPropertySheetPrivate { + ItemViewPropertySheetPrivate(QDesignerFormEditorInterface *core, + QHeaderView *horizontalHeader, + QHeaderView *verticalHeader); + + inline QStringList realPropertyNames(); + inline QString fakePropertyName(const QString &prefix, const QString &realName); + + // Maps index of fake property to index of real property in respective sheet + FakePropertyMap m_propertyIdMap; + + // Maps name of fake property to name of real property + QHash m_propertyNameMap; + + QHash m_propertySheet; + QStringList m_realPropertyNames; +}; + +// Name of the fake group +static const char *headerGroup = "Header"; + +// Name of the real properties +static const char *visibleProperty = "visible"; +static const char *cascadingSectionResizesProperty = "cascadingSectionResizes"; +static const char *defaultSectionSizeProperty = "defaultSectionSize"; +static const char *highlightSectionsProperty = "highlightSections"; +static const char *minimumSectionSizeProperty = "minimumSectionSize"; +static const char *showSortIndicatorProperty = "showSortIndicator"; +static const char *stretchLastSectionProperty = "stretchLastSection"; +} // namespace qdesigner_internal + +using namespace qdesigner_internal; + + +/***************** ItemViewPropertySheetPrivate *********************/ + +ItemViewPropertySheetPrivate::ItemViewPropertySheetPrivate(QDesignerFormEditorInterface *core, + QHeaderView *horizontalHeader, + QHeaderView *verticalHeader) +{ + if (horizontalHeader) + m_propertySheet.insert(horizontalHeader, + qt_extension + (core->extensionManager(), horizontalHeader)); + if (verticalHeader) + m_propertySheet.insert(verticalHeader, + qt_extension + (core->extensionManager(), verticalHeader)); +} + +QStringList ItemViewPropertySheetPrivate::realPropertyNames() +{ + if (m_realPropertyNames.isEmpty()) + m_realPropertyNames + << QLatin1String(visibleProperty) + << QLatin1String(cascadingSectionResizesProperty) + << QLatin1String(defaultSectionSizeProperty) + << QLatin1String(highlightSectionsProperty) + << QLatin1String(minimumSectionSizeProperty) + << QLatin1String(showSortIndicatorProperty) + << QLatin1String(stretchLastSectionProperty); + return m_realPropertyNames; +} + +QString ItemViewPropertySheetPrivate::fakePropertyName(const QString &prefix, + const QString &realName) +{ + // prefix = "header", realPropertyName = "isVisible" returns "headerIsVisible" + QString fakeName = prefix + realName.at(0).toUpper() + realName.mid(1); + m_propertyNameMap.insert(fakeName, realName); + return fakeName; +} + +/***************** ItemViewPropertySheet *********************/ + +/*! + \class qdesigner_internal::ItemViewPropertySheet + + \brief + Adds header fake properties to QTreeView and QTableView objects + + QHeaderView objects are currently not shown in the object inspector. + This class adds some fake properties to the property sheet + of QTreeView and QTableView objects that nevertheless allow the manipulation + of the headers attached to the item view object. + + Currently the defaultAlignment property is not shown because the property sheet + would only show integers, instead of the Qt::Alignment enumeration. + + The fake properties here need special handling in QDesignerResource, uiloader and uic. + */ + +ItemViewPropertySheet::ItemViewPropertySheet(QTreeView *treeViewObject, QObject *parent) + : QDesignerPropertySheet(treeViewObject, parent), + d(new ItemViewPropertySheetPrivate(core(), treeViewObject->header(), 0)) +{ + initHeaderProperties(treeViewObject->header(), QLatin1String("header")); +} + +ItemViewPropertySheet::ItemViewPropertySheet(QTableView *tableViewObject, QObject *parent) + : QDesignerPropertySheet(tableViewObject, parent), + d(new ItemViewPropertySheetPrivate(core(), + tableViewObject->horizontalHeader(), + tableViewObject->verticalHeader())) +{ + initHeaderProperties(tableViewObject->horizontalHeader(), QLatin1String("horizontalHeader")); + initHeaderProperties(tableViewObject->verticalHeader(), QLatin1String("verticalHeader")); +} + +ItemViewPropertySheet::~ItemViewPropertySheet() +{ + delete d; +} + +void ItemViewPropertySheet::initHeaderProperties(QHeaderView *hv, const QString &prefix) +{ + QDesignerPropertySheetExtension *headerSheet = d->m_propertySheet.value(hv); + Q_ASSERT(headerSheet); + const QString headerGroupS = QLatin1String(headerGroup); + foreach (const QString &realPropertyName, d->realPropertyNames()) { + const int headerIndex = headerSheet->indexOf(realPropertyName); + Q_ASSERT(headerIndex != -1); + const QVariant defaultValue = realPropertyName == QLatin1String(visibleProperty) ? + QVariant(true) : headerSheet->property(headerIndex); + const QString fakePropertyName = d->fakePropertyName(prefix, realPropertyName); + const int fakeIndex = createFakeProperty(fakePropertyName, defaultValue); + d->m_propertyIdMap.insert(fakeIndex, Property(headerSheet, headerIndex)); + setAttribute(fakeIndex, true); + setPropertyGroup(fakeIndex, headerGroupS); + } +} + +/*! + Returns the mapping of fake property names to real property names + */ +QHash ItemViewPropertySheet::propertyNameMap() const +{ + return d->m_propertyNameMap; +} + +QVariant ItemViewPropertySheet::property(int index) const +{ + const FakePropertyMap::const_iterator it = d->m_propertyIdMap.constFind(index); + if (it != d->m_propertyIdMap.constEnd()) + return it.value().m_sheet->property(it.value().m_id); + return QDesignerPropertySheet::property(index); +} + +void ItemViewPropertySheet::setProperty(int index, const QVariant &value) +{ + const FakePropertyMap::iterator it = d->m_propertyIdMap.find(index); + if (it != d->m_propertyIdMap.end()) { + it.value().m_sheet->setProperty(it.value().m_id, value); + } else { + QDesignerPropertySheet::setProperty(index, value); + } +} + +void ItemViewPropertySheet::setChanged(int index, bool changed) +{ + const FakePropertyMap::iterator it = d->m_propertyIdMap.find(index); + if (it != d->m_propertyIdMap.end()) { + it.value().m_sheet->setChanged(it.value().m_id, changed); + } else { + QDesignerPropertySheet::setChanged(index, changed); + } +} + +bool ItemViewPropertySheet::isChanged(int index) const +{ + const FakePropertyMap::const_iterator it = d->m_propertyIdMap.constFind(index); + if (it != d->m_propertyIdMap.constEnd()) + return it.value().m_sheet->isChanged(it.value().m_id); + return QDesignerPropertySheet::isChanged(index); +} + +bool ItemViewPropertySheet::hasReset(int index) const +{ + const FakePropertyMap::const_iterator it = d->m_propertyIdMap.constFind(index); + if (it != d->m_propertyIdMap.constEnd()) + return it.value().m_sheet->hasReset(it.value().m_id); + return QDesignerPropertySheet::hasReset(index); +} + +bool ItemViewPropertySheet::reset(int index) +{ + const FakePropertyMap::iterator it = d->m_propertyIdMap.find(index); + if (it != d->m_propertyIdMap.end()) { + QDesignerPropertySheetExtension *headerSheet = it.value().m_sheet; + const int headerIndex = it.value().m_id; + const bool resetRC = headerSheet->reset(headerIndex); + // Resetting for "visible" might fail and the stored default + // of the Widget database is "false" due to the widget not being + // visible at the time it was determined. Reset to "true" manually. + if (!resetRC && headerSheet->propertyName(headerIndex) == QLatin1String(visibleProperty)) { + headerSheet->setProperty(headerIndex, QVariant(true)); + headerSheet->setChanged(headerIndex, false); + return true; + } + return resetRC; + } else { + return QDesignerPropertySheet::reset(index); + } +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/itemview_propertysheet.h b/src/designer/src/components/formeditor/itemview_propertysheet.h new file mode 100644 index 000000000..59cf809c8 --- /dev/null +++ b/src/designer/src/components/formeditor/itemview_propertysheet.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ITEMVIEW_PROPERTYSHEET_H +#define ITEMVIEW_PROPERTYSHEET_H + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +struct ItemViewPropertySheetPrivate; + +class ItemViewPropertySheet: public QDesignerPropertySheet +{ + Q_OBJECT + Q_INTERFACES(QDesignerPropertySheetExtension) +public: + explicit ItemViewPropertySheet(QTreeView *treeViewObject, QObject *parent = 0); + explicit ItemViewPropertySheet(QTableView *tableViewObject, QObject *parent = 0); + ~ItemViewPropertySheet(); + + QHash propertyNameMap() const; + + // QDesignerPropertySheet + QVariant property(int index) const; + void setProperty(int index, const QVariant &value); + + virtual void setChanged(int index, bool changed); + virtual bool isChanged(int index) const; + + virtual bool hasReset(int index) const; + virtual bool reset(int index); + +private: + void initHeaderProperties(QHeaderView *hv, const QString &prefix); + + ItemViewPropertySheetPrivate *d; +}; + +typedef QDesignerPropertySheetFactory + QTreeViewPropertySheetFactory; +typedef QDesignerPropertySheetFactory + QTableViewPropertySheetFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // ITEMVIEW_PROPERTYSHEET_H diff --git a/src/designer/src/components/formeditor/layout_propertysheet.cpp b/src/designer/src/components/formeditor/layout_propertysheet.cpp new file mode 100644 index 000000000..34e51b178 --- /dev/null +++ b/src/designer/src/components/formeditor/layout_propertysheet.cpp @@ -0,0 +1,546 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "layout_propertysheet.h" + +// sdk +#include +#include + +// shared +#include +#include +#include + +#include + +#include +#include +#include +#include +#include // Remove once there is an editor for lists + +QT_BEGIN_NAMESPACE + +#define USE_LAYOUT_SIZE_CONSTRAINT + +static const char *leftMargin = "leftMargin"; +static const char *topMargin = "topMargin"; +static const char *rightMargin = "rightMargin"; +static const char *bottomMargin = "bottomMargin"; +static const char *horizontalSpacing = "horizontalSpacing"; +static const char *verticalSpacing = "verticalSpacing"; +static const char *spacing = "spacing"; +static const char *margin = "margin"; +static const char *sizeConstraint = "sizeConstraint"; +static const char *boxStretchPropertyC = "stretch"; +static const char *gridRowStretchPropertyC = "rowStretch"; +static const char *gridColumnStretchPropertyC = "columnStretch"; +static const char *gridRowMinimumHeightPropertyC = "rowMinimumHeight"; +static const char *gridColumnMinimumWidthPropertyC = "columnMinimumWidth"; + +namespace { + enum LayoutPropertyType { + LayoutPropertyNone, + LayoutPropertyMargin, // Deprecated + LayoutPropertyLeftMargin, + LayoutPropertyTopMargin, + LayoutPropertyRightMargin, + LayoutPropertyBottomMargin, + LayoutPropertySpacing, + LayoutPropertyHorizontalSpacing, + LayoutPropertyVerticalSpacing, + LayoutPropertySizeConstraint, + LayoutPropertyBoxStretch, + LayoutPropertyGridRowStretch, + LayoutPropertyGridColumnStretch, + LayoutPropertyGridRowMinimumHeight, + LayoutPropertyGridColumnMinimumWidth + }; +} + +// Check for a comma-separated list of integers. Used for +// per-cell stretch properties and grid per row/column properties. +// As it works now, they are passed as QByteArray strings. The +// property sheet refuses all invalid values. This could be +// replaced by lists once the property editor can handle them. + +static bool isIntegerList(const QString &s) +{ + // Check for empty string or comma-separated list of integers + static const QRegExp re(QLatin1String("[0-9]+(,[0-9]+)+")); + Q_ASSERT(re.isValid()); + return s.isEmpty() || re.exactMatch(s); +} + +// Quick lookup by name +static LayoutPropertyType layoutPropertyType(const QString &name) +{ + static QHash namePropertyMap; + if (namePropertyMap.empty()) { + namePropertyMap.insert(QLatin1String(leftMargin), LayoutPropertyLeftMargin); + namePropertyMap.insert(QLatin1String(topMargin), LayoutPropertyTopMargin); + namePropertyMap.insert(QLatin1String(rightMargin), LayoutPropertyRightMargin); + namePropertyMap.insert(QLatin1String(bottomMargin), LayoutPropertyBottomMargin); + namePropertyMap.insert(QLatin1String(horizontalSpacing), LayoutPropertyHorizontalSpacing); + namePropertyMap.insert(QLatin1String(verticalSpacing), LayoutPropertyVerticalSpacing); + namePropertyMap.insert(QLatin1String(spacing), LayoutPropertySpacing); + namePropertyMap.insert(QLatin1String(margin), LayoutPropertyMargin); + namePropertyMap.insert(QLatin1String(sizeConstraint), LayoutPropertySizeConstraint); + namePropertyMap.insert(QLatin1String(boxStretchPropertyC ), LayoutPropertyBoxStretch); + namePropertyMap.insert(QLatin1String(gridRowStretchPropertyC), LayoutPropertyGridRowStretch); + namePropertyMap.insert(QLatin1String(gridColumnStretchPropertyC), LayoutPropertyGridColumnStretch); + namePropertyMap.insert(QLatin1String(gridRowMinimumHeightPropertyC), LayoutPropertyGridRowMinimumHeight); + namePropertyMap.insert(QLatin1String(gridColumnMinimumWidthPropertyC), LayoutPropertyGridColumnMinimumWidth); + } + return namePropertyMap.value(name, LayoutPropertyNone); +} + +// return the layout margin if it is margin +static int getLayoutMargin(const QLayout *l, LayoutPropertyType type) +{ + int left, top, right, bottom; + l->getContentsMargins(&left, &top, &right, &bottom); + switch (type) { + case LayoutPropertyLeftMargin: + return left; + case LayoutPropertyTopMargin: + return top; + case LayoutPropertyRightMargin: + return right; + case LayoutPropertyBottomMargin: + return bottom; + default: + Q_ASSERT(0); + break; + } + return 0; +} + +// return the layout margin if it is margin +static void setLayoutMargin(QLayout *l, LayoutPropertyType type, int margin) +{ + int left, top, right, bottom; + l->getContentsMargins(&left, &top, &right, &bottom); + switch (type) { + case LayoutPropertyLeftMargin: + left = margin; + break; + case LayoutPropertyTopMargin: + top = margin; + break; + case LayoutPropertyRightMargin: + right = margin; + break; + case LayoutPropertyBottomMargin: + bottom = margin; + break; + default: + Q_ASSERT(0); + break; + } + l->setContentsMargins(left, top, right, bottom); +} + +namespace qdesigner_internal { + +// ---------- LayoutPropertySheet: This sheet is never visible in +// the property editor. Rather, the sheet pulled for QLayoutWidget +// forwards all properties to it. Some properties (grid spacings) must be handled +// manually, as they are QDOC_PROPERTY only and not visible to introspection. Ditto +// for the 4 margins. + +LayoutPropertySheet::LayoutPropertySheet(QLayout *l, QObject *parent) + : QDesignerPropertySheet(l, parent), m_layout(l) +{ + const QString layoutGroup = QLatin1String("Layout"); + int pindex = createFakeProperty(QLatin1String(leftMargin), 0); + setPropertyGroup(pindex, layoutGroup); + + pindex = createFakeProperty(QLatin1String(topMargin), 0); + setPropertyGroup(pindex, layoutGroup); + + pindex = createFakeProperty(QLatin1String(rightMargin), 0); + setPropertyGroup(pindex, layoutGroup); + + pindex = createFakeProperty(QLatin1String(bottomMargin), 0); + setPropertyGroup(pindex, layoutGroup); + + const int visibleMask = LayoutProperties::visibleProperties(m_layout); + if (visibleMask & LayoutProperties::HorizSpacingProperty) { + pindex = createFakeProperty(QLatin1String(horizontalSpacing), 0); + setPropertyGroup(pindex, layoutGroup); + + pindex = createFakeProperty(QLatin1String(verticalSpacing), 0); + setPropertyGroup(pindex, layoutGroup); + + setAttribute(indexOf(QLatin1String(spacing)), true); + } + + setAttribute(indexOf(QLatin1String(margin)), true); + // Stretch + if (visibleMask & LayoutProperties::BoxStretchProperty) { + pindex = createFakeProperty(QLatin1String(boxStretchPropertyC), QByteArray()); + setPropertyGroup(pindex, layoutGroup); + setAttribute(pindex, true); + } else { + // Add the grid per-row/column stretch and size limits + if (visibleMask & LayoutProperties::GridColumnStretchProperty) { + const QByteArray empty; + pindex = createFakeProperty(QLatin1String(gridRowStretchPropertyC), empty); + setPropertyGroup(pindex, layoutGroup); + setAttribute(pindex, true); + pindex = createFakeProperty(QLatin1String(gridColumnStretchPropertyC), empty); + setPropertyGroup(pindex, layoutGroup); + setAttribute(pindex, true); + pindex = createFakeProperty(QLatin1String(gridRowMinimumHeightPropertyC), empty); + setPropertyGroup(pindex, layoutGroup); + setAttribute(pindex, true); + pindex = createFakeProperty(QLatin1String(gridColumnMinimumWidthPropertyC), empty); + setPropertyGroup(pindex, layoutGroup); + setAttribute(pindex, true); + } + } +#ifdef USE_LAYOUT_SIZE_CONSTRAINT + // SizeConstraint cannot possibly be handled as a real property + // as it affects the layout parent widget and thus + // conflicts with Designer's special layout widget. + // It will take effect on the preview only. + pindex = createFakeProperty(QLatin1String(sizeConstraint)); + setPropertyGroup(pindex, layoutGroup); +#endif +} + +LayoutPropertySheet::~LayoutPropertySheet() +{ +} + +void LayoutPropertySheet::setProperty(int index, const QVariant &value) +{ + const LayoutPropertyType type = layoutPropertyType(propertyName(index)); + if (QLayoutWidget *lw = qobject_cast(m_layout->parent())) { + switch (type) { + case LayoutPropertyLeftMargin: + lw->setLayoutLeftMargin(value.toInt()); + return; + case LayoutPropertyTopMargin: + lw->setLayoutTopMargin(value.toInt()); + return; + case LayoutPropertyRightMargin: + lw->setLayoutRightMargin(value.toInt()); + return; + case LayoutPropertyBottomMargin: + lw->setLayoutBottomMargin(value.toInt()); + return; + case LayoutPropertyMargin: { + const int v = value.toInt(); + lw->setLayoutLeftMargin(v); + lw->setLayoutTopMargin(v); + lw->setLayoutRightMargin(v); + lw->setLayoutBottomMargin(v); + } + return; + default: + break; + } + } + switch (type) { + case LayoutPropertyLeftMargin: + case LayoutPropertyTopMargin: + case LayoutPropertyRightMargin: + case LayoutPropertyBottomMargin: + setLayoutMargin(m_layout, type, value.toInt()); + return; + case LayoutPropertyHorizontalSpacing: + if (QGridLayout *grid = qobject_cast(m_layout)) { + grid->setHorizontalSpacing(value.toInt()); + return; + } + if (QFormLayout *form = qobject_cast(m_layout)) { + form->setHorizontalSpacing(value.toInt()); + return; + } + break; + case LayoutPropertyVerticalSpacing: + if (QGridLayout *grid = qobject_cast(m_layout)) { + grid->setVerticalSpacing(value.toInt()); + return; + } + if (QFormLayout *form = qobject_cast(m_layout)) { + form->setVerticalSpacing(value.toInt()); + return; + } + break; + case LayoutPropertyBoxStretch: + // TODO: Remove the regexp check once a proper editor for integer + // lists is in place? + if (QBoxLayout *box = qobject_cast(m_layout)) { + const QString stretch = value.toString(); + if (isIntegerList(stretch)) + QFormBuilderExtra::setBoxLayoutStretch(value.toString(), box); + } + break; + case LayoutPropertyGridRowStretch: + if (QGridLayout *grid = qobject_cast(m_layout)) { + const QString stretch = value.toString(); + if (isIntegerList(stretch)) + QFormBuilderExtra::setGridLayoutRowStretch(stretch, grid); + } + break; + case LayoutPropertyGridColumnStretch: + if (QGridLayout *grid = qobject_cast(m_layout)) { + const QString stretch = value.toString(); + if (isIntegerList(stretch)) + QFormBuilderExtra::setGridLayoutColumnStretch(value.toString(), grid); + } + break; + case LayoutPropertyGridRowMinimumHeight: + if (QGridLayout *grid = qobject_cast(m_layout)) { + const QString minSize = value.toString(); + if (isIntegerList(minSize)) + QFormBuilderExtra::setGridLayoutRowMinimumHeight(minSize, grid); + } + break; + case LayoutPropertyGridColumnMinimumWidth: + if (QGridLayout *grid = qobject_cast(m_layout)) { + const QString minSize = value.toString(); + if (isIntegerList(minSize)) + QFormBuilderExtra::setGridLayoutColumnMinimumWidth(minSize, grid); + } + break; + default: + break; + } + QDesignerPropertySheet::setProperty(index, value); +} + +QVariant LayoutPropertySheet::property(int index) const +{ + const LayoutPropertyType type = layoutPropertyType(propertyName(index)); + if (const QLayoutWidget *lw = qobject_cast(m_layout->parent())) { + switch (type) { + case LayoutPropertyLeftMargin: + return lw->layoutLeftMargin(); + case LayoutPropertyTopMargin: + return lw->layoutTopMargin(); + case LayoutPropertyRightMargin: + return lw->layoutRightMargin(); + case LayoutPropertyBottomMargin: + return lw->layoutBottomMargin(); + default: + break; + } + } + switch (type) { + case LayoutPropertyLeftMargin: + case LayoutPropertyTopMargin: + case LayoutPropertyRightMargin: + case LayoutPropertyBottomMargin: + return getLayoutMargin(m_layout, type); + case LayoutPropertyHorizontalSpacing: + if (const QGridLayout *grid = qobject_cast(m_layout)) + return grid->horizontalSpacing(); + if (const QFormLayout *form = qobject_cast(m_layout)) + return form->horizontalSpacing(); + break; + case LayoutPropertyVerticalSpacing: + if (const QGridLayout *grid = qobject_cast(m_layout)) + return grid->verticalSpacing(); + if (const QFormLayout *form = qobject_cast(m_layout)) + return form->verticalSpacing(); + case LayoutPropertyBoxStretch: + if (const QBoxLayout *box = qobject_cast(m_layout)) + return QVariant(QByteArray(QFormBuilderExtra::boxLayoutStretch(box).toUtf8())); + break; + case LayoutPropertyGridRowStretch: + if (const QGridLayout *grid = qobject_cast(m_layout)) + return QVariant(QByteArray(QFormBuilderExtra::gridLayoutRowStretch(grid).toUtf8())); + break; + case LayoutPropertyGridColumnStretch: + if (const QGridLayout *grid = qobject_cast(m_layout)) + return QVariant(QByteArray(QFormBuilderExtra::gridLayoutColumnStretch(grid).toUtf8())); + break; + case LayoutPropertyGridRowMinimumHeight: + if (const QGridLayout *grid = qobject_cast(m_layout)) + return QVariant(QByteArray(QFormBuilderExtra::gridLayoutRowMinimumHeight(grid).toUtf8())); + break; + case LayoutPropertyGridColumnMinimumWidth: + if (const QGridLayout *grid = qobject_cast(m_layout)) + return QVariant(QByteArray(QFormBuilderExtra::gridLayoutColumnMinimumWidth(grid).toUtf8())); + break; + default: + break; + } + return QDesignerPropertySheet::property(index); +} + +bool LayoutPropertySheet::reset(int index) +{ + int left, top, right, bottom; + m_layout->getContentsMargins(&left, &top, &right, &bottom); + const LayoutPropertyType type = layoutPropertyType(propertyName(index)); + bool rc = true; + switch (type) { + case LayoutPropertyLeftMargin: + m_layout->setContentsMargins(-1, top, right, bottom); + break; + case LayoutPropertyTopMargin: + m_layout->setContentsMargins(left, -1, right, bottom); + break; + case LayoutPropertyRightMargin: + m_layout->setContentsMargins(left, top, -1, bottom); + break; + case LayoutPropertyBottomMargin: + m_layout->setContentsMargins(left, top, right, -1); + break; + case LayoutPropertyBoxStretch: + if (QBoxLayout *box = qobject_cast(m_layout)) + QFormBuilderExtra::clearBoxLayoutStretch(box); + break; + case LayoutPropertyGridRowStretch: + if (QGridLayout *grid = qobject_cast(m_layout)) + QFormBuilderExtra::clearGridLayoutRowStretch(grid); + break; + case LayoutPropertyGridColumnStretch: + if (QGridLayout *grid = qobject_cast(m_layout)) + QFormBuilderExtra::clearGridLayoutColumnStretch(grid); + break; + case LayoutPropertyGridRowMinimumHeight: + if (QGridLayout *grid = qobject_cast(m_layout)) + QFormBuilderExtra::clearGridLayoutRowMinimumHeight(grid); + break; + case LayoutPropertyGridColumnMinimumWidth: + if (QGridLayout *grid = qobject_cast(m_layout)) + QFormBuilderExtra::clearGridLayoutColumnMinimumWidth(grid); + break; + default: + rc = QDesignerPropertySheet::reset(index); + break; + } + return rc; +} + +void LayoutPropertySheet::setChanged(int index, bool changed) +{ + const LayoutPropertyType type = layoutPropertyType(propertyName(index)); + switch (type) { + case LayoutPropertySpacing: + if (LayoutProperties::visibleProperties(m_layout) & LayoutProperties::HorizSpacingProperty) { + setChanged(indexOf(QLatin1String(horizontalSpacing)), changed); + setChanged(indexOf(QLatin1String(verticalSpacing)), changed); + } + break; + case LayoutPropertyMargin: + setChanged(indexOf(QLatin1String(leftMargin)), changed); + setChanged(indexOf(QLatin1String(topMargin)), changed); + setChanged(indexOf(QLatin1String(rightMargin)), changed); + setChanged(indexOf(QLatin1String(bottomMargin)), changed); + break; + default: + break; + } + QDesignerPropertySheet::setChanged(index, changed); +} + +void LayoutPropertySheet::stretchAttributesToDom(QDesignerFormEditorInterface *core, QLayout *lt, DomLayout *domLayout) +{ + // Check if the respective stretch properties of the layout are changed. + // If so, set them to the DOM + const int visibleMask = LayoutProperties::visibleProperties(lt); + if (!(visibleMask & (LayoutProperties::BoxStretchProperty|LayoutProperties::GridColumnStretchProperty|LayoutProperties::GridRowStretchProperty))) + return; + const QDesignerPropertySheetExtension *sheet = qt_extension(core->extensionManager(), lt); + Q_ASSERT(sheet); + + // Stretch + if (visibleMask & LayoutProperties::BoxStretchProperty) { + const int index = sheet->indexOf(QLatin1String(boxStretchPropertyC)); + Q_ASSERT(index != -1); + if (sheet->isChanged(index)) + domLayout->setAttributeStretch(sheet->property(index).toString()); + } + if (visibleMask & LayoutProperties::GridColumnStretchProperty) { + const int index = sheet->indexOf(QLatin1String(gridColumnStretchPropertyC)); + Q_ASSERT(index != -1); + if (sheet->isChanged(index)) + domLayout->setAttributeColumnStretch(sheet->property(index).toString()); + } + if (visibleMask & LayoutProperties::GridRowStretchProperty) { + const int index = sheet->indexOf(QLatin1String(gridRowStretchPropertyC)); + Q_ASSERT(index != -1); + if (sheet->isChanged(index)) + domLayout->setAttributeRowStretch(sheet->property(index).toString()); + } + if (visibleMask & LayoutProperties::GridRowMinimumHeightProperty) { + const int index = sheet->indexOf(QLatin1String(gridRowMinimumHeightPropertyC)); + Q_ASSERT(index != -1); + if (sheet->isChanged(index)) + domLayout->setAttributeRowMinimumHeight(sheet->property(index).toString()); + } + if (visibleMask & LayoutProperties::GridColumnMinimumWidthProperty) { + const int index = sheet->indexOf(QLatin1String(gridColumnMinimumWidthPropertyC)); + Q_ASSERT(index != -1); + if (sheet->isChanged(index)) + domLayout->setAttributeColumnMinimumWidth(sheet->property(index).toString()); + } +} + +void LayoutPropertySheet::markChangedStretchProperties(QDesignerFormEditorInterface *core, QLayout *lt, const DomLayout *domLayout) +{ + // While the actual values are applied by the form builder, we still need + // to mark them as 'changed'. + QDesignerPropertySheetExtension *sheet = qt_extension(core->extensionManager(), lt); + Q_ASSERT(sheet); + if (!domLayout->attributeStretch().isEmpty()) + sheet->setChanged(sheet->indexOf(QLatin1String(boxStretchPropertyC)), true); + if (!domLayout->attributeRowStretch().isEmpty()) + sheet->setChanged(sheet->indexOf(QLatin1String(gridRowStretchPropertyC)), true); + if (!domLayout->attributeColumnStretch().isEmpty()) + sheet->setChanged(sheet->indexOf(QLatin1String(gridColumnStretchPropertyC)), true); + if (!domLayout->attributeColumnMinimumWidth().isEmpty()) + sheet->setChanged(sheet->indexOf(QLatin1String(gridColumnMinimumWidthPropertyC)), true); + if (!domLayout->attributeRowMinimumHeight().isEmpty()) + sheet->setChanged(sheet->indexOf(QLatin1String(gridRowMinimumHeightPropertyC)), true); +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/layout_propertysheet.h b/src/designer/src/components/formeditor/layout_propertysheet.h new file mode 100644 index 000000000..72a59f876 --- /dev/null +++ b/src/designer/src/components/formeditor/layout_propertysheet.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LAYOUT_PROPERTYSHEET_H +#define LAYOUT_PROPERTYSHEET_H + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class DomLayout; + +namespace qdesigner_internal { + +class LayoutPropertySheet: public QDesignerPropertySheet +{ + Q_OBJECT + Q_INTERFACES(QDesignerPropertySheetExtension) +public: + explicit LayoutPropertySheet(QLayout *object, QObject *parent = 0); + virtual ~LayoutPropertySheet(); + + virtual void setProperty(int index, const QVariant &value); + virtual QVariant property(int index) const; + virtual bool reset(int index); + void setChanged(int index, bool changed); + + static void stretchAttributesToDom(QDesignerFormEditorInterface *core, QLayout *lt, DomLayout *domLayout); + static void markChangedStretchProperties(QDesignerFormEditorInterface *core, QLayout *lt, const DomLayout *domLayout); + +private: + QLayout *m_layout; +}; + +typedef QDesignerPropertySheetFactory LayoutPropertySheetFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // LAYOUT_PROPERTYSHEET_H diff --git a/src/designer/src/components/formeditor/line_propertysheet.cpp b/src/designer/src/components/formeditor/line_propertysheet.cpp new file mode 100644 index 000000000..64699eaa5 --- /dev/null +++ b/src/designer/src/components/formeditor/line_propertysheet.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "line_propertysheet.h" +#include "formwindow.h" + +// sdk +#include + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +LinePropertySheet::LinePropertySheet(Line *object, QObject *parent) + : QDesignerPropertySheet(object, parent) +{ + clearFakeProperties(); +} + +LinePropertySheet::~LinePropertySheet() +{ +} + +bool LinePropertySheet::isVisible(int index) const +{ + const QString name = propertyName(index); + + if (name == QLatin1String("frameShape")) + return false; + return QDesignerPropertySheet::isVisible(index); +} + +void LinePropertySheet::setProperty(int index, const QVariant &value) +{ + QDesignerPropertySheet::setProperty(index, value); +} + +QString LinePropertySheet::propertyGroup(int index) const +{ + return QDesignerPropertySheet::propertyGroup(index); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/line_propertysheet.h b/src/designer/src/components/formeditor/line_propertysheet.h new file mode 100644 index 000000000..ec1c098f3 --- /dev/null +++ b/src/designer/src/components/formeditor/line_propertysheet.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LINE_PROPERTYSHEET_H +#define LINE_PROPERTYSHEET_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class LinePropertySheet: public QDesignerPropertySheet +{ + Q_OBJECT + Q_INTERFACES(QDesignerPropertySheetExtension) +public: + explicit LinePropertySheet(Line *object, QObject *parent = 0); + virtual ~LinePropertySheet(); + + virtual void setProperty(int index, const QVariant &value); + virtual bool isVisible(int index) const; + virtual QString propertyGroup(int index) const; +}; + +typedef QDesignerPropertySheetFactory LinePropertySheetFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // LINE_PROPERTYSHEET_H diff --git a/src/designer/src/components/formeditor/previewactiongroup.cpp b/src/designer/src/components/formeditor/previewactiongroup.cpp new file mode 100644 index 000000000..607212c41 --- /dev/null +++ b/src/designer/src/components/formeditor/previewactiongroup.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "previewactiongroup.h" + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +enum { MaxDeviceActions = 20 }; + +namespace qdesigner_internal { + +PreviewActionGroup::PreviewActionGroup(QDesignerFormEditorInterface *core, QObject *parent) : + QActionGroup(parent), + m_core(core) +{ + /* Create a list of up to MaxDeviceActions invisible actions to be + * populated with device profiles (actiondata: index) followed by the + * standard style actions (actiondata: style name). */ + connect(this, SIGNAL(triggered(QAction*)), this, SLOT(slotTriggered(QAction*))); + setExclusive(true); + + const QString objNamePostfix = QLatin1String("_action"); + // Create invisible actions for devices. Set index as action data. + QString objNamePrefix = QLatin1String("__qt_designer_device_"); + for (int i = 0; i < MaxDeviceActions; i++) { + QAction *a = new QAction(this); + QString objName = objNamePrefix; + objName += QString::number(i); + objName += objNamePostfix; + a->setObjectName(objName); + a->setVisible(false); + a->setData(i); + addAction(a); + } + // Create separator at index MaxDeviceActions + QAction *sep = new QAction(this); + sep->setObjectName(QLatin1String("__qt_designer_deviceseparator")); + sep->setSeparator(true); + sep->setVisible(false); + addAction(sep); + // Populate devices + updateDeviceProfiles(); + + // Add style actions + const QStringList styles = QStyleFactory::keys(); + const QStringList::const_iterator cend = styles.constEnd(); + // Make sure ObjectName is unique in case toolbar solution is used. + objNamePrefix = QLatin1String("__qt_designer_style_"); + // Create styles. Set style name string as action data. + for (QStringList::const_iterator it = styles.constBegin(); it != cend ;++it) { + QAction *a = new QAction(tr("%1 Style").arg(*it), this); + QString objName = objNamePrefix; + objName += *it; + objName += objNamePostfix; + a->setObjectName(objName); + a->setData(*it); + addAction(a); + } +} + +void PreviewActionGroup::updateDeviceProfiles() +{ + typedef QList DeviceProfileList; + typedef QList ActionList; + + const QDesignerSharedSettings settings(m_core); + const DeviceProfileList profiles = settings.deviceProfiles(); + const ActionList al = actions(); + // Separator? + const bool hasProfiles = !profiles.empty(); + al.at(MaxDeviceActions)->setVisible(hasProfiles); + int index = 0; + if (hasProfiles) { + // Make actions visible + const int maxIndex = qMin(static_cast(MaxDeviceActions), profiles.size()); + for (; index < maxIndex; index++) { + const QString name = profiles.at(index).name(); + al.at(index)->setText(name); + al.at(index)->setVisible(true); + } + } + // Hide rest + for ( ; index < MaxDeviceActions; index++) + al.at(index)->setVisible(false); +} + +void PreviewActionGroup::slotTriggered(QAction *a) +{ + // Device or style according to data. + const QVariant data = a->data(); + switch (data.type()) { + case QVariant::String: + emit preview(data.toString(), -1); + break; + case QVariant::Int: + emit preview(QString(), data.toInt()); + break; + default: + break; + } +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/previewactiongroup.h b/src/designer/src/components/formeditor/previewactiongroup.h new file mode 100644 index 000000000..9ba65512b --- /dev/null +++ b/src/designer/src/components/formeditor/previewactiongroup.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef PREVIEWACTIONGROUP_H +#define PREVIEWACTIONGROUP_H + +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +/* PreviewActionGroup: To be used as a submenu for 'Preview in...' + * Offers a menu of styles and device profiles. */ + +class PreviewActionGroup : public QActionGroup +{ + Q_DISABLE_COPY(PreviewActionGroup) + Q_OBJECT +public: + explicit PreviewActionGroup(QDesignerFormEditorInterface *core, QObject *parent = 0); + +signals: + void preview(const QString &style, int deviceProfileIndex); + +public slots: + void updateDeviceProfiles(); + +private slots: + void slotTriggered(QAction *); + +private: + QDesignerFormEditorInterface *m_core; +}; +} + +QT_END_NAMESPACE + +#endif // PREVIEWACTIONGROUP_H diff --git a/src/designer/src/components/formeditor/qdesigner_resource.cpp b/src/designer/src/components/formeditor/qdesigner_resource.cpp new file mode 100644 index 000000000..409a20e8d --- /dev/null +++ b/src/designer/src/components/formeditor/qdesigner_resource.cpp @@ -0,0 +1,2475 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_resource.h" +#include "formwindow.h" +#include "dynamicpropertysheet.h" +#include "qdesigner_tabwidget_p.h" +#include "qdesigner_toolbox_p.h" +#include "qdesigner_stackedbox_p.h" +#include "qdesigner_toolbar_p.h" +#include "qdesigner_dockwidget_p.h" +#include "qdesigner_menu_p.h" +#include "qdesigner_menubar_p.h" +#include "qdesigner_membersheet_p.h" +#include "qtresourcemodel_p.h" +#include "qmdiarea_container.h" +#include "qwizard_container.h" +#include "layout_propertysheet.h" + +#include +#include +#include +#include +#include + +// shared +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// sdk +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +Q_DECLARE_METATYPE(QWidgetList) + +QT_BEGIN_NAMESPACE + +namespace { + typedef QList DomPropertyList; +} + +static const char *currentUiVersion = "4.0"; +static const char *clipboardObjectName = "__qt_fake_top_level"; + +#define OLD_RESOURCE_FORMAT // Support pre 4.4 format. + +namespace qdesigner_internal { + +// -------------------- QDesignerResourceBuilder: A resource builder that works on the property sheet icon types. +class QDesignerResourceBuilder : public QResourceBuilder +{ +public: + QDesignerResourceBuilder(QDesignerFormEditorInterface *core, DesignerPixmapCache *pixmapCache, DesignerIconCache *iconCache); + + void setPixmapCache(DesignerPixmapCache *pixmapCache) { m_pixmapCache = pixmapCache; } + void setIconCache(DesignerIconCache *iconCache) { m_iconCache = iconCache; } + bool isSaveRelative() const { return m_saveRelative; } + void setSaveRelative(bool relative) { m_saveRelative = relative; } + QStringList usedQrcFiles() const { return m_usedQrcFiles.keys(); } +#ifdef OLD_RESOURCE_FORMAT + QStringList loadedQrcFiles() const { return m_loadedQrcFiles.keys(); } // needed only for loading old resource attribute of tag. +#endif + + virtual QVariant loadResource(const QDir &workingDirectory, const DomProperty *icon) const; + + virtual QVariant toNativeValue(const QVariant &value) const; + + virtual DomProperty *saveResource(const QDir &workingDirectory, const QVariant &value) const; + + virtual bool isResourceType(const QVariant &value) const; +private: + + QDesignerFormEditorInterface *m_core; + DesignerPixmapCache *m_pixmapCache; + DesignerIconCache *m_iconCache; + const QDesignerLanguageExtension *m_lang; + bool m_saveRelative; + mutable QMap m_usedQrcFiles; + mutable QMap m_loadedQrcFiles; +}; + +QDesignerResourceBuilder::QDesignerResourceBuilder(QDesignerFormEditorInterface *core, DesignerPixmapCache *pixmapCache, DesignerIconCache *iconCache) : + m_core(core), + m_pixmapCache(pixmapCache), + m_iconCache(iconCache), + m_lang(qt_extension(core->extensionManager(), core)), + m_saveRelative(true) +{ +} + +static inline void setIconPixmap(QIcon::Mode m, QIcon::State s, const QDir &workingDirectory, + QString path, PropertySheetIconValue &icon, + const QDesignerLanguageExtension *lang = 0) +{ + if (lang == 0 || !lang->isLanguageResource(path)) + path = QFileInfo(workingDirectory, path).absoluteFilePath(); + icon.setPixmap(m, s, PropertySheetPixmapValue(path)); +} + +QVariant QDesignerResourceBuilder::loadResource(const QDir &workingDirectory, const DomProperty *property) const +{ + switch (property->kind()) { + case DomProperty::Pixmap: { + PropertySheetPixmapValue pixmap; + DomResourcePixmap *dp = property->elementPixmap(); + if (!dp->text().isEmpty()) { + if (m_lang != 0 && m_lang->isLanguageResource(dp->text())) { + pixmap.setPath(dp->text()); + } else { + pixmap.setPath(QFileInfo(workingDirectory, dp->text()).absoluteFilePath()); + } +#ifdef OLD_RESOURCE_FORMAT + if (dp->hasAttributeResource()) + m_loadedQrcFiles.insert(QFileInfo(workingDirectory, dp->attributeResource()).absoluteFilePath(), false); +#endif + } + return QVariant::fromValue(pixmap); + } + + case DomProperty::IconSet: { + PropertySheetIconValue icon; + DomResourceIcon *di = property->elementIconSet(); + icon.setTheme(di->attributeTheme()); + if (const int flags = iconStateFlags(di)) { // new, post 4.4 format + if (flags & NormalOff) + setIconPixmap(QIcon::Normal, QIcon::Off, workingDirectory, di->elementNormalOff()->text(), icon, m_lang); + if (flags & NormalOn) + setIconPixmap(QIcon::Normal, QIcon::On, workingDirectory, di->elementNormalOn()->text(), icon, m_lang); + if (flags & DisabledOff) + setIconPixmap(QIcon::Disabled, QIcon::Off, workingDirectory, di->elementDisabledOff()->text(), icon, m_lang); + if (flags & DisabledOn) + setIconPixmap(QIcon::Disabled, QIcon::On, workingDirectory, di->elementDisabledOn()->text(), icon, m_lang); + if (flags & ActiveOff) + setIconPixmap(QIcon::Active, QIcon::Off, workingDirectory, di->elementActiveOff()->text(), icon, m_lang); + if (flags & ActiveOn) + setIconPixmap(QIcon::Active, QIcon::On, workingDirectory, di->elementActiveOn()->text(), icon, m_lang); + if (flags & SelectedOff) + setIconPixmap(QIcon::Selected, QIcon::Off, workingDirectory, di->elementSelectedOff()->text(), icon, m_lang); + if (flags & SelectedOn) + setIconPixmap(QIcon::Selected, QIcon::On, workingDirectory, di->elementSelectedOn()->text(), icon, m_lang); + } else { +#ifdef OLD_RESOURCE_FORMAT + setIconPixmap(QIcon::Normal, QIcon::Off, workingDirectory, di->text(), icon, m_lang); + if (di->hasAttributeResource()) + m_loadedQrcFiles.insert(QFileInfo(workingDirectory, di->attributeResource()).absoluteFilePath(), false); +#endif + } + return QVariant::fromValue(icon); + } + default: + break; + } + return QVariant(); +} + +QVariant QDesignerResourceBuilder::toNativeValue(const QVariant &value) const +{ + if (value.canConvert()) { + if (m_pixmapCache) + return m_pixmapCache->pixmap(qvariant_cast(value)); + } else if (value.canConvert()) { + if (m_iconCache) + return m_iconCache->icon(qvariant_cast(value)); + } + return value; +} + +DomProperty *QDesignerResourceBuilder::saveResource(const QDir &workingDirectory, const QVariant &value) const +{ + DomProperty *p = new DomProperty; + if (value.canConvert()) { + const PropertySheetPixmapValue pix = qvariant_cast(value); + DomResourcePixmap *rp = new DomResourcePixmap; + const QString pixPath = pix.path(); + switch (pix.pixmapSource(m_core)) { + case PropertySheetPixmapValue::LanguageResourcePixmap: + rp->setText(pixPath); + break; + case PropertySheetPixmapValue::ResourcePixmap: { + rp->setText(pixPath); + const QString qrcFile = m_core->resourceModel()->qrcPath(pixPath); + if (!qrcFile.isEmpty()) { + m_usedQrcFiles.insert(qrcFile, false); +#ifdef OLD_RESOURCE_FORMAT // Legacy: Add qrc path + rp->setAttributeResource(workingDirectory.relativeFilePath(qrcFile)); +#endif + } + } + break; + case PropertySheetPixmapValue::FilePixmap: + rp->setText(m_saveRelative ? workingDirectory.relativeFilePath(pixPath) : pixPath); + break; + } + p->setElementPixmap(rp); + return p; + } else if (value.canConvert()) { + const PropertySheetIconValue icon = qvariant_cast(value); + const QMap, PropertySheetPixmapValue> pixmaps = icon.paths(); + const QString theme = icon.theme(); + if (!pixmaps.isEmpty() || !theme.isEmpty()) { + DomResourceIcon *ri = new DomResourceIcon; + if (!theme.isEmpty()) + ri->setAttributeTheme(theme); + QMapIterator, PropertySheetPixmapValue> itPix(pixmaps); + while (itPix.hasNext()) { + const QIcon::Mode mode = itPix.next().key().first; + const QIcon::State state = itPix.key().second; + DomResourcePixmap *rp = new DomResourcePixmap; + const PropertySheetPixmapValue pix = itPix.value(); + const PropertySheetPixmapValue::PixmapSource ps = pix.pixmapSource(m_core); + const QString pixPath = pix.path(); + rp->setText(ps == PropertySheetPixmapValue::FilePixmap && m_saveRelative ? workingDirectory.relativeFilePath(pixPath) : pixPath); + if (state == QIcon::Off) { + switch (mode) { + case QIcon::Normal: + ri->setElementNormalOff(rp); +#ifdef OLD_RESOURCE_FORMAT // Legacy: Set Normal off as text/path in old format. + ri->setText(rp->text()); +#endif + if (ps == PropertySheetPixmapValue::ResourcePixmap) { + // Be sure that ri->text() file comes from active resourceSet (i.e. make appropriate + // resourceSet active before calling this method). + const QString qrcFile = m_core->resourceModel()->qrcPath(ri->text()); + if (!qrcFile.isEmpty()) { + m_usedQrcFiles.insert(qrcFile, false); +#ifdef OLD_RESOURCE_FORMAT // Legacy: Set Normal off as text/path in old format. + ri->setAttributeResource(workingDirectory.relativeFilePath(qrcFile)); +#endif + } + } + break; + case QIcon::Disabled: ri->setElementDisabledOff(rp); break; + case QIcon::Active: ri->setElementActiveOff(rp); break; + case QIcon::Selected: ri->setElementSelectedOff(rp); break; + } + } else { + switch (mode) { + case QIcon::Normal: ri->setElementNormalOn(rp); break; + case QIcon::Disabled: ri->setElementDisabledOn(rp); break; + case QIcon::Active: ri->setElementActiveOn(rp); break; + case QIcon::Selected: ri->setElementSelectedOn(rp); break; + } + } + } + p->setElementIconSet(ri); + return p; + } + } + delete p; + return 0; +} + +bool QDesignerResourceBuilder::isResourceType(const QVariant &value) const +{ + if (value.canConvert() || value.canConvert()) + return true; + return false; +} +// ------------------------- QDesignerTextBuilder +class QDesignerTextBuilder : public QTextBuilder +{ +public: + QDesignerTextBuilder() {} + + virtual QVariant loadText(const DomProperty *icon) const; + + virtual QVariant toNativeValue(const QVariant &value) const; + + virtual DomProperty *saveText(const QVariant &value) const; +}; + +QVariant QDesignerTextBuilder::loadText(const DomProperty *text) const +{ + const DomString *str = text->elementString(); + PropertySheetStringValue strVal(str->text()); + if (str->hasAttributeComment()) { + strVal.setDisambiguation(str->attributeComment()); + } + if (str->hasAttributeExtraComment()) { + strVal.setComment(str->attributeExtraComment()); + } + if (str->hasAttributeNotr()) { + const QString notr = str->attributeNotr(); + const bool translatable = !(notr == QLatin1String("true") || notr == QLatin1String("yes")); + if (!translatable) + strVal.setTranslatable(translatable); + } + return QVariant::fromValue(strVal); +} + +QVariant QDesignerTextBuilder::toNativeValue(const QVariant &value) const +{ + if (value.canConvert()) + return QVariant::fromValue(qvariant_cast(value).value()); + return value; +} + +DomProperty *QDesignerTextBuilder::saveText(const QVariant &value) const +{ + if (!value.canConvert() && !value.canConvert()) + return 0; + + DomProperty *property = new DomProperty(); + DomString *domStr = new DomString(); + + if (value.canConvert()) { + PropertySheetStringValue str = qvariant_cast(value); + + domStr->setText(str.value()); + + const QString property_comment = str.disambiguation(); + if (!property_comment.isEmpty()) + domStr->setAttributeComment(property_comment); + const QString property_extraComment = str.comment(); + if (!property_extraComment.isEmpty()) + domStr->setAttributeExtraComment(property_extraComment); + const bool property_translatable = str.translatable(); + if (!property_translatable) + domStr->setAttributeNotr(QLatin1String("true")); + } else { + domStr->setText(value.toString()); + } + + property->setElementString(domStr); + return property; +} + +QDesignerResource::QDesignerResource(FormWindow *formWindow) : + QEditorFormBuilder(formWindow->core()), + m_formWindow(formWindow), + m_topLevelSpacerCount(0), + m_copyWidget(false), + m_selected(0), + m_resourceBuilder(new QDesignerResourceBuilder(m_formWindow->core(), m_formWindow->pixmapCache(), m_formWindow->iconCache())) +{ + setWorkingDirectory(formWindow->absoluteDir()); + setResourceBuilder(m_resourceBuilder); + setTextBuilder(new QDesignerTextBuilder()); + + // ### generalise + const QString designerWidget = QLatin1String("QDesignerWidget"); + const QString layoutWidget = QLatin1String("QLayoutWidget"); + const QString widget = QLatin1String("QWidget"); + m_internal_to_qt.insert(layoutWidget, widget); + m_internal_to_qt.insert(designerWidget, widget); + m_internal_to_qt.insert(QLatin1String("QDesignerDialog"), QLatin1String("QDialog")); + m_internal_to_qt.insert(QLatin1String("QDesignerMenuBar"), QLatin1String("QMenuBar")); + m_internal_to_qt.insert(QLatin1String("QDesignerMenu"), QLatin1String("QMenu")); + m_internal_to_qt.insert(QLatin1String("QDesignerDockWidget"), QLatin1String("QDockWidget")); + m_internal_to_qt.insert(QLatin1String("QDesignerQ3WidgetStack"), QLatin1String("Q3WidgetStack")); + + // invert + QHash::const_iterator cend = m_internal_to_qt.constEnd(); + for (QHash::const_iterator it = m_internal_to_qt.constBegin();it != cend; ++it ) { + if (it.value() != designerWidget && it.value() != layoutWidget) + m_qt_to_internal.insert(it.value(), it.key()); + + } +} + +QDesignerResource::~QDesignerResource() +{ +} + +static inline QString messageBoxTitle() +{ + return QApplication::translate("Designer", "Qt Designer"); +} + +void QDesignerResource::save(QIODevice *dev, QWidget *widget) +{ + m_topLevelSpacerCount = 0; + + QAbstractFormBuilder::save(dev, widget); + + if (QSimpleResource::warningsEnabled() && m_topLevelSpacerCount != 0) { + const QString message = QApplication::translate("Designer", "This file contains top level spacers.
" + "They have NOT been saved into the form."); + const QString infoMessage = QApplication::translate("Designer", "Perhaps you forgot to create a layout?"); + + core()->dialogGui()->message(widget->window(), QDesignerDialogGuiInterface::TopLevelSpacerMessage, + QMessageBox::Warning, messageBoxTitle(), message, infoMessage, + QMessageBox::Ok); + } +} + +void QDesignerResource::saveDom(DomUI *ui, QWidget *widget) +{ + QAbstractFormBuilder::saveDom(ui, widget); + + QDesignerPropertySheetExtension *sheet = qt_extension(core()->extensionManager(), widget); + Q_ASSERT(sheet != 0); + + const QVariant classVar = sheet->property(sheet->indexOf(QLatin1String("objectName"))); + QString classStr; + if (classVar.canConvert(QVariant::String)) + classStr = classVar.toString(); + else + classStr = qvariant_cast(classVar).value(); + ui->setElementClass(classStr); + + for (int index = 0; index < m_formWindow->toolCount(); ++index) { + QDesignerFormWindowToolInterface *tool = m_formWindow->tool(index); + Q_ASSERT(tool != 0); + tool->saveToDom(ui, widget); + } + + const QString author = m_formWindow->author(); + if (!author.isEmpty()) { + ui->setElementAuthor(author); + } + + const QString comment = m_formWindow->comment(); + if (!comment.isEmpty()) { + ui->setElementComment(comment); + } + + const QString exportMacro = m_formWindow->exportMacro(); + if (!exportMacro.isEmpty()) { + ui->setElementExportMacro(exportMacro); + } + + const QVariantMap designerFormData = m_formWindow->formData(); + if (!designerFormData.empty()) { + DomPropertyList domPropertyList; + const QVariantMap::const_iterator cend = designerFormData.constEnd(); + for (QVariantMap::const_iterator it = designerFormData.constBegin(); it != cend; ++it) { + if (DomProperty *prop = variantToDomProperty(this, widget->metaObject(), it.key(), it.value())) + domPropertyList += prop; + } + if (!domPropertyList.empty()) { + DomDesignerData* domDesignerFormData = new DomDesignerData; + domDesignerFormData->setElementProperty(domPropertyList); + ui->setElementDesignerdata(domDesignerFormData); + } + } + + if (!m_formWindow->includeHints().isEmpty()) { + const QString local = QLatin1String("local"); + const QString global = QLatin1String("global"); + QList ui_includes; + foreach (QString includeHint, m_formWindow->includeHints()) { + if (includeHint.isEmpty()) + continue; + DomInclude *incl = new DomInclude; + const QString location = includeHint.at(0) == QLatin1Char('<') ? global : local; + includeHint.remove(QLatin1Char('"')); + includeHint.remove(QLatin1Char('<')); + includeHint.remove(QLatin1Char('>')); + incl->setAttributeLocation(location); + incl->setText(includeHint); + ui_includes.append(incl); + } + + DomIncludes *includes = new DomIncludes; + includes->setElementInclude(ui_includes); + ui->setElementIncludes(includes); + } + + int defaultMargin = INT_MIN, defaultSpacing = INT_MIN; + m_formWindow->layoutDefault(&defaultMargin, &defaultSpacing); + + if (defaultMargin != INT_MIN || defaultSpacing != INT_MIN) { + DomLayoutDefault *def = new DomLayoutDefault; + if (defaultMargin != INT_MIN) + def->setAttributeMargin(defaultMargin); + if (defaultSpacing != INT_MIN) + def->setAttributeSpacing(defaultSpacing); + ui->setElementLayoutDefault(def); + } + + QString marginFunction, spacingFunction; + m_formWindow->layoutFunction(&marginFunction, &spacingFunction); + if (!marginFunction.isEmpty() || !spacingFunction.isEmpty()) { + DomLayoutFunction *def = new DomLayoutFunction; + + if (!marginFunction.isEmpty()) + def->setAttributeMargin(marginFunction); + if (!spacingFunction.isEmpty()) + def->setAttributeSpacing(spacingFunction); + ui->setElementLayoutFunction(def); + } + + QString pixFunction = m_formWindow->pixmapFunction(); + if (!pixFunction.isEmpty()) { + ui->setElementPixmapFunction(pixFunction); + } + + if (QDesignerExtraInfoExtension *extra = qt_extension(core()->extensionManager(), core())) + extra->saveUiExtraInfo(ui); + + if (MetaDataBase *metaDataBase = qobject_cast(core()->metaDataBase())) { + const MetaDataBaseItem *item = metaDataBase->metaDataBaseItem(m_formWindow->mainContainer()); + const QStringList fakeSlots = item->fakeSlots(); + const QStringList fakeSignals =item->fakeSignals(); + if (!fakeSlots.empty() || !fakeSignals.empty()) { + DomSlots *domSlots = new DomSlots(); + domSlots->setElementSlot(fakeSlots); + domSlots->setElementSignal(fakeSignals); + ui->setElementSlots(domSlots); + } + } +} + +namespace { + enum LoadPreCheck { LoadPreCheckFailed, LoadPreCheckVersion3, LoadPreCheckVersionMismatch, LoadPreCheckOk }; + // Pair of major, minor + typedef QPair UiVersion; +} + +static UiVersion uiVersion(const QString &attr) +{ + const QStringList versions = attr.split(QLatin1Char('.')); + if (versions.empty()) + return UiVersion(-1, -1); + + bool ok = false; + UiVersion rc(versions.at(0).toInt(&ok), 0); + + if (!ok) + return UiVersion(-1, -1); + + if (versions.size() > 1) { + const int minorVersion = versions.at(1).toInt(&ok); + if (ok) + rc.second = minorVersion; + } + return rc; +} + +// Read version and language attributes of an element. +static bool readUiAttributes(QIODevice *dev, QString *errorMessage, + QString *version, + QString *language) +{ + const QString uiElement = QLatin1String("ui"); + const QString versionAttribute = QLatin1String("version"); + const QString languageAttribute = QLatin1String("language"); + QXmlStreamReader reader(dev); + // Read up to first element + while (!reader.atEnd()) { + if (reader.readNext() == QXmlStreamReader::StartElement) { + const QStringRef tag = reader.name(); + if (reader.name().compare(uiElement, Qt::CaseInsensitive) == 0) { + const QXmlStreamAttributes attributes = reader.attributes(); + if (attributes.hasAttribute(versionAttribute)) + *version = attributes.value(versionAttribute).toString(); + if (attributes.hasAttribute(languageAttribute)) + *language = attributes.value(languageAttribute).toString(); + return true; + } else { + *errorMessage = QCoreApplication::translate("Designer", "Invalid UI file: The root element is missing."); + return false; + + } + } + } + *errorMessage = QCoreApplication::translate("Designer", "An error has occurred while reading the UI file at line %1, column %2: %3") + .arg(reader.lineNumber()).arg(reader.columnNumber()).arg(reader.errorString()); + return false; +} + +// While loading a file, check language, version and extra extension +static LoadPreCheck loadPrecheck(QDesignerFormEditorInterface *core, + QIODevice *dev, + QString *errorMessage, QString *versionString) +{ + QString language; + // Read attributes of and rewind + if (!readUiAttributes(dev, errorMessage, versionString, &language)) { + // XML error: Mimick the behaviour occurring if an XML error is + // detected later on, report to warning log and have embedding + // application display a dialog. + designerWarning(*errorMessage); + errorMessage->clear(); + return LoadPreCheckFailed; + } + dev->seek(0); + + // Check language unless extension present (Jambi) + if (!language.isEmpty() && !qt_extension(core->extensionManager(), core)) { + if (language.toLower() != QLatin1String("c++")) { + // Jambi?! + *errorMessage = QApplication::translate("Designer", "This file cannot be read because it was created using %1.").arg(language); + return LoadPreCheckFailed; + } + } + + // Version + if (!versionString->isEmpty()) { + const UiVersion version = uiVersion(*versionString); + switch (version.first) { + case 3: + return LoadPreCheckVersion3; + case 4: + break; + default: + *errorMessage = QApplication::translate("Designer", "This file was created using Designer from Qt-%1 and cannot be read.").arg(*versionString); + return LoadPreCheckVersionMismatch; + } + } + return LoadPreCheckOk; +} + +QWidget *QDesignerResource::load(QIODevice *dev, QWidget *parentWidget) +{ + // Run loadPreCheck for version and language + QString errorMessage; + QString version; + switch (loadPrecheck(core(), dev, &errorMessage, &version)) { + case LoadPreCheckFailed: + case LoadPreCheckVersionMismatch: + if (!errorMessage.isEmpty()) + core()->dialogGui()->message(parentWidget->window(), QDesignerDialogGuiInterface::FormLoadFailureMessage, + QMessageBox::Warning, messageBoxTitle(), errorMessage, QMessageBox::Ok); + return 0; + case LoadPreCheckVersion3: { + QWidget *w = 0; + QByteArray ba; + if (runUIC( m_formWindow->fileName(), UIC_ConvertV3, ba, errorMessage)) { + QBuffer buffer(&ba); + buffer.open(QIODevice::ReadOnly); + w = load(&buffer, parentWidget); + if (w) { + // Force the form to pop up a save file dialog + m_formWindow->setFileName(QString()); + } else { + errorMessage = QApplication::translate("Designer", "The converted file could not be read."); + } + } + if (w) { + const QString message = QApplication::translate("Designer", + "This file was created using Designer from Qt-%1 and" + " will be converted to a new form by Qt Designer.").arg(version); + const QString infoMessage = QApplication::translate("Designer", + "The old form has not been touched, but you will have to save the form" + " under a new name."); + + core()->dialogGui()->message(parentWidget->window(), + QDesignerDialogGuiInterface::UiVersionMismatchMessage, + QMessageBox::Information, messageBoxTitle(), message, infoMessage, + QMessageBox::Ok); + return w; + } + + const QString message = QApplication::translate("Designer", + "This file was created using Designer from Qt-%1 and " + "could not be read:\n%2").arg(version).arg(errorMessage); + const QString infoMessage = QApplication::translate("Designer", + "Please run it through uic3 -convert to convert " + "it to Qt-4's ui format."); + core()->dialogGui()->message(parentWidget->window(), QDesignerDialogGuiInterface::FormLoadFailureMessage, + QMessageBox::Warning, messageBoxTitle(), message, infoMessage, + QMessageBox::Ok); + return 0; + } + + case LoadPreCheckOk: + break; + } + QWidget *w = QEditorFormBuilder::load(dev, parentWidget); + if (w) // Store the class name as 'reset' value for the main container's object name. + w->setProperty("_q_classname", w->objectName()); + return w; +} + +bool QDesignerResource::saveRelative() const +{ + return m_resourceBuilder->isSaveRelative(); +} + +void QDesignerResource::setSaveRelative(bool relative) +{ + m_resourceBuilder->setSaveRelative(relative); +} + +QWidget *QDesignerResource::create(DomUI *ui, QWidget *parentWidget) +{ + // Load extra info extension. This is used by Jambi for preventing + // C++ UI files from being loaded + if (QDesignerExtraInfoExtension *extra = qt_extension(core()->extensionManager(), core())) { + if (!extra->loadUiExtraInfo(ui)) { + const QString errorMessage = QApplication::translate("Designer", "This file cannot be read because the extra info extension failed to load."); + core()->dialogGui()->message(parentWidget->window(), QDesignerDialogGuiInterface::FormLoadFailureMessage, + QMessageBox::Warning, messageBoxTitle(), errorMessage, QMessageBox::Ok); + return 0; + } + } + + qdesigner_internal::WidgetFactory *factory = qobject_cast(core()->widgetFactory()); + Q_ASSERT(factory != 0); + + QDesignerFormWindowInterface *previousFormWindow = factory->currentFormWindow(m_formWindow); + + m_isMainWidget = true; + QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem. + QWidget *mainWidget = QAbstractFormBuilder::create(ui, parentWidget); + + if (mainWidget && m_formWindow) { + m_formWindow->setAuthor(ui->elementAuthor()); + m_formWindow->setComment(ui->elementComment()); + m_formWindow->setExportMacro(ui->elementExportMacro()); + + // Designer data + QVariantMap designerFormData; + if (ui->hasElementDesignerdata()) { + const DomPropertyList domPropertyList = ui->elementDesignerdata()->elementProperty(); + const DomPropertyList::const_iterator cend = domPropertyList.constEnd(); + for (DomPropertyList::const_iterator it = domPropertyList.constBegin(); it != cend; ++it) { + const QVariant vprop = domPropertyToVariant(this, mainWidget->metaObject(), *it); + if (vprop.type() != QVariant::Invalid) + designerFormData.insert((*it)->attributeName(), vprop); + } + } + m_formWindow->setFormData(designerFormData); + + m_formWindow->setPixmapFunction(ui->elementPixmapFunction()); + + if (DomLayoutDefault *def = ui->elementLayoutDefault()) { + m_formWindow->setLayoutDefault(def->attributeMargin(), def->attributeSpacing()); + } + + if (DomLayoutFunction *fun = ui->elementLayoutFunction()) { + m_formWindow->setLayoutFunction(fun->attributeMargin(), fun->attributeSpacing()); + } + + if (DomIncludes *includes = ui->elementIncludes()) { + const QString global = QLatin1String("global"); + QStringList includeHints; + foreach (DomInclude *incl, includes->elementInclude()) { + QString text = incl->text(); + + if (text.isEmpty()) + continue; + + if (incl->hasAttributeLocation() && incl->attributeLocation() == global ) { + text = text.prepend(QLatin1Char('<')).append(QLatin1Char('>')); + } else { + text = text.prepend(QLatin1Char('"')).append(QLatin1Char('"')); + } + + includeHints.append(text); + } + + m_formWindow->setIncludeHints(includeHints); + } + + // Register all button groups the form builder adds as children of the main container for them to be found + // in the signal slot editor + const QObjectList mchildren = mainWidget->children(); + if (!mchildren.empty()) { + QDesignerMetaDataBaseInterface *mdb = core()->metaDataBase(); + const QObjectList::const_iterator cend = mchildren.constEnd(); + for (QObjectList::const_iterator it = mchildren.constBegin(); it != cend; ++it) + if (QButtonGroup *bg = qobject_cast(*it)) + mdb->add(bg); + } + // Load tools + for (int index = 0; index < m_formWindow->toolCount(); ++index) { + QDesignerFormWindowToolInterface *tool = m_formWindow->tool(index); + Q_ASSERT(tool != 0); + tool->loadFromDom(ui, mainWidget); + } + } + + factory->currentFormWindow(previousFormWindow); + + if (const DomSlots *domSlots = ui->elementSlots()) { + if (MetaDataBase *metaDataBase = qobject_cast(core()->metaDataBase())) { + QStringList fakeSlots; + QStringList fakeSignals; + if (addFakeMethods(domSlots, fakeSlots, fakeSignals)) { + MetaDataBaseItem *item = metaDataBase->metaDataBaseItem(mainWidget); + item->setFakeSlots(fakeSlots); + item->setFakeSignals(fakeSignals); + } + } + } + if (mainWidget) { + // Initialize the mainwindow geometry. Has it been explicitly specified? + bool hasExplicitGeometry = false; + const QList properties = ui->elementWidget()->elementProperty(); + if (!properties.empty()) { + const QString geometry = QLatin1String("geometry"); + foreach (const DomProperty *p, properties) + if (p->attributeName() == geometry) { + hasExplicitGeometry = true; + break; + } + } + if (hasExplicitGeometry) { + // Geometry was specified explicitly: Verify that smartMinSize is respected + // (changed fonts, label wrapping policies, etc). This does not happen automatically in docked mode. + const QSize size = mainWidget->size(); + const QSize minSize = size.expandedTo(qSmartMinSize(mainWidget)); + if (minSize != size) + mainWidget->resize(minSize); + } else { + // No explicit Geometry: perform an adjustSize() to resize the form correctly before embedding it into a container + // (which might otherwise squeeze the form) + mainWidget->adjustSize(); + } + // Some integration wizards create forms with main containers + // based on derived classes of QWidget and load them into Designer + // without the plugin existing. This will trigger the auto-promotion + // mechanism of Designer, which will set container=false for + // QWidgets. For the main container, force container=true and warn. + const QDesignerWidgetDataBaseInterface *wdb = core()->widgetDataBase(); + const int wdbIndex = wdb->indexOfObject(mainWidget); + if (wdbIndex != -1) { + QDesignerWidgetDataBaseItemInterface *item = wdb->item(wdbIndex); + // Promoted main container that is not of container type + if (item->isPromoted() && !item->isContainer()) { + item->setContainer(true); + qWarning("** WARNING The form's main container is an unknown custom widget '%s'." + " Defaulting to a promoted instance of '%s', assuming container.", + item->name().toUtf8().constData(), item->extends().toUtf8().constData()); + } + } + } + return mainWidget; +} + +QWidget *QDesignerResource::create(DomWidget *ui_widget, QWidget *parentWidget) +{ + const QString className = ui_widget->attributeClass(); + if (!m_isMainWidget && className == QLatin1String("QWidget") && ui_widget->elementLayout().size() && + !ui_widget->hasAttributeNative()) { + // ### check if elementLayout.size() == 1 + + QDesignerContainerExtension *container = qt_extension(core()->extensionManager(), parentWidget); + + if (container == 0) { + // generate a QLayoutWidget iff the parent is not an QDesignerContainerExtension. + ui_widget->setAttributeClass(QLatin1String("QLayoutWidget")); + } + } + + // save the actions + const QList actionRefs = ui_widget->elementAddAction(); + ui_widget->setElementAddAction(QList()); + + QWidget *w = QAbstractFormBuilder::create(ui_widget, parentWidget); + + // restore the actions + ui_widget->setElementAddAction(actionRefs); + + if (w == 0) + return 0; + + // ### generalize using the extension manager + QDesignerMenu *menu = qobject_cast(w); + QDesignerMenuBar *menuBar = qobject_cast(w); + + if (menu) { + menu->interactive(false); + menu->hide(); + } else if (menuBar) { + menuBar->interactive(false); + } + + foreach (DomActionRef *ui_action_ref, actionRefs) { + const QString name = ui_action_ref->attributeName(); + if (name == QLatin1String("separator")) { + QAction *sep = new QAction(w); + sep->setSeparator(true); + w->addAction(sep); + addMenuAction(sep); + } else if (QAction *a = m_actions.value(name)) { + w->addAction(a); + } else if (QActionGroup *g = m_actionGroups.value(name)) { + w->addActions(g->actions()); + } else if (QMenu *menu = w->findChild(name)) { + w->addAction(menu->menuAction()); + addMenuAction(menu->menuAction()); + } + } + + if (menu) { + menu->interactive(true); + menu->adjustSpecialActions(); + } else if (menuBar) { + menuBar->interactive(true); + menuBar->adjustSpecialActions(); + } + + ui_widget->setAttributeClass(className); // fix the class name + applyExtensionDataFromDOM(this, core(), ui_widget, w, true); + + // store user-defined scripts + if (MetaDataBase *metaDataBase = qobject_cast(core()->metaDataBase())) { + const QString designerSource = QLatin1String("designer"); + const DomScripts domScripts = ui_widget->elementScript(); + if (!domScripts.empty()) { + foreach (const DomScript *script, domScripts) { + if (script->hasAttributeSource() && script->attributeSource() == designerSource) { + metaDataBase->metaDataBaseItem(w)->setScript(script->text()); + } + } + } + } + + return w; +} + +QLayout *QDesignerResource::create(DomLayout *ui_layout, QLayout *layout, QWidget *parentWidget) +{ + QLayout *l = QAbstractFormBuilder::create(ui_layout, layout, parentWidget); + + if (QGridLayout *gridLayout = qobject_cast(l)) { + QLayoutSupport::createEmptyCells(gridLayout); + } else { + if (QFormLayout *formLayout = qobject_cast(l)) + QLayoutSupport::createEmptyCells(formLayout); + } + // While the actual values are applied by the form builder, we still need + // to mark them as 'changed'. + LayoutPropertySheet::markChangedStretchProperties(core(), l, ui_layout); + return l; +} + +QLayoutItem *QDesignerResource::create(DomLayoutItem *ui_layoutItem, QLayout *layout, QWidget *parentWidget) +{ + if (ui_layoutItem->kind() == DomLayoutItem::Spacer) { + const DomSpacer *domSpacer = ui_layoutItem->elementSpacer(); + const QHash properties = propertyMap(domSpacer->elementProperty()); + Spacer *spacer = static_cast(core()->widgetFactory()->createWidget(QLatin1String("Spacer"), parentWidget)); + if (domSpacer->hasAttributeName()) + changeObjectName(spacer, domSpacer->attributeName()); + core()->metaDataBase()->add(spacer); + + spacer->setInteractiveMode(false); + applyProperties(spacer, ui_layoutItem->elementSpacer()->elementProperty()); + spacer->setInteractiveMode(true); + + if (m_formWindow) { + m_formWindow->manageWidget(spacer); + if (QDesignerPropertySheetExtension *sheet = qt_extension(core()->extensionManager(), spacer)) + sheet->setChanged(sheet->indexOf(QLatin1String("orientation")), true); + } + + return new QWidgetItem(spacer); + } else if (ui_layoutItem->kind() == DomLayoutItem::Layout && parentWidget) { + DomLayout *ui_layout = ui_layoutItem->elementLayout(); + QLayoutWidget *layoutWidget = new QLayoutWidget(m_formWindow, parentWidget); + core()->metaDataBase()->add(layoutWidget); + if (m_formWindow) + m_formWindow->manageWidget(layoutWidget); + (void) create(ui_layout, 0, layoutWidget); + return new QWidgetItem(layoutWidget); + } + return QAbstractFormBuilder::create(ui_layoutItem, layout, parentWidget); +} + +void QDesignerResource::changeObjectName(QObject *o, QString objName) +{ + m_formWindow->unify(o, objName, true); + o->setObjectName(objName); + +} + +/* If the property is a enum or flag value, retrieve + * the existing enum/flag via property sheet and use it to convert */ + +static bool readDomEnumerationValue(const DomProperty *p, + const QDesignerPropertySheetExtension* sheet, int index, + QVariant &v) +{ + switch (p->kind()) { + case DomProperty::Set: { + const QVariant sheetValue = sheet->property(index); + if (sheetValue.canConvert()) { + const PropertySheetFlagValue f = qvariant_cast(sheetValue); + bool ok = false; + v = f.metaFlags.parseFlags(p->elementSet(), &ok); + if (!ok) + designerWarning(f.metaFlags.messageParseFailed(p->elementSet())); + return true; + } + } + break; + case DomProperty::Enum: { + const QVariant sheetValue = sheet->property(index); + if (sheetValue.canConvert()) { + const PropertySheetEnumValue e = qvariant_cast(sheetValue); + bool ok = false; + v = e.metaEnum.parseEnum(p->elementEnum(), &ok); + if (!ok) + designerWarning(e.metaEnum.messageParseFailed(p->elementEnum())); + return true; + } + } + break; + default: + break; + } + return false; +} + +void QDesignerResource::applyProperties(QObject *o, const QList &properties) +{ + if (properties.empty()) + return; + + QDesignerPropertySheetExtension *sheet = qt_extension(core()->extensionManager(), o); + if (!sheet) + return; + + QFormBuilderExtra *formBuilderExtra = QFormBuilderExtra::instance(this); + QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension(core()->extensionManager(), o); + const bool dynamicPropertiesAllowed = dynamicSheet && dynamicSheet->dynamicPropertiesAllowed(); + + const QString objectNameProperty = QLatin1String("objectName"); + const DomPropertyList::const_iterator cend = properties.constEnd(); + for (DomPropertyList::const_iterator it = properties.constBegin(); it != cend; ++it) { + const DomProperty *p = *it; + const QString propertyName = p->attributeName(); + const int index = sheet->indexOf(propertyName); + QVariant v; + if (!readDomEnumerationValue(p, sheet, index, v)) + v = toVariant(o->metaObject(), *it); + + if (p->kind() == DomProperty::String) { + if (index != -1 && sheet->property(index).userType() == qMetaTypeId()) { + const DomString *key = p->elementString(); + PropertySheetKeySequenceValue keyVal(QKeySequence(key->text())); + if (key->hasAttributeComment()) + keyVal.setDisambiguation(key->attributeComment()); + if (key->hasAttributeExtraComment()) + keyVal.setComment(key->attributeExtraComment()); + if (key->hasAttributeNotr()) { + const QString notr = key->attributeNotr(); + const bool translatable = !(notr == QLatin1String("true") || notr == QLatin1String("yes")); + if (!translatable) + keyVal.setTranslatable(translatable); + } + v = QVariant::fromValue(keyVal); + } else { + const DomString *str = p->elementString(); + PropertySheetStringValue strVal(v.toString()); + if (str->hasAttributeComment()) + strVal.setDisambiguation(str->attributeComment()); + if (str->hasAttributeExtraComment()) + strVal.setComment(str->attributeExtraComment()); + if (str->hasAttributeNotr()) { + const QString notr = str->attributeNotr(); + const bool translatable = !(notr == QLatin1String("true") || notr == QLatin1String("yes")); + if (!translatable) + strVal.setTranslatable(translatable); + } + v = QVariant::fromValue(strVal); + } + } + + formBuilderExtra->applyPropertyInternally(o, propertyName, v); + if (index != -1) { + sheet->setProperty(index, v); + sheet->setChanged(index, true); + } else if (dynamicPropertiesAllowed) { + QVariant defaultValue = QVariant(v.type()); + bool isDefault = (v == defaultValue); + if (v.canConvert()) { + defaultValue = QVariant(QVariant::Icon); + isDefault = (qvariant_cast(v) == PropertySheetIconValue()); + } else if (v.canConvert()) { + defaultValue = QVariant(QVariant::Pixmap); + isDefault = (qvariant_cast(v) == PropertySheetPixmapValue()); + } else if (v.canConvert()) { + defaultValue = QVariant(QVariant::String); + isDefault = (qvariant_cast(v) == PropertySheetStringValue()); + } else if (v.canConvert()) { + defaultValue = QVariant(QVariant::KeySequence); + isDefault = (qvariant_cast(v) == PropertySheetKeySequenceValue()); + } + if (defaultValue.type() != QVariant::UserType) { + const int idx = dynamicSheet->addDynamicProperty(p->attributeName(), defaultValue); + if (idx != -1) { + sheet->setProperty(idx, v); + sheet->setChanged(idx, !isDefault); + } + } + } + + if (propertyName == objectNameProperty) + changeObjectName(o, o->objectName()); + } +} + +QWidget *QDesignerResource::createWidget(const QString &widgetName, QWidget *parentWidget, const QString &_name) +{ + QString name = _name; + QString className = widgetName; + if (m_isMainWidget) + m_isMainWidget = false; + + QWidget *w = core()->widgetFactory()->createWidget(className, parentWidget); + if (!w) + return 0; + + if (name.isEmpty()) { + QDesignerWidgetDataBaseInterface *db = core()->widgetDataBase(); + if (QDesignerWidgetDataBaseItemInterface *item = db->item(db->indexOfObject(w))) + name = qtify(item->name()); + } + + changeObjectName(w, name); + + QDesignerContainerExtension *container = qt_extension(core()->extensionManager(), parentWidget); + if (!qobject_cast(w) && (!parentWidget || !container)) { + m_formWindow->manageWidget(w); + if (parentWidget) { + QList list = qvariant_cast(parentWidget->property("_q_widgetOrder")); + list.append(w); + parentWidget->setProperty("_q_widgetOrder", QVariant::fromValue(list)); + QList zOrder = qvariant_cast(parentWidget->property("_q_zOrder")); + zOrder.append(w); + parentWidget->setProperty("_q_zOrder", QVariant::fromValue(zOrder)); + } + } else { + core()->metaDataBase()->add(w); + } + + w->setWindowFlags(w->windowFlags() & ~Qt::Window); + // Make sure it is non-modal (for example, KDialog calls setModal(true) in the constructor). + w->setWindowModality(Qt::NonModal); + + return w; +} + +QLayout *QDesignerResource::createLayout(const QString &layoutName, QObject *parent, const QString &name) +{ + QWidget *layoutBase = 0; + QLayout *layout = qobject_cast(parent); + + if (parent->isWidgetType()) + layoutBase = static_cast(parent); + else { + Q_ASSERT( layout != 0 ); + layoutBase = layout->parentWidget(); + } + + LayoutInfo::Type layoutType = LayoutInfo::layoutType(layoutName); + if (layoutType == LayoutInfo::NoLayout) { + designerWarning(QCoreApplication::translate("QDesignerResource", "The layout type '%1' is not supported, defaulting to grid.").arg(layoutName)); + layoutType = LayoutInfo::Grid; + } + QLayout *lay = core()->widgetFactory()->createLayout(layoutBase, layout, layoutType); + if (lay != 0) + changeObjectName(lay, name); + + return lay; +} + +// save +DomWidget *QDesignerResource::createDom(QWidget *widget, DomWidget *ui_parentWidget, bool recursive) +{ + QDesignerMetaDataBaseItemInterface *item = core()->metaDataBase()->item(widget); + if (!item) + return 0; + + if (qobject_cast(widget) && m_copyWidget == false) { + ++m_topLevelSpacerCount; + return 0; + } + + const QDesignerWidgetDataBaseInterface *wdb = core()->widgetDataBase(); + QDesignerWidgetDataBaseItemInterface *widgetInfo = 0; + const int widgetInfoIndex = wdb->indexOfObject(widget, false); + if (widgetInfoIndex != -1) { + widgetInfo = wdb->item(widgetInfoIndex); + // Recursively add all dependent custom widgets + QDesignerWidgetDataBaseItemInterface *customInfo = widgetInfo; + while (customInfo && customInfo->isCustom()) { + m_usedCustomWidgets.insert(customInfo, true); + const QString extends = customInfo->extends(); + if (extends == customInfo->name()) { + break; // There are faulty files around that have name==extends + } else { + const int extendsIndex = wdb->indexOfClassName(customInfo->extends()); + customInfo = extendsIndex != -1 ? wdb->item(extendsIndex) : static_cast(0); + } + } + } + + DomWidget *w = 0; + + if (QTabWidget *tabWidget = qobject_cast(widget)) + w = saveWidget(tabWidget, ui_parentWidget); + else if (QStackedWidget *stackedWidget = qobject_cast(widget)) + w = saveWidget(stackedWidget, ui_parentWidget); + else if (QToolBox *toolBox = qobject_cast(widget)) + w = saveWidget(toolBox, ui_parentWidget); + else if (QToolBar *toolBar = qobject_cast(widget)) + w = saveWidget(toolBar, ui_parentWidget); + else if (QDesignerDockWidget *dockWidget = qobject_cast(widget)) + w = saveWidget(dockWidget, ui_parentWidget); + else if (QDesignerContainerExtension *container = qt_extension(core()->extensionManager(), widget)) + w = saveWidget(widget, container, ui_parentWidget); + else if (QWizardPage *wizardPage = qobject_cast(widget)) + w = saveWidget(wizardPage, ui_parentWidget); + else + w = QAbstractFormBuilder::createDom(widget, ui_parentWidget, recursive); + + Q_ASSERT( w != 0 ); + + if (!qobject_cast(widget) && w->attributeClass() == QLatin1String("QWidget")) { + w->setAttributeNative(true); + } + + const QString className = w->attributeClass(); + if (m_internal_to_qt.contains(className)) + w->setAttributeClass(m_internal_to_qt.value(className)); + + w->setAttributeName(widget->objectName()); + + if (isPromoted( core(), widget)) { // is promoted? + Q_ASSERT(widgetInfo != 0); + + w->setAttributeName(widget->objectName()); + w->setAttributeClass(widgetInfo->name()); + + QList prop_list = w->elementProperty(); + foreach (DomProperty *prop, prop_list) { + if (prop->attributeName() == QLatin1String("geometry")) { + if (DomRect *rect = prop->elementRect()) { + rect->setElementX(widget->x()); + rect->setElementY(widget->y()); + } + break; + } + } + } else if (widgetInfo != 0 && m_usedCustomWidgets.contains(widgetInfo)) { + if (widgetInfo->name() != w->attributeClass()) + w->setAttributeClass(widgetInfo->name()); + } + addExtensionDataToDOM(this, core(), w, widget); + + addUserDefinedScripts(widget, w); + return w; +} + +DomLayout *QDesignerResource::createDom(QLayout *layout, DomLayout *ui_parentLayout, DomWidget *ui_parentWidget) +{ + QDesignerMetaDataBaseItemInterface *item = core()->metaDataBase()->item(layout); + + if (item == 0) { + layout = layout->findChild(); + // refresh the meta database item + item = core()->metaDataBase()->item(layout); + } + + if (item == 0) { + // nothing to do. + return 0; + } + + if (qobject_cast(layout->parentWidget()) != 0) { + // nothing to do. + return 0; + } + + m_chain.push(layout); + + DomLayout *l = QAbstractFormBuilder::createDom(layout, ui_parentLayout, ui_parentWidget); + Q_ASSERT(l != 0); + LayoutPropertySheet::stretchAttributesToDom(core(), layout, l); + + m_chain.pop(); + + return l; +} + +DomLayoutItem *QDesignerResource::createDom(QLayoutItem *item, DomLayout *ui_layout, DomWidget *ui_parentWidget) +{ + DomLayoutItem *ui_item = 0; + + if (Spacer *s = qobject_cast(item->widget())) { + if (!core()->metaDataBase()->item(s)) + return 0; + + DomSpacer *spacer = new DomSpacer(); + const QString objectName = s->objectName(); + if (!objectName.isEmpty()) + spacer->setAttributeName(objectName); + const QList properties = computeProperties(item->widget()); + // ### filter the properties + spacer->setElementProperty(properties); + + ui_item = new DomLayoutItem(); + ui_item->setElementSpacer(spacer); + m_laidout.insert(item->widget(), true); + } else if (QLayoutWidget *layoutWidget = qobject_cast(item->widget())) { + // Do not save a QLayoutWidget if it is within a layout (else it is saved as "QWidget" + Q_ASSERT(layoutWidget->layout()); + DomLayout *l = createDom(layoutWidget->layout(), ui_layout, ui_parentWidget); + ui_item = new DomLayoutItem(); + ui_item->setElementLayout(l); + m_laidout.insert(item->widget(), true); + } else if (!item->spacerItem()) { // we use spacer as fake item in the Designer + ui_item = QAbstractFormBuilder::createDom(item, ui_layout, ui_parentWidget); + } else { + return 0; + } + return ui_item; +} + +void QDesignerResource::createCustomWidgets(DomCustomWidgets *dom_custom_widgets) +{ + QSimpleResource::handleDomCustomWidgets(core(), dom_custom_widgets); +} + +DomTabStops *QDesignerResource::saveTabStops() +{ + QDesignerMetaDataBaseItemInterface *item = core()->metaDataBase()->item(m_formWindow); + Q_ASSERT(item); + + QStringList tabStops; + foreach (QWidget *widget, item->tabOrder()) { + if (m_formWindow->mainContainer()->isAncestorOf(widget)) + tabStops.append(widget->objectName()); + } + + if (tabStops.count()) { + DomTabStops *dom = new DomTabStops; + dom->setElementTabStop(tabStops); + return dom; + } + + return 0; +} + +void QDesignerResource::applyTabStops(QWidget *widget, DomTabStops *tabStops) +{ + if (!tabStops) + return; + + QList tabOrder; + foreach (const QString &widgetName, tabStops->elementTabStop()) { + if (QWidget *w = widget->findChild(widgetName)) { + tabOrder.append(w); + } + } + + QDesignerMetaDataBaseItemInterface *item = core()->metaDataBase()->item(m_formWindow); + Q_ASSERT(item); + item->setTabOrder(tabOrder); +} + +/* Unmanaged container pages occur when someone adds a page in a custom widget + * constructor. They don't have a meta DB entry which causes createDom + * to return 0. */ +inline QString msgUnmanagedPage(QDesignerFormEditorInterface *core, + QWidget *container, int index, QWidget *page) +{ + return QCoreApplication::translate("QDesignerResource", +"The container extension of the widget '%1' (%2) returned a widget not managed by Designer '%3' (%4) when queried for page #%5.\n" +"Container pages should only be added by specifying them in XML returned by the domXml() method of the custom widget."). + arg(container->objectName(), WidgetFactory::classNameOf(core, container), + page->objectName(), WidgetFactory::classNameOf(core, page)). + arg(index); +} + +DomWidget *QDesignerResource::saveWidget(QWidget *widget, QDesignerContainerExtension *container, DomWidget *ui_parentWidget) +{ + DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false); + QList ui_widget_list; + + for (int i=0; icount(); ++i) { + QWidget *page = container->widget(i); + Q_ASSERT(page); + + if (DomWidget *ui_page = createDom(page, ui_widget)) { + ui_widget_list.append(ui_page); + } else { + if (QSimpleResource::warningsEnabled()) + designerWarning(msgUnmanagedPage(core(), widget, i, page)); + } + } + + ui_widget->setElementWidget(ui_widget_list); + + return ui_widget; +} + +DomWidget *QDesignerResource::saveWidget(QStackedWidget *widget, DomWidget *ui_parentWidget) +{ + DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false); + QList ui_widget_list; + if (QDesignerContainerExtension *container = qt_extension(core()->extensionManager(), widget)) { + for (int i=0; icount(); ++i) { + QWidget *page = container->widget(i); + Q_ASSERT(page); + if (DomWidget *ui_page = createDom(page, ui_widget)) { + ui_widget_list.append(ui_page); + } else { + if (QSimpleResource::warningsEnabled()) + designerWarning(msgUnmanagedPage(core(), widget, i, page)); + } + } + } + + ui_widget->setElementWidget(ui_widget_list); + + return ui_widget; +} + +DomWidget *QDesignerResource::saveWidget(QToolBar *toolBar, DomWidget *ui_parentWidget) +{ + DomWidget *ui_widget = QAbstractFormBuilder::createDom(toolBar, ui_parentWidget, false); + if (const QMainWindow *mainWindow = qobject_cast(toolBar->parentWidget())) { + const bool toolBarBreak = mainWindow->toolBarBreak(toolBar); + const Qt::ToolBarArea area = mainWindow->toolBarArea(toolBar); + + QList attributes = ui_widget->elementAttribute(); + + DomProperty *attr = new DomProperty(); + attr->setAttributeName(QLatin1String("toolBarArea")); + attr->setElementEnum(QLatin1String(toolBarAreaMetaEnum().valueToKey(area))); + attributes << attr; + + attr = new DomProperty(); + attr->setAttributeName(QLatin1String("toolBarBreak")); + attr->setElementBool(toolBarBreak ? QLatin1String("true") : QLatin1String("false")); + attributes << attr; + ui_widget->setElementAttribute(attributes); + } + + return ui_widget; +} + +DomWidget *QDesignerResource::saveWidget(QDesignerDockWidget *dockWidget, DomWidget *ui_parentWidget) +{ + DomWidget *ui_widget = QAbstractFormBuilder::createDom(dockWidget, ui_parentWidget, true); + if (QMainWindow *mainWindow = qobject_cast(dockWidget->parentWidget())) { + const Qt::DockWidgetArea area = mainWindow->dockWidgetArea(dockWidget); + DomProperty *attr = new DomProperty(); + attr->setAttributeName(QLatin1String("dockWidgetArea")); + attr->setElementNumber(int(area)); + ui_widget->setElementAttribute(ui_widget->elementAttribute() << attr); + } + + return ui_widget; +} + +static void saveStringProperty(DomProperty *property, const PropertySheetStringValue &value) +{ + DomString *str = new DomString(); + str->setText(value.value()); + + const QString property_comment = value.disambiguation(); + if (!property_comment.isEmpty()) + str->setAttributeComment(property_comment); + const QString property_extraComment = value.comment(); + if (!property_extraComment.isEmpty()) + str->setAttributeExtraComment(property_extraComment); + const bool property_translatable = value.translatable(); + if (!property_translatable) + str->setAttributeNotr(QLatin1String("true")); + + property->setElementString(str); +} + +static void saveKeySequenceProperty(DomProperty *property, const PropertySheetKeySequenceValue &value) +{ + DomString *str = new DomString(); + str->setText(value.value().toString()); + + const QString property_comment = value.disambiguation(); + if (!property_comment.isEmpty()) + str->setAttributeComment(property_comment); + const QString property_extraComment = value.comment(); + if (!property_extraComment.isEmpty()) + str->setAttributeExtraComment(property_extraComment); + const bool property_translatable = value.translatable(); + if (!property_translatable) + str->setAttributeNotr(QLatin1String("true")); + + property->setElementString(str); +} + +DomWidget *QDesignerResource::saveWidget(QTabWidget *widget, DomWidget *ui_parentWidget) +{ + DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false); + QList ui_widget_list; + + if (QDesignerContainerExtension *container = qt_extension(core()->extensionManager(), widget)) { + const int current = widget->currentIndex(); + for (int i=0; icount(); ++i) { + QWidget *page = container->widget(i); + Q_ASSERT(page); + + DomWidget *ui_page = createDom(page, ui_widget); + if (!ui_page) { + if (QSimpleResource::warningsEnabled()) + designerWarning(msgUnmanagedPage(core(), widget, i, page)); + continue; + } + QList ui_attribute_list; + + const QFormBuilderStrings &strings = QFormBuilderStrings::instance(); + // attribute `icon' + widget->setCurrentIndex(i); + QDesignerPropertySheetExtension *sheet = qt_extension(core()->extensionManager(), widget); + PropertySheetIconValue icon = qvariant_cast(sheet->property(sheet->indexOf(QLatin1String("currentTabIcon")))); + DomProperty *p = resourceBuilder()->saveResource(workingDirectory(), QVariant::fromValue(icon)); + if (p) { + p->setAttributeName(strings.iconAttribute); + ui_attribute_list.append(p); + } + // attribute `title' + p = textBuilder()->saveText(sheet->property(sheet->indexOf(QLatin1String("currentTabText")))); + if (p) { + p->setAttributeName(strings.titleAttribute); + ui_attribute_list.append(p); + } + + // attribute `toolTip' + QVariant v = sheet->property(sheet->indexOf(QLatin1String("currentTabToolTip"))); + if (!qvariant_cast(v).value().isEmpty()) { + p = textBuilder()->saveText(v); + if (p) { + p->setAttributeName(strings.toolTipAttribute); + ui_attribute_list.append(p); + } + } + + // attribute `whatsThis' + v = sheet->property(sheet->indexOf(QLatin1String("currentTabWhatsThis"))); + if (!qvariant_cast(v).value().isEmpty()) { + p = textBuilder()->saveText(v); + if (p) { + p->setAttributeName(strings.whatsThisAttribute); + ui_attribute_list.append(p); + } + } + + ui_page->setElementAttribute(ui_attribute_list); + + ui_widget_list.append(ui_page); + } + widget->setCurrentIndex(current); + } + + ui_widget->setElementWidget(ui_widget_list); + + return ui_widget; +} + +DomWidget *QDesignerResource::saveWidget(QToolBox *widget, DomWidget *ui_parentWidget) +{ + DomWidget *ui_widget = QAbstractFormBuilder::createDom(widget, ui_parentWidget, false); + QList ui_widget_list; + + if (QDesignerContainerExtension *container = qt_extension(core()->extensionManager(), widget)) { + const int current = widget->currentIndex(); + for (int i=0; icount(); ++i) { + QWidget *page = container->widget(i); + Q_ASSERT(page); + + DomWidget *ui_page = createDom(page, ui_widget); + if (!ui_page) { + if (QSimpleResource::warningsEnabled()) + designerWarning(msgUnmanagedPage(core(), widget, i, page)); + continue; + } + + // attribute `label' + QList ui_attribute_list; + + const QFormBuilderStrings &strings = QFormBuilderStrings::instance(); + + // attribute `icon' + widget->setCurrentIndex(i); + QDesignerPropertySheetExtension *sheet = qt_extension(core()->extensionManager(), widget); + PropertySheetIconValue icon = qvariant_cast(sheet->property(sheet->indexOf(QLatin1String("currentItemIcon")))); + DomProperty *p = resourceBuilder()->saveResource(workingDirectory(), QVariant::fromValue(icon)); + if (p) { + p->setAttributeName(strings.iconAttribute); + ui_attribute_list.append(p); + } + p = textBuilder()->saveText(sheet->property(sheet->indexOf(QLatin1String("currentItemText")))); + if (p) { + p->setAttributeName(strings.labelAttribute); + ui_attribute_list.append(p); + } + + // attribute `toolTip' + QVariant v = sheet->property(sheet->indexOf(QLatin1String("currentItemToolTip"))); + if (!qvariant_cast(v).value().isEmpty()) { + p = textBuilder()->saveText(v); + if (p) { + p->setAttributeName(strings.toolTipAttribute); + ui_attribute_list.append(p); + } + } + + ui_page->setElementAttribute(ui_attribute_list); + + ui_widget_list.append(ui_page); + } + widget->setCurrentIndex(current); + } + + ui_widget->setElementWidget(ui_widget_list); + + return ui_widget; +} + +DomWidget *QDesignerResource::saveWidget(QWizardPage *wizardPage, DomWidget *ui_parentWidget) +{ + DomWidget *ui_widget = QAbstractFormBuilder::createDom(wizardPage, ui_parentWidget, true); + QDesignerPropertySheetExtension *sheet = qt_extension(core()->extensionManager(), wizardPage); + // Save the page id (string) attribute, append to existing attributes + const QString pageIdPropertyName = QLatin1String(QWizardPagePropertySheet::pageIdProperty); + const int pageIdIndex = sheet->indexOf(pageIdPropertyName); + if (pageIdIndex != -1 && sheet->isChanged(pageIdIndex)) { + DomProperty *property = variantToDomProperty(this, wizardPage->metaObject(), pageIdPropertyName, sheet->property(pageIdIndex)); + Q_ASSERT(property); + property->elementString()->setAttributeNotr(QLatin1String("true")); + DomPropertyList attributes = ui_widget->elementAttribute(); + attributes.push_back(property); + ui_widget->setElementAttribute(attributes); + } + return ui_widget; +} + +// Do not save the 'currentTabName' properties of containers +static inline bool checkContainerProperty(const QWidget *w, const QString &propertyName) +{ + if (qobject_cast(w)) + return QToolBoxWidgetPropertySheet::checkProperty(propertyName); + if (qobject_cast(w)) + return QTabWidgetPropertySheet::checkProperty(propertyName); + if (qobject_cast(w)) + return QStackedWidgetPropertySheet::checkProperty(propertyName); + if (qobject_cast(w) || qobject_cast(w)) + return QMdiAreaPropertySheet::checkProperty(propertyName); + return true; +} + +bool QDesignerResource::checkProperty(QObject *obj, const QString &prop) const +{ + const QDesignerMetaObjectInterface *meta = core()->introspection()->metaObject(obj); + + const int pindex = meta->indexOfProperty(prop); + if (pindex != -1 && !(meta->property(pindex)->attributes(obj) & QDesignerMetaPropertyInterface::StoredAttribute)) + return false; + + if (prop == QLatin1String("objectName") || prop == QLatin1String("spacerName")) // ### don't store the property objectName + return false; + + QWidget *check_widget = 0; + if (obj->isWidgetType()) + check_widget = static_cast(obj); + + if (check_widget && prop == QLatin1String("geometry")) { + if (check_widget == m_formWindow->mainContainer()) + return true; // Save although maincontainer is technically laid-out by embedding container + if (m_selected && m_selected == check_widget) + return true; + + return !LayoutInfo::isWidgetLaidout(core(), check_widget); + } + + if (check_widget && !checkContainerProperty(check_widget, prop)) + return false; + + if (QDesignerPropertySheetExtension *sheet = qt_extension(core()->extensionManager(), obj)) { + QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension(core()->extensionManager(), obj); + const int pindex = sheet->indexOf(prop); + if (sheet->isAttribute(pindex)) + return false; + + if (!dynamicSheet || !dynamicSheet->isDynamicProperty(pindex)) + return sheet->isChanged(pindex); + if (!sheet->isVisible(pindex)) + return false; + return true; + } + + return false; +} + +bool QDesignerResource::addItem(DomLayoutItem *ui_item, QLayoutItem *item, QLayout *layout) +{ + if (item->widget() == 0) { + return false; + } + + QGridLayout *grid = qobject_cast(layout); + QBoxLayout *box = qobject_cast(layout); + + if (grid != 0) { + const int rowSpan = ui_item->hasAttributeRowSpan() ? ui_item->attributeRowSpan() : 1; + const int colSpan = ui_item->hasAttributeColSpan() ? ui_item->attributeColSpan() : 1; + grid->addWidget(item->widget(), ui_item->attributeRow(), ui_item->attributeColumn(), rowSpan, colSpan, item->alignment()); + return true; + } else if (box != 0) { + box->addItem(item); + return true; + } + + return QAbstractFormBuilder::addItem(ui_item, item, layout); +} + +bool QDesignerResource::addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) +{ + core()->metaDataBase()->add(widget); // ensure the widget is in the meta database + + if (! QAbstractFormBuilder::addItem(ui_widget, widget, parentWidget) || qobject_cast (parentWidget)) { + if (QDesignerContainerExtension *container = qt_extension(core()->extensionManager(), parentWidget)) + container->addWidget(widget); + } + + if (QTabWidget *tabWidget = qobject_cast(parentWidget)) { + const int tabIndex = tabWidget->count() - 1; + const int current = tabWidget->currentIndex(); + + tabWidget->setCurrentIndex(tabIndex); + + const QFormBuilderStrings &strings = QFormBuilderStrings::instance(); + + const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute()); + QDesignerPropertySheetExtension *sheet = qt_extension(core()->extensionManager(), parentWidget); + if (DomProperty *picon = attributes.value(strings.iconAttribute)) { + QVariant v = resourceBuilder()->loadResource(workingDirectory(), picon); + sheet->setProperty(sheet->indexOf(QLatin1String("currentTabIcon")), v); + } + if (DomProperty *ptext = attributes.value(strings.titleAttribute)) { + QVariant v = textBuilder()->loadText(ptext); + sheet->setProperty(sheet->indexOf(QLatin1String("currentTabText")), v); + } + if (DomProperty *ptext = attributes.value(strings.toolTipAttribute)) { + QVariant v = textBuilder()->loadText(ptext); + sheet->setProperty(sheet->indexOf(QLatin1String("currentTabToolTip")), v); + } + if (DomProperty *ptext = attributes.value(strings.whatsThisAttribute)) { + QVariant v = textBuilder()->loadText(ptext); + sheet->setProperty(sheet->indexOf(QLatin1String("currentTabWhatsThis")), v); + } + tabWidget->setCurrentIndex(current); + } else if (QToolBox *toolBox = qobject_cast(parentWidget)) { + const int itemIndex = toolBox->count() - 1; + const int current = toolBox->currentIndex(); + + toolBox->setCurrentIndex(itemIndex); + + const QFormBuilderStrings &strings = QFormBuilderStrings::instance(); + + const DomPropertyHash attributes = propertyMap(ui_widget->elementAttribute()); + QDesignerPropertySheetExtension *sheet = qt_extension(core()->extensionManager(), parentWidget); + if (DomProperty *picon = attributes.value(strings.iconAttribute)) { + QVariant v = resourceBuilder()->loadResource(workingDirectory(), picon); + sheet->setProperty(sheet->indexOf(QLatin1String("currentItemIcon")), v); + } + if (DomProperty *ptext = attributes.value(strings.labelAttribute)) { + QVariant v = textBuilder()->loadText(ptext); + sheet->setProperty(sheet->indexOf(QLatin1String("currentItemText")), v); + } + if (DomProperty *ptext = attributes.value(strings.toolTipAttribute)) { + QVariant v = textBuilder()->loadText(ptext); + sheet->setProperty(sheet->indexOf(QLatin1String("currentItemToolTip")), v); + } + toolBox->setCurrentIndex(current); + } + + return true; +} + +bool QDesignerResource::copy(QIODevice *dev, const FormBuilderClipboard &selection) +{ + m_copyWidget = true; + + DomUI *ui = copy(selection); + + m_laidout.clear(); + m_copyWidget = false; + + if (!ui) + return false; + + QXmlStreamWriter writer(dev); + writer.setAutoFormatting(true); + writer.setAutoFormattingIndent(1); + writer.writeStartDocument(); + ui->write(writer); + writer.writeEndDocument(); + delete ui; + return true; +} + +DomUI *QDesignerResource::copy(const FormBuilderClipboard &selection) +{ + if (selection.empty()) + return 0; + + m_copyWidget = true; + + DomWidget *ui_widget = new DomWidget(); + ui_widget->setAttributeName(QLatin1String(clipboardObjectName)); + bool hasItems = false; + // Widgets + if (!selection.m_widgets.empty()) { + QList ui_widget_list; + const int size = selection.m_widgets.size(); + for (int i=0; i< size; ++i) { + QWidget *w = selection.m_widgets.at(i); + m_selected = w; + DomWidget *ui_child = createDom(w, ui_widget); + m_selected = 0; + if (ui_child) + ui_widget_list.append(ui_child); + } + if (!ui_widget_list.empty()) { + ui_widget->setElementWidget(ui_widget_list); + hasItems = true; + } + } + // actions + if (!selection.m_actions.empty()) { + QList domActions; + foreach(QAction* action, selection.m_actions) + if (DomAction *domAction = createDom(action)) + domActions += domAction; + if (!domActions.empty()) { + ui_widget-> setElementAction(domActions); + hasItems = true; + } + } + + m_laidout.clear(); + m_copyWidget = false; + + if (!hasItems) { + delete ui_widget; + return 0; + } + // UI + DomUI *ui = new DomUI(); + ui->setAttributeVersion(QLatin1String(currentUiVersion)); + ui->setElementWidget(ui_widget); + ui->setElementResources(saveResources(m_resourceBuilder->usedQrcFiles())); + if (DomCustomWidgets *cws = saveCustomWidgets()) + ui->setElementCustomWidgets(cws); + return ui; +} + +FormBuilderClipboard QDesignerResource::paste(DomUI *ui, QWidget *widgetParent, QObject *actionParent) +{ + QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem. + const int saved = m_isMainWidget; + m_isMainWidget = false; + + FormBuilderClipboard rc; + + // Widgets + const DomWidget *topLevel = ui->elementWidget(); + initialize(ui); + const QList domWidgets = topLevel->elementWidget(); + if (!domWidgets.empty()) { + const QPoint offset = m_formWindow->grid(); + foreach (DomWidget* domWidget, domWidgets) { + if (QWidget *w = create(domWidget, widgetParent)) { + w->move(w->pos() + offset); + // ### change the init properties of w + rc.m_widgets.append(w); + } + } + } + const QList domActions = topLevel->elementAction(); + if (!domActions.empty()) + foreach (DomAction *domAction, domActions) + if (QAction *a = create(domAction, actionParent)) + rc.m_actions .append(a); + + m_isMainWidget = saved; + + if (QDesignerExtraInfoExtension *extra = qt_extension(core()->extensionManager(), core())) + extra->loadUiExtraInfo(ui); + + createResources(ui->elementResources()); + + return rc; +} + +FormBuilderClipboard QDesignerResource::paste(QIODevice *dev, QWidget *widgetParent, QObject *actionParent) +{ + DomUI ui; + QXmlStreamReader reader(dev); + bool uiInitialized = false; + + const QString uiElement = QLatin1String("ui"); + while (!reader.atEnd()) { + if (reader.readNext() == QXmlStreamReader::StartElement) { + if (reader.name().compare(uiElement, Qt::CaseInsensitive)) { + ui.read(reader); + uiInitialized = true; + } else { + //: Parsing clipboard contents + reader.raiseError(QCoreApplication::translate("QDesignerResource", "Unexpected element <%1>").arg(reader.name().toString())); + } + } + } + if (reader.hasError()) { + //: Parsing clipboard contents + designerWarning(QCoreApplication::translate("QDesignerResource", "Error while pasting clipboard contents at line %1, column %2: %3") + .arg(reader.lineNumber()).arg(reader.columnNumber()) + .arg(reader.errorString())); + uiInitialized = false; + } else if (uiInitialized == false) { + //: Parsing clipboard contents + designerWarning(QCoreApplication::translate("QDesignerResource", "Error while pasting clipboard contents: The root element is missing.")); + } + + if (!uiInitialized) + return FormBuilderClipboard(); + + FormBuilderClipboard clipBoard = paste(&ui, widgetParent, actionParent); + + return clipBoard; +} + +void QDesignerResource::layoutInfo(DomLayout *layout, QObject *parent, int *margin, int *spacing) +{ + QAbstractFormBuilder::layoutInfo(layout, parent, margin, spacing); +} + +DomCustomWidgets *QDesignerResource::saveCustomWidgets() +{ + if (m_usedCustomWidgets.isEmpty()) + return 0; + + // We would like the list to be in order of the widget database indexes + // to ensure that base classes come first (nice optics) + QDesignerFormEditorInterface *core = m_formWindow->core(); + QDesignerWidgetDataBaseInterface *db = core->widgetDataBase(); + const bool isInternalWidgetDataBase = qobject_cast(db); + typedef QMap OrderedDBIndexDomCustomWidgetMap; + OrderedDBIndexDomCustomWidgetMap orderedMap; + + const QString global = QLatin1String("global"); + foreach (QDesignerWidgetDataBaseItemInterface *item, m_usedCustomWidgets.keys()) { + const QString name = item->name(); + DomCustomWidget *custom_widget = new DomCustomWidget; + + custom_widget->setElementClass(name); + if (item->isContainer()) + custom_widget->setElementContainer(item->isContainer()); + + if (!item->includeFile().isEmpty()) { + DomHeader *header = new DomHeader; + const IncludeSpecification spec = includeSpecification(item->includeFile()); + header->setText(spec.first); + if (spec.second == IncludeGlobal) { + header->setAttributeLocation(global); + } + custom_widget->setElementHeader(header); + custom_widget->setElementExtends(item->extends()); + } + + if (isInternalWidgetDataBase) { + WidgetDataBaseItem *internalItem = static_cast(item); + const QStringList fakeSlots = internalItem->fakeSlots(); + const QStringList fakeSignals = internalItem->fakeSignals(); + if (!fakeSlots.empty() || !fakeSignals.empty()) { + DomSlots *domSlots = new DomSlots(); + domSlots->setElementSlot(fakeSlots); + domSlots->setElementSignal(fakeSignals); + custom_widget->setElementSlots(domSlots); + } + const QString addPageMethod = internalItem->addPageMethod(); + if (!addPageMethod.isEmpty()) + custom_widget->setElementAddPageMethod(addPageMethod); + } + + // Look up static per-class scripts of designer + if (DomScript *domScript = createScript(customWidgetScript(core, name), ScriptCustomWidgetPlugin)) + custom_widget->setElementScript(domScript); + + orderedMap.insert(db->indexOfClassName(name), custom_widget); + } + + DomCustomWidgets *customWidgets = new DomCustomWidgets; + customWidgets->setElementCustomWidget(orderedMap.values()); + return customWidgets; +} + +bool QDesignerResource::canCompressMargins(QObject *object) const +{ + if (QDesignerPropertySheetExtension *sheet = qt_extension(core()->extensionManager(), object)) { + if (qobject_cast(object)) { + const int l = sheet->property(sheet->indexOf(QLatin1String("leftMargin"))).toInt(); + const int t = sheet->property(sheet->indexOf(QLatin1String("topMargin"))).toInt(); + const int r = sheet->property(sheet->indexOf(QLatin1String("rightMargin"))).toInt(); + const int b = sheet->property(sheet->indexOf(QLatin1String("bottomMargin"))).toInt(); + if (l == t && l == r && l == b) + return true; + } + } + return false; +} + +bool QDesignerResource::canCompressSpacings(QObject *object) const +{ + if (QDesignerPropertySheetExtension *sheet = qt_extension(core()->extensionManager(), object)) { + if (qobject_cast(object)) { + const int h = sheet->property(sheet->indexOf(QLatin1String("horizontalSpacing"))).toInt(); + const int v = sheet->property(sheet->indexOf(QLatin1String("verticalSpacing"))).toInt(); + if (h == v) + return true; + } + } + return false; +} + +QList QDesignerResource::computeProperties(QObject *object) +{ + QList properties; + if (QDesignerPropertySheetExtension *sheet = qt_extension(core()->extensionManager(), object)) { + QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension(core()->extensionManager(), object); + const int count = sheet->count(); + QList marginProperties; + QList spacingProperties; + const bool compressMargins = canCompressMargins(object); + const bool compressSpacings = canCompressSpacings(object); + for (int index = 0; index < count; ++index) { + if (!sheet->isChanged(index) && (!dynamicSheet || !dynamicSheet->isDynamicProperty(index))) + continue; + + const QString propertyName = sheet->propertyName(index); + // Suppress windowModality in legacy forms that have it set on child widgets + if (propertyName == QLatin1String("windowModality") && !sheet->isVisible(index)) + continue; + + const QVariant value = sheet->property(index); + if (DomProperty *p = createProperty(object, propertyName, value)) { + if (compressMargins && (propertyName == QLatin1String("leftMargin") + || propertyName == QLatin1String("rightMargin") + || propertyName == QLatin1String("topMargin") + || propertyName == QLatin1String("bottomMargin"))) { + marginProperties.append(p); + } else if (compressSpacings && (propertyName == QLatin1String("horizontalSpacing") + || propertyName == QLatin1String("verticalSpacing"))) { + spacingProperties.append(p); + } else { + properties.append(p); + } + } + } + if (compressMargins) { + if (marginProperties.count() == 4) { // if we have 3 it means one is reset so we can't compress + DomProperty *marginProperty = marginProperties.at(0); + marginProperty->setAttributeName(QLatin1String("margin")); + properties.append(marginProperty); + delete marginProperties.at(1); + delete marginProperties.at(2); + delete marginProperties.at(3); + } else { + properties += marginProperties; + } + } + if (compressSpacings) { + if (spacingProperties.count() == 2) { + DomProperty *spacingProperty = spacingProperties.at(0); + spacingProperty->setAttributeName(QLatin1String("spacing")); + properties.append(spacingProperty); + delete spacingProperties.at(1); + } else { + properties += spacingProperties; + } + } + } + return properties; +} + +DomProperty *QDesignerResource::applyProperStdSetAttribute(QObject *object, const QString &propertyName, DomProperty *property) +{ + if (!property) + return 0; + + QExtensionManager *mgr = core()->extensionManager(); + if (const QDesignerPropertySheetExtension *sheet = qt_extension(mgr, object)) { + const QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension(mgr, object); + const QDesignerPropertySheet *designerSheet = qobject_cast(core()->extensionManager()->extension(object, Q_TYPEID(QDesignerPropertySheetExtension))); + const int index = sheet->indexOf(propertyName); + if ((dynamicSheet && dynamicSheet->isDynamicProperty(index)) || (designerSheet && designerSheet->isDefaultDynamicProperty(index))) + property->setAttributeStdset(0); + } + return property; +} + +// Optimistic check for a standard setter function +static inline bool hasSetter(QDesignerFormEditorInterface *core, QObject *object, const QString &propertyName) +{ + const QDesignerMetaObjectInterface *meta = core->introspection()->metaObject(object); + const int pindex = meta->indexOfProperty(propertyName); + if (pindex == -1) + return true; + return meta->property(pindex)->hasSetter(); +} + +DomProperty *QDesignerResource::createProperty(QObject *object, const QString &propertyName, const QVariant &value) +{ + if (!checkProperty(object, propertyName)) { + return 0; + } + + if (value.canConvert()) { + const PropertySheetFlagValue f = qvariant_cast(value); + const QString flagString = f.metaFlags.toString(f.value, DesignerMetaFlags::FullyQualified); + if (flagString.isEmpty()) + return 0; + + DomProperty *p = new DomProperty; + // check if we have a standard cpp set function + if (!hasSetter(core(), object, propertyName)) + p->setAttributeStdset(0); + p->setAttributeName(propertyName); + p->setElementSet(flagString); + return applyProperStdSetAttribute(object, propertyName, p); + } else if (value.canConvert()) { + const PropertySheetEnumValue e = qvariant_cast(value); + bool ok; + const QString id = e.metaEnum.toString(e.value, DesignerMetaEnum::FullyQualified, &ok); + if (!ok) + designerWarning(e.metaEnum.messageToStringFailed(e.value)); + if (id.isEmpty()) + return 0; + + DomProperty *p = new DomProperty; + // check if we have a standard cpp set function + if (!hasSetter(core(), object, propertyName)) + p->setAttributeStdset(0); + p->setAttributeName(propertyName); + p->setElementEnum(id); + return applyProperStdSetAttribute(object, propertyName, p); + } else if (value.canConvert()) { + const PropertySheetStringValue strVal = qvariant_cast(value); + DomProperty *p = new DomProperty; + if (!hasSetter(core(), object, propertyName)) + p->setAttributeStdset(0); + + p->setAttributeName(propertyName); + + saveStringProperty(p, strVal); + + return applyProperStdSetAttribute(object, propertyName, p); + } else if (value.canConvert()) { + const PropertySheetKeySequenceValue keyVal = qvariant_cast(value); + DomProperty *p = new DomProperty; + if (!hasSetter(core(), object, propertyName)) + p->setAttributeStdset(0); + + p->setAttributeName(propertyName); + + saveKeySequenceProperty(p, keyVal); + + return applyProperStdSetAttribute(object, propertyName, p); + } + + return applyProperStdSetAttribute(object, propertyName, QAbstractFormBuilder::createProperty(object, propertyName, value)); +} + +QStringList QDesignerResource::mergeWithLoadedPaths(const QStringList &paths) const +{ + QStringList newPaths = paths; +#ifdef OLD_RESOURCE_FORMAT + QStringList loadedPaths = m_resourceBuilder->loadedQrcFiles(); + QStringListIterator it(loadedPaths); + while (it.hasNext()) { + const QString path = it.next(); + if (!newPaths.contains(path)) + newPaths << path; + } +#endif + return newPaths; +} + + +void QDesignerResource::createResources(DomResources *resources) +{ + QStringList paths; + if (resources != 0) { + const QList dom_include = resources->elementInclude(); + foreach (DomResource *res, dom_include) { + QString path = QDir::cleanPath(m_formWindow->absoluteDir().absoluteFilePath(res->attributeLocation())); + while (!QFile::exists(path)) { + QWidget *dialogParent = m_formWindow->core()->topLevel(); + const QString promptTitle = QApplication::translate("qdesigner_internal::QDesignerResource", "Loading qrc file", 0, QApplication::UnicodeUTF8); + const QString prompt = QApplication::translate("qdesigner_internal::QDesignerResource", "The specified qrc file

%1

could not be found. Do you want to update the file location?

", 0, QApplication::UnicodeUTF8).arg(path); + + const QMessageBox::StandardButton answer = core()->dialogGui()->message(dialogParent, QDesignerDialogGuiInterface::ResourceLoadFailureMessage, + QMessageBox::Warning, promptTitle, prompt, QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes); + if (answer == QMessageBox::Yes) { + const QFileInfo fi(path); + const QString fileDialogTitle = QApplication::translate("qdesigner_internal::QDesignerResource", "New location for %1", 0, QApplication::UnicodeUTF8).arg(fi.fileName()); + const QString fileDialogPattern = QApplication::translate("qdesigner_internal::QDesignerResource", "Resource files (*.qrc)", 0, QApplication::UnicodeUTF8); + path = core()->dialogGui()->getOpenFileName(dialogParent, fileDialogTitle, fi.absolutePath(), fileDialogPattern); + if (path.isEmpty()) + break; + m_formWindow->setProperty("_q_resourcepathchanged", QVariant(true)); + } else { + break; + } + } + if (!path.isEmpty()) { + paths << path; + m_formWindow->addResourceFile(path); + } + } + } + +#ifdef OLD_RESOURCE_FORMAT + paths = mergeWithLoadedPaths(paths); +#endif + + QtResourceSet *resourceSet = m_formWindow->resourceSet(); + if (resourceSet) { + QStringList oldPaths = resourceSet->activeQrcPaths(); + QStringList newPaths = oldPaths; + QStringListIterator it(paths); + while (it.hasNext()) { + const QString path = it.next(); + if (!newPaths.contains(path)) + newPaths << path; + } + resourceSet->activateQrcPaths(newPaths); + } else { + resourceSet = m_formWindow->core()->resourceModel()->addResourceSet(paths); + m_formWindow->setResourceSet(resourceSet); + QObject::connect(m_formWindow->core()->resourceModel(), SIGNAL(resourceSetActivated(QtResourceSet*,bool)), + m_formWindow, SLOT(resourceSetActivated(QtResourceSet*,bool))); + } +} + +DomResources *QDesignerResource::saveResources() +{ + QStringList paths; + if (m_formWindow->saveResourcesBehaviour() == FormWindowBase::SaveAll) { + QtResourceSet *resourceSet = m_formWindow->resourceSet(); + QList dom_include; + if (resourceSet) + paths = resourceSet->activeQrcPaths(); + } else if (m_formWindow->saveResourcesBehaviour() == FormWindowBase::SaveOnlyUsedQrcFiles) { + paths = m_resourceBuilder->usedQrcFiles(); + } + + return saveResources(paths); +} + +DomResources *QDesignerResource::saveResources(const QStringList &qrcPaths) +{ + QtResourceSet *resourceSet = m_formWindow->resourceSet(); + QList dom_include; + if (resourceSet) { + const QStringList activePaths = resourceSet->activeQrcPaths(); + foreach (const QString &path, activePaths) { + if (qrcPaths.contains(path)) { + DomResource *dom_res = new DomResource; + QString conv_path = path; + if (m_resourceBuilder->isSaveRelative()) + conv_path = m_formWindow->absoluteDir().relativeFilePath(path); + dom_res->setAttributeLocation(conv_path.replace(QDir::separator(), QLatin1Char('/'))); + dom_include.append(dom_res); + } + } + } + + DomResources *dom_resources = new DomResources; + dom_resources->setElementInclude(dom_include); + + return dom_resources; +} + +DomAction *QDesignerResource::createDom(QAction *action) +{ + if (!core()->metaDataBase()->item(action) || action->menu()) + return 0; + + return QAbstractFormBuilder::createDom(action); +} + +DomActionGroup *QDesignerResource::createDom(QActionGroup *actionGroup) +{ + if (core()->metaDataBase()->item(actionGroup) != 0) { + return QAbstractFormBuilder::createDom(actionGroup); + } + + return 0; +} + +QAction *QDesignerResource::create(DomAction *ui_action, QObject *parent) +{ + if (QAction *action = QAbstractFormBuilder::create(ui_action, parent)) { + core()->metaDataBase()->add(action); + return action; + } + + return 0; +} + +QActionGroup *QDesignerResource::create(DomActionGroup *ui_action_group, QObject *parent) +{ + if (QActionGroup *actionGroup = QAbstractFormBuilder::create(ui_action_group, parent)) { + core()->metaDataBase()->add(actionGroup); + return actionGroup; + } + + return 0; +} + +DomActionRef *QDesignerResource::createActionRefDom(QAction *action) +{ + if (!core()->metaDataBase()->item(action) + || (!action->isSeparator() && !action->menu() && action->objectName().isEmpty())) + return 0; + + return QAbstractFormBuilder::createActionRefDom(action); +} + +void QDesignerResource::addMenuAction(QAction *action) +{ + core()->metaDataBase()->add(action); +} + +QAction *QDesignerResource::createAction(QObject *parent, const QString &name) +{ + if (QAction *action = QAbstractFormBuilder::createAction(parent, name)) { + core()->metaDataBase()->add(action); + return action; + } + + return 0; +} + +QActionGroup *QDesignerResource::createActionGroup(QObject *parent, const QString &name) +{ + if (QActionGroup *actionGroup = QAbstractFormBuilder::createActionGroup(parent, name)) { + core()->metaDataBase()->add(actionGroup); + return actionGroup; + } + + return 0; +} + +/* Apply the attributes to a widget via property sheet where appropriate, + * that is, the sheet handles attributive fake properties */ +void QDesignerResource::applyAttributesToPropertySheet(const DomWidget *ui_widget, QWidget *widget) +{ + const DomPropertyList attributes = ui_widget->elementAttribute(); + if (attributes.empty()) + return; + QDesignerPropertySheetExtension *sheet = qt_extension(m_formWindow->core()->extensionManager(), widget); + const DomPropertyList::const_iterator acend = attributes.constEnd(); + for (DomPropertyList::const_iterator it = attributes.constBegin(); it != acend; ++it) { + const QString name = (*it)->attributeName(); + const int index = sheet->indexOf(name); + if (index == -1) { + const QString msg = QString::fromUtf8("Unable to apply attributive property '%1' to '%2'. It does not exist.").arg(name, widget->objectName()); + designerWarning(msg); + } else { + sheet->setProperty(index, domPropertyToVariant(this, widget->metaObject(), *it)); + sheet->setChanged(index, true); + } + } +} + +void QDesignerResource::loadExtraInfo(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) +{ + QAbstractFormBuilder::loadExtraInfo(ui_widget, widget, parentWidget); + // Apply the page id attribute of a QWizardPage (which is an attributive fake property) + if (qobject_cast(widget)) + applyAttributesToPropertySheet(ui_widget, widget); +} + +// Add user defined scripts (dialog box) belonging to QWidget to DomWidget. +void QDesignerResource::addUserDefinedScripts(QWidget *w, DomWidget *ui_widget) +{ + QDesignerFormEditorInterface *core = m_formWindow->core(); + DomScripts domScripts = ui_widget->elementScript(); + // Look up user-defined scripts of designer + if (const qdesigner_internal::MetaDataBase *metaDataBase = qobject_cast(core->metaDataBase())) { + if (const qdesigner_internal::MetaDataBaseItem *metaItem = metaDataBase->metaDataBaseItem(w)) { + addScript(metaItem->script(), ScriptDesigner, domScripts); + } + } + if (!domScripts.empty()) + ui_widget->setElementScript(domScripts); +} +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/qdesigner_resource.h b/src/designer/src/components/formeditor/qdesigner_resource.h new file mode 100644 index 000000000..b7113d162 --- /dev/null +++ b/src/designer/src/components/formeditor/qdesigner_resource.h @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_RESOURCE_H +#define QDESIGNER_RESOURCE_H + +#include "formeditor_global.h" +#include "qsimpleresource_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class DomCustomWidget; +class DomCustomWidgets; +class DomResource; + +class QDesignerContainerExtension; +class QDesignerFormEditorInterface; +class QDesignerCustomWidgetInterface; +class QDesignerWidgetDataBaseItemInterface; + +class QTabWidget; +class QStackedWidget; +class QToolBox; +class QToolBar; +class QDesignerDockWidget; +class QLayoutWidget; +class QWizardPage; + +namespace qdesigner_internal { + +class FormWindow; + +class QT_FORMEDITOR_EXPORT QDesignerResource : public QEditorFormBuilder +{ +public: + explicit QDesignerResource(FormWindow *fw); + virtual ~QDesignerResource(); + + virtual void save(QIODevice *dev, QWidget *widget); + + virtual bool copy(QIODevice *dev, const FormBuilderClipboard &selection); + virtual DomUI *copy(const FormBuilderClipboard &selection); + + virtual FormBuilderClipboard paste(DomUI *ui, QWidget *widgetParent, QObject *actionParent = 0); + virtual FormBuilderClipboard paste(QIODevice *dev, QWidget *widgetParent, QObject *actionParent = 0); + + bool saveRelative() const; + void setSaveRelative(bool relative); + + virtual QWidget *load(QIODevice *dev, QWidget *parentWidget = 0); + +protected: + using QEditorFormBuilder::create; + using QEditorFormBuilder::createDom; + + virtual void saveDom(DomUI *ui, QWidget *widget); + virtual QWidget *create(DomUI *ui, QWidget *parentWidget); + virtual QWidget *create(DomWidget *ui_widget, QWidget *parentWidget); + virtual QLayout *create(DomLayout *ui_layout, QLayout *layout, QWidget *parentWidget); + virtual QLayoutItem *create(DomLayoutItem *ui_layoutItem, QLayout *layout, QWidget *parentWidget); + virtual void applyProperties(QObject *o, const QList &properties); + virtual QList computeProperties(QObject *obj); + virtual DomProperty *createProperty(QObject *object, const QString &propertyName, const QVariant &value); + + virtual QWidget *createWidget(const QString &widgetName, QWidget *parentWidget, const QString &name); + virtual QLayout *createLayout(const QString &layoutName, QObject *parent, const QString &name); + virtual void createCustomWidgets(DomCustomWidgets *); + virtual void createResources(DomResources*); + virtual void applyTabStops(QWidget *widget, DomTabStops *tabStops); + + virtual bool addItem(DomLayoutItem *ui_item, QLayoutItem *item, QLayout *layout); + virtual bool addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget); + + virtual DomWidget *createDom(QWidget *widget, DomWidget *ui_parentWidget, bool recursive = true); + virtual DomLayout *createDom(QLayout *layout, DomLayout *ui_layout, DomWidget *ui_parentWidget); + virtual DomLayoutItem *createDom(QLayoutItem *item, DomLayout *ui_layout, DomWidget *ui_parentWidget); + + virtual QAction *create(DomAction *ui_action, QObject *parent); + virtual QActionGroup *create(DomActionGroup *ui_action_group, QObject *parent); + virtual void addMenuAction(QAction *action); + + virtual DomAction *createDom(QAction *action); + virtual DomActionGroup *createDom(QActionGroup *actionGroup); + virtual DomActionRef *createActionRefDom(QAction *action); + + virtual QAction *createAction(QObject *parent, const QString &name); + virtual QActionGroup *createActionGroup(QObject *parent, const QString &name); + + virtual bool checkProperty(QObject *obj, const QString &prop) const; + + DomWidget *saveWidget(QTabWidget *widget, DomWidget *ui_parentWidget); + DomWidget *saveWidget(QStackedWidget *widget, DomWidget *ui_parentWidget); + DomWidget *saveWidget(QToolBox *widget, DomWidget *ui_parentWidget); + DomWidget *saveWidget(QWidget *widget, QDesignerContainerExtension *container, DomWidget *ui_parentWidget); + DomWidget *saveWidget(QToolBar *toolBar, DomWidget *ui_parentWidget); + DomWidget *saveWidget(QDesignerDockWidget *dockWidget, DomWidget *ui_parentWidget); + DomWidget *saveWidget(QWizardPage *wizardPage, DomWidget *ui_parentWidget); + + virtual DomCustomWidgets *saveCustomWidgets(); + virtual DomTabStops *saveTabStops(); + virtual DomResources *saveResources(); + + virtual void layoutInfo(DomLayout *layout, QObject *parent, int *margin, int *spacing); + + virtual void loadExtraInfo(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget); + + void changeObjectName(QObject *o, QString name); + DomProperty *applyProperStdSetAttribute(QObject *object, const QString &propertyName, DomProperty *property); + +private: + void addUserDefinedScripts(QWidget *w, DomWidget *ui_widget); + DomResources *saveResources(const QStringList &qrcPaths); + bool canCompressMargins(QObject *object) const; + bool canCompressSpacings(QObject *object) const; + QStringList mergeWithLoadedPaths(const QStringList &paths) const; + void applyAttributesToPropertySheet(const DomWidget *ui_widget, QWidget *widget); + + typedef QList DomCustomWidgetList; + void addCustomWidgetsToWidgetDatabase(DomCustomWidgetList& list); + FormWindow *m_formWindow; + bool m_isMainWidget; + QHash m_internal_to_qt; + QHash m_qt_to_internal; + QStack m_chain; + QHash m_usedCustomWidgets; + int m_topLevelSpacerCount; + bool m_copyWidget; + QWidget *m_selected; + class QDesignerResourceBuilder *m_resourceBuilder; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QDESIGNER_RESOURCE_H diff --git a/src/designer/src/components/formeditor/qdesignerundostack.cpp b/src/designer/src/components/formeditor/qdesignerundostack.cpp new file mode 100644 index 000000000..56bb04f9e --- /dev/null +++ b/src/designer/src/components/formeditor/qdesignerundostack.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesignerundostack.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +QDesignerUndoStack::QDesignerUndoStack(QObject *parent) : + QObject(parent), + m_undoStack(new QUndoStack), + m_fakeDirty(false) +{ + connect(m_undoStack, SIGNAL(indexChanged(int)), this, SIGNAL(changed())); +} + +QDesignerUndoStack::~QDesignerUndoStack() +{ // QUndoStack is managed by the QUndoGroup +} + +void QDesignerUndoStack::push(QUndoCommand * cmd) +{ + m_undoStack->push(cmd); +} + +void QDesignerUndoStack::beginMacro(const QString &text) +{ + m_undoStack->beginMacro(text); +} + +void QDesignerUndoStack::endMacro() +{ + m_undoStack->endMacro(); +} + +int QDesignerUndoStack::index() const +{ + return m_undoStack->index(); +} + +const QUndoStack *QDesignerUndoStack::qundoStack() const +{ + return m_undoStack; +} +QUndoStack *QDesignerUndoStack::qundoStack() +{ + return m_undoStack; +} + +bool QDesignerUndoStack::isDirty() const +{ + return m_fakeDirty || !m_undoStack->isClean(); +} + +void QDesignerUndoStack::setDirty(bool v) +{ + if (isDirty() == v) + return; + if (v) { + m_fakeDirty = true; + emit changed(); + } else { + m_fakeDirty = false; + m_undoStack->setClean(); + } +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/qdesignerundostack.h b/src/designer/src/components/formeditor/qdesignerundostack.h new file mode 100644 index 000000000..cabb4abdb --- /dev/null +++ b/src/designer/src/components/formeditor/qdesignerundostack.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNERUNDOSTACK_H +#define QDESIGNERUNDOSTACK_H + +#include + +QT_BEGIN_NAMESPACE +class QUndoStack; +class QUndoCommand; + +namespace qdesigner_internal { + +/* QDesignerUndoStack: A QUndoStack extended by a way of setting it to + * "dirty" indepently of commands (by modifications without commands + * such as resizing). Accomplished via bool m_fakeDirty flag. The + * lifecycle of the QUndoStack is managed by the QUndoGroup. */ +class QDesignerUndoStack : public QObject +{ + Q_DISABLE_COPY(QDesignerUndoStack) + Q_OBJECT +public: + explicit QDesignerUndoStack(QObject *parent = 0); + virtual ~QDesignerUndoStack(); + + void push(QUndoCommand * cmd); + void beginMacro(const QString &text); + void endMacro(); + int index() const; + + const QUndoStack *qundoStack() const; + QUndoStack *qundoStack(); + + bool isDirty() const; + +signals: + void changed(); + +public slots: + void setDirty(bool); + +private: + QUndoStack *m_undoStack; + bool m_fakeDirty; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QDESIGNERUNDOSTACK_H diff --git a/src/designer/src/components/formeditor/qlayoutwidget_propertysheet.cpp b/src/designer/src/components/formeditor/qlayoutwidget_propertysheet.cpp new file mode 100644 index 000000000..49c49fa8e --- /dev/null +++ b/src/designer/src/components/formeditor/qlayoutwidget_propertysheet.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlayoutwidget_propertysheet.h" +#include "qlayout_widget_p.h" +#include "formwindow.h" +#include "formeditor.h" + +#include + +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +QLayoutWidgetPropertySheet::QLayoutWidgetPropertySheet(QLayoutWidget *object, QObject *parent) + : QDesignerPropertySheet(object, parent) +{ + clearFakeProperties(); +} + +QLayoutWidgetPropertySheet::~QLayoutWidgetPropertySheet() +{ +} + +bool QLayoutWidgetPropertySheet::isVisible(int index) const +{ + static const QString layoutPropertyGroup = QLatin1String("Layout"); + if (propertyGroup(index) == layoutPropertyGroup) + return QDesignerPropertySheet::isVisible(index); + return false; +} + +void QLayoutWidgetPropertySheet::setProperty(int index, const QVariant &value) +{ + QDesignerPropertySheet::setProperty(index, value); +} + +bool QLayoutWidgetPropertySheet::dynamicPropertiesAllowed() const +{ + return false; +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/qlayoutwidget_propertysheet.h b/src/designer/src/components/formeditor/qlayoutwidget_propertysheet.h new file mode 100644 index 000000000..76e3263f6 --- /dev/null +++ b/src/designer/src/components/formeditor/qlayoutwidget_propertysheet.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLAYOUTWIDGET_PROPERTYSHEET_H +#define QLAYOUTWIDGET_PROPERTYSHEET_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QLayoutWidgetPropertySheet: public QDesignerPropertySheet +{ + Q_OBJECT + Q_INTERFACES(QDesignerPropertySheetExtension) +public: + explicit QLayoutWidgetPropertySheet(QLayoutWidget *object, QObject *parent = 0); + virtual ~QLayoutWidgetPropertySheet(); + + virtual void setProperty(int index, const QVariant &value); + virtual bool isVisible(int index) const; + + virtual bool dynamicPropertiesAllowed() const; +}; + +typedef QDesignerPropertySheetFactory QLayoutWidgetPropertySheetFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QLAYOUTWIDGET_PROPERTYSHEET_H diff --git a/src/designer/src/components/formeditor/qmainwindow_container.cpp b/src/designer/src/components/formeditor/qmainwindow_container.cpp new file mode 100644 index 000000000..d2664b418 --- /dev/null +++ b/src/designer/src/components/formeditor/qmainwindow_container.cpp @@ -0,0 +1,199 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmainwindow_container.h" +#include "qdesigner_toolbar_p.h" +#include "formwindow.h" + +#include + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +QMainWindowContainer::QMainWindowContainer(QMainWindow *widget, QObject *parent) + : QObject(parent), + m_mainWindow(widget) +{ +} + +int QMainWindowContainer::count() const +{ + return m_widgets.count(); +} + +QWidget *QMainWindowContainer::widget(int index) const +{ + if (index == -1) + return 0; + + return m_widgets.at(index); +} + +int QMainWindowContainer::currentIndex() const +{ + return m_mainWindow->centralWidget() ? 0 : -1; +} + +void QMainWindowContainer::setCurrentIndex(int index) +{ + Q_UNUSED(index); +} + + +namespace { + // Pair of + typedef QPair ToolBarData; + + ToolBarData toolBarData(QToolBar *me) { + const QMainWindow *mw = qobject_cast(me->parentWidget()); + if (!mw || !mw->layout() || mw->layout()->indexOf(me) == -1) + return ToolBarData(Qt::TopToolBarArea,false); + return ToolBarData(mw->toolBarArea(me), mw->toolBarBreak(me)); + } + +Qt::DockWidgetArea dockWidgetArea(QDockWidget *me) +{ + if (const QMainWindow *mw = qobject_cast(me->parentWidget())) { + // Make sure that me is actually managed by mw, otherwise + // QMainWindow::dockWidgetArea() will be VERY upset + QList candidates; + if (mw->layout()) { + candidates.append(mw->layout()); + candidates += mw->layout()->findChildren(); + } + foreach (QLayout *l, candidates) { + if (l->indexOf(me) != -1) { + return mw->dockWidgetArea(me); + } + } + } + return Qt::LeftDockWidgetArea; +} +} + +void QMainWindowContainer::addWidget(QWidget *widget) +{ + // remove all the occurrences of widget + m_widgets.removeAll(widget); + + // the + if (QToolBar *toolBar = qobject_cast(widget)) { + m_widgets.append(widget); + const ToolBarData data = toolBarData(toolBar); + m_mainWindow->addToolBar(data.first, toolBar); + if (data.second) m_mainWindow->insertToolBarBreak(toolBar); + toolBar->show(); + } + + else if (QMenuBar *menuBar = qobject_cast(widget)) { + if (menuBar != m_mainWindow->menuBar()) + m_mainWindow->setMenuBar(menuBar); + + m_widgets.append(widget); + menuBar->show(); + } + + else if (QStatusBar *statusBar = qobject_cast(widget)) { + if (statusBar != m_mainWindow->statusBar()) + m_mainWindow->setStatusBar(statusBar); + + m_widgets.append(widget); + statusBar->show(); + } + + else if (QDockWidget *dockWidget = qobject_cast(widget)) { + m_widgets.append(widget); + m_mainWindow->addDockWidget(dockWidgetArea(dockWidget), dockWidget); + dockWidget->show(); + + if (FormWindow *fw = FormWindow::findFormWindow(m_mainWindow)) { + fw->manageWidget(widget); + } + } + + else if (widget) { + m_widgets.prepend(widget); + + if (widget != m_mainWindow->centralWidget()) { + // note that qmainwindow will delete the current central widget if you + // call setCentralWidget(), we end up with dangeling pointers in m_widgets list + m_widgets.removeAll(m_mainWindow->centralWidget()); + + widget->setParent(m_mainWindow); + m_mainWindow->setCentralWidget(widget); + } + } +} + +void QMainWindowContainer::insertWidget(int index, QWidget *widget) +{ + Q_UNUSED(index); + + addWidget(widget); +} + +void QMainWindowContainer::remove(int index) +{ + QWidget *widget = m_widgets.at(index); + if (QToolBar *toolBar = qobject_cast(widget)) { + m_mainWindow->removeToolBar(toolBar); + } else if (QMenuBar *menuBar = qobject_cast(widget)) { + menuBar->hide(); + menuBar->setParent(0); + m_mainWindow->setMenuBar(0); + } else if (QStatusBar *statusBar = qobject_cast(widget)) { + statusBar->hide(); + statusBar->setParent(0); + m_mainWindow->setStatusBar(0); + } else if (QDockWidget *dockWidget = qobject_cast(widget)) { + m_mainWindow->removeDockWidget(dockWidget); + } + m_widgets.removeAt(index); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/qmainwindow_container.h b/src/designer/src/components/formeditor/qmainwindow_container.h new file mode 100644 index 000000000..6151c97ff --- /dev/null +++ b/src/designer/src/components/formeditor/qmainwindow_container.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMAINWINDOW_CONTAINER_H +#define QMAINWINDOW_CONTAINER_H + +#include +#include + +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QMainWindowContainer: public QObject, public QDesignerContainerExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerContainerExtension) +public: + explicit QMainWindowContainer(QMainWindow *widget, QObject *parent = 0); + + virtual int count() const; + virtual QWidget *widget(int index) const; + virtual int currentIndex() const; + virtual void setCurrentIndex(int index); + virtual void addWidget(QWidget *widget); + virtual void insertWidget(int index, QWidget *widget); + virtual void remove(int index); + +private: + QMainWindow *m_mainWindow; + QList m_widgets; +}; + +typedef ExtensionFactory QMainWindowContainerFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QMAINWINDOW_CONTAINER_H diff --git a/src/designer/src/components/formeditor/qmdiarea_container.cpp b/src/designer/src/components/formeditor/qmdiarea_container.cpp new file mode 100644 index 000000000..670d1d062 --- /dev/null +++ b/src/designer/src/components/formeditor/qmdiarea_container.cpp @@ -0,0 +1,281 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmdiarea_container.h" + +#include +#include + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +QMdiAreaContainer::QMdiAreaContainer(QMdiArea *widget, QObject *parent) + : QObject(parent), + m_mdiArea(widget) +{ +} + +int QMdiAreaContainer::count() const +{ + return m_mdiArea->subWindowList(QMdiArea::CreationOrder).count(); +} + +QWidget *QMdiAreaContainer::widget(int index) const +{ + if (index < 0) + return 0; + return m_mdiArea->subWindowList(QMdiArea::CreationOrder).at(index)->widget(); +} + +int QMdiAreaContainer::currentIndex() const +{ + if (QMdiSubWindow *sub = m_mdiArea->activeSubWindow()) + return m_mdiArea->subWindowList(QMdiArea::CreationOrder).indexOf(sub); + return -1; +} + +void QMdiAreaContainer::setCurrentIndex(int index) +{ + if (index < 0) { + qDebug() << "** WARNING Attempt to QMdiAreaContainer::setCurrentIndex(-1)"; + return; + } + QMdiSubWindow *frame = m_mdiArea->subWindowList(QMdiArea::CreationOrder).at(index); + m_mdiArea->setActiveSubWindow(frame); +} + +void QMdiAreaContainer::addWidget(QWidget *widget) +{ + QMdiSubWindow *frame = m_mdiArea->addSubWindow(widget, Qt::Window); + frame->show(); + m_mdiArea->cascadeSubWindows(); + positionNewMdiChild(m_mdiArea, frame); +} + +// Semi-smart positioning of new windows: Make child fill the whole MDI window below +// cascaded other windows +void QMdiAreaContainer::positionNewMdiChild(const QWidget *area, QWidget *mdiChild) +{ + enum { MinSize = 20 }; + const QPoint pos = mdiChild->pos(); + const QSize areaSize = area->size(); + switch (QApplication::layoutDirection()) { + case Qt::LayoutDirectionAuto: + case Qt::LeftToRight: { + const QSize fullSize = QSize(areaSize.width() - pos.x(), areaSize.height() - pos.y()); + if (fullSize.width() > MinSize && fullSize.height() > MinSize) + mdiChild->resize(fullSize); + } + break; + case Qt::RightToLeft: { + const QSize fullSize = QSize(pos.x() + mdiChild->width(), areaSize.height() - pos.y()); + if (fullSize.width() > MinSize && fullSize.height() > MinSize) { + mdiChild->move(0, pos.y()); + mdiChild->resize(fullSize); + } + } + break; + } +} + +void QMdiAreaContainer::insertWidget(int, QWidget *widget) +{ + addWidget(widget); +} + +void QMdiAreaContainer::remove(int index) +{ + QList subWins = m_mdiArea->subWindowList(QMdiArea::CreationOrder); + if (index >= 0 && index < subWins.size()) { + QMdiSubWindow *f = subWins.at(index); + m_mdiArea->removeSubWindow(f->widget()); + delete f; + } +} + +// ---------- MdiAreaPropertySheet, creates fake properties: +// 1) window name (object name of child) +// 2) title (windowTitle of child). + +static const char *subWindowTitleC = "activeSubWindowTitle"; +static const char *subWindowNameC = "activeSubWindowName"; + +QMdiAreaPropertySheet::QMdiAreaPropertySheet(QWidget *mdiArea, QObject *parent) : + QDesignerPropertySheet(mdiArea, parent), + m_windowTitleProperty(QLatin1String("windowTitle")) +{ + createFakeProperty(QLatin1String(subWindowNameC), QString()); + createFakeProperty(QLatin1String(subWindowTitleC), QString()); +} + +QMdiAreaPropertySheet::MdiAreaProperty QMdiAreaPropertySheet::mdiAreaProperty(const QString &name) +{ + typedef QHash MdiAreaPropertyHash; + static MdiAreaPropertyHash mdiAreaPropertyHash; + if (mdiAreaPropertyHash.empty()) { + mdiAreaPropertyHash.insert(QLatin1String(subWindowNameC), MdiAreaSubWindowName); + mdiAreaPropertyHash.insert(QLatin1String(subWindowTitleC), MdiAreaSubWindowTitle); + } + return mdiAreaPropertyHash.value(name,MdiAreaNone); +} + +void QMdiAreaPropertySheet::setProperty(int index, const QVariant &value) +{ + switch (mdiAreaProperty(propertyName(index))) { + case MdiAreaSubWindowName: + if (QWidget *w = currentWindow()) + w->setObjectName(value.toString()); + break; + case MdiAreaSubWindowTitle: // Forward to window title of subwindow + if (QDesignerPropertySheetExtension *cws = currentWindowSheet()) { + const int index = cws->indexOf(m_windowTitleProperty); + cws->setProperty(index, value); + cws->setChanged(index, true); + } + break; + default: + QDesignerPropertySheet::setProperty(index, value); + break; + } +} + +bool QMdiAreaPropertySheet::reset(int index) +{ + bool rc = true; + switch (mdiAreaProperty(propertyName(index))) { + case MdiAreaSubWindowName: + setProperty(index, QVariant(QString())); + setChanged(index, false); + break; + case MdiAreaSubWindowTitle: // Forward to window title of subwindow + if (QDesignerPropertySheetExtension *cws = currentWindowSheet()) { + const int index = cws->indexOf(m_windowTitleProperty); + rc = cws->reset(index); + } + break; + default: + rc = QDesignerPropertySheet::reset(index); + break; + } + return rc; +} + +QVariant QMdiAreaPropertySheet::property(int index) const +{ + switch (mdiAreaProperty(propertyName(index))) { + case MdiAreaSubWindowName: + if (QWidget *w = currentWindow()) + return w->objectName(); + return QVariant(QString()); + case MdiAreaSubWindowTitle: + if (QWidget *w = currentWindow()) + return w->windowTitle(); + return QVariant(QString()); + case MdiAreaNone: + break; + } + return QDesignerPropertySheet::property(index); +} + +bool QMdiAreaPropertySheet::isEnabled(int index) const +{ + switch (mdiAreaProperty(propertyName(index))) { + case MdiAreaSubWindowName: + case MdiAreaSubWindowTitle: + return currentWindow() != 0; + case MdiAreaNone: + break; + } + return QDesignerPropertySheet::isEnabled(index); +} + +bool QMdiAreaPropertySheet::isChanged(int index) const +{ + bool rc = false; + switch (mdiAreaProperty(propertyName(index))) { + case MdiAreaSubWindowName: + rc = currentWindow() != 0; + break; + case MdiAreaSubWindowTitle: + if (QDesignerPropertySheetExtension *cws = currentWindowSheet()) { + const int index = cws->indexOf(m_windowTitleProperty); + rc = cws->isChanged(index); + } + break; + default: + rc = QDesignerPropertySheet::isChanged(index); + break; + } + return rc; +} + +QWidget *QMdiAreaPropertySheet::currentWindow() const +{ + if (const QDesignerContainerExtension *c = qt_extension(core()->extensionManager(), object())) { + const int ci = c->currentIndex(); + if (ci < 0) + return 0; + return c->widget(ci); + } + return 0; +} + +QDesignerPropertySheetExtension *QMdiAreaPropertySheet::currentWindowSheet() const +{ + QWidget *cw = currentWindow(); + if (cw == 0) + return 0; + return qt_extension(core()->extensionManager(), cw); +} + +bool QMdiAreaPropertySheet::checkProperty(const QString &propertyName) +{ + return mdiAreaProperty(propertyName) == MdiAreaNone; +} +} +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/qmdiarea_container.h b/src/designer/src/components/formeditor/qmdiarea_container.h new file mode 100644 index 000000000..453e67109 --- /dev/null +++ b/src/designer/src/components/formeditor/qmdiarea_container.h @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMDIAREA_CONTAINER_H +#define QMDIAREA_CONTAINER_H + +#include + + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// Container for QMdiArea +class QMdiAreaContainer: public QObject, public QDesignerContainerExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerContainerExtension) +public: + explicit QMdiAreaContainer(QMdiArea *widget, QObject *parent = 0); + + virtual int count() const; + virtual QWidget *widget(int index) const; + virtual int currentIndex() const; + virtual void setCurrentIndex(int index); + virtual void addWidget(QWidget *widget); + virtual void insertWidget(int index, QWidget *widget); + virtual void remove(int index); + + // Semismart positioning of a new MDI child after cascading + static void positionNewMdiChild(const QWidget *area, QWidget *mdiChild); + +private: + QMdiArea *m_mdiArea; +}; + +// PropertySheet for QMdiArea: Fakes window title and name. +// Also works for a QWorkspace as it relies on the container extension. + +class QMdiAreaPropertySheet: public QDesignerPropertySheet +{ + Q_OBJECT + Q_INTERFACES(QDesignerPropertySheetExtension) +public: + explicit QMdiAreaPropertySheet(QWidget *mdiArea, QObject *parent = 0); + + virtual void setProperty(int index, const QVariant &value); + virtual bool reset(int index); + virtual bool isEnabled(int index) const; + virtual bool isChanged(int index) const; + virtual QVariant property(int index) const; + + // Check whether the property is to be saved. Returns false for the page + // properties (as the property sheet has no concept of 'stored') + static bool checkProperty(const QString &propertyName); + +private: + const QString m_windowTitleProperty; + QWidget *currentWindow() const; + QDesignerPropertySheetExtension *currentWindowSheet() const; + + enum MdiAreaProperty { MdiAreaSubWindowName, MdiAreaSubWindowTitle, MdiAreaNone }; + static MdiAreaProperty mdiAreaProperty(const QString &name); +}; + +// Factories + +typedef ExtensionFactory QMdiAreaContainerFactory; +typedef QDesignerPropertySheetFactory QMdiAreaPropertySheetFactory; +typedef QDesignerPropertySheetFactory QWorkspacePropertySheetFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QMDIAREA_CONTAINER_H diff --git a/src/designer/src/components/formeditor/qtbrushmanager.cpp b/src/designer/src/components/formeditor/qtbrushmanager.cpp new file mode 100644 index 000000000..8cba8fa56 --- /dev/null +++ b/src/designer/src/components/formeditor/qtbrushmanager.cpp @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtbrushmanager.h" +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QtBrushManagerPrivate +{ + QtBrushManager *q_ptr; + Q_DECLARE_PUBLIC(QtBrushManager) +public: + QMap theBrushMap; + QString theCurrentBrush; +}; + +QtBrushManager::QtBrushManager(QObject *parent) + : QDesignerBrushManagerInterface(parent), d_ptr(new QtBrushManagerPrivate) +{ + d_ptr->q_ptr = this; +} + +QtBrushManager::~QtBrushManager() +{ +} + +QBrush QtBrushManager::brush(const QString &name) const +{ + if (d_ptr->theBrushMap.contains(name)) + return d_ptr->theBrushMap[name]; + return QBrush(); +} + +QMap QtBrushManager::brushes() const +{ + return d_ptr->theBrushMap; +} + +QString QtBrushManager::currentBrush() const +{ + return d_ptr->theCurrentBrush; +} + +QString QtBrushManager::addBrush(const QString &name, const QBrush &brush) +{ + if (name.isNull()) + return QString(); + + QString newName = name; + QString nameBase = newName; + int i = 0; + while (d_ptr->theBrushMap.contains(newName)) { + newName = nameBase + QString::number(++i); + } + d_ptr->theBrushMap[newName] = brush; + emit brushAdded(newName, brush); + + return newName; +} + +void QtBrushManager::removeBrush(const QString &name) +{ + if (!d_ptr->theBrushMap.contains(name)) + return; + if (currentBrush() == name) + setCurrentBrush(QString()); + emit brushRemoved(name); + d_ptr->theBrushMap.remove(name); +} + +void QtBrushManager::setCurrentBrush(const QString &name) +{ + QBrush newBrush; + if (!name.isNull()) { + if (d_ptr->theBrushMap.contains(name)) + newBrush = d_ptr->theBrushMap[name]; + else + return; + } + d_ptr->theCurrentBrush = name; + emit currentBrushChanged(name, newBrush); +} + +QPixmap QtBrushManager::brushPixmap(const QBrush &brush) const +{ + int w = 64; + int h = 64; + + QImage img(w, h, QImage::Format_ARGB32_Premultiplied); + QPainter p(&img); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.fillRect(QRect(0, 0, w, h), brush); + return QPixmap::fromImage(img); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/qtbrushmanager.h b/src/designer/src/components/formeditor/qtbrushmanager.h new file mode 100644 index 000000000..d490523c8 --- /dev/null +++ b/src/designer/src/components/formeditor/qtbrushmanager.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTBRUSHMANAGER_H +#define QTBRUSHMANAGER_H + +#include +#include "formeditor_global.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QtBrushManagerPrivate; + +class QT_FORMEDITOR_EXPORT QtBrushManager : public QDesignerBrushManagerInterface +{ + Q_OBJECT +public: + QtBrushManager(QObject *parent = 0); + ~QtBrushManager(); + + QBrush brush(const QString &name) const; + QMap brushes() const; + QString currentBrush() const; + + QString addBrush(const QString &name, const QBrush &brush); + void removeBrush(const QString &name); + void setCurrentBrush(const QString &name); + + QPixmap brushPixmap(const QBrush &brush) const; + +private: + QScopedPointer d_ptr; + Q_DECLARE_PRIVATE(QtBrushManager) + Q_DISABLE_COPY(QtBrushManager) +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif diff --git a/src/designer/src/components/formeditor/qwizard_container.cpp b/src/designer/src/components/formeditor/qwizard_container.cpp new file mode 100644 index 000000000..d88bcf2f6 --- /dev/null +++ b/src/designer/src/components/formeditor/qwizard_container.cpp @@ -0,0 +1,226 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwizard_container.h" + +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +typedef QList IdList; +typedef QList WizardPageList; + +namespace qdesigner_internal { + +QWizardContainer::QWizardContainer(QWizard *widget, QObject *parent) : + QObject(parent), + m_wizard(widget) +{ +} + +int QWizardContainer::count() const +{ + return m_wizard->pageIds().size(); +} + +QWidget *QWizardContainer::widget(int index) const +{ + QWidget *rc = 0; + if (index >= 0) { + const IdList idList = m_wizard->pageIds(); + if (index < idList.size()) + rc = m_wizard->page(idList.at(index)); + } + return rc; +} + +int QWizardContainer::currentIndex() const +{ + const IdList idList = m_wizard->pageIds(); + const int currentId = m_wizard->currentId(); + const int rc = idList.empty() ? -1 : idList.indexOf(currentId); + return rc; +} + +void QWizardContainer::setCurrentIndex(int index) +{ + if (index < 0 || m_wizard->pageIds().empty()) + return; + + int currentIdx = currentIndex(); + + if (currentIdx == -1) { + m_wizard->restart(); + currentIdx = currentIndex(); + } + + if (currentIdx == index) + return; + + const int d = qAbs(index - currentIdx); + if (index > currentIdx) { + for (int i = 0; i < d; i++) + m_wizard->next(); + } else { + for (int i = 0; i < d; i++) + m_wizard->back(); + } +} + +static const char *msgWrongType = "** WARNING Attempt to add oject that is not of class WizardPage to a QWizard"; + +void QWizardContainer::addWidget(QWidget *widget) +{ + QWizardPage *page = qobject_cast(widget); + if (!page) { + qWarning("%s", msgWrongType); + return; + } + m_wizard->addPage(page); + // Might be -1 after adding the first page + setCurrentIndex(m_wizard->pageIds().size() - 1); +} + +void QWizardContainer::insertWidget(int index, QWidget *widget) +{ + enum { delta = 5 }; + + QWizardPage *newPage = qobject_cast(widget); + if (!newPage) { + qWarning("%s", msgWrongType); + return; + } + + const IdList idList = m_wizard->pageIds(); + const int pageCount = idList.size(); + if (index >= pageCount) { + addWidget(widget); + return; + } + + // Insert before, reshuffle ids if required + const int idBefore = idList.at(index); + const int newId = idBefore - 1; + const bool needsShuffle = + (index == 0 && newId < 0) // At start: QWizard refuses to insert id -1 + || (index > 0 && idList.at(index - 1) == newId); // In-between + if (needsShuffle) { + // Create a gap by shuffling pages + WizardPageList pageList; + pageList.push_back(newPage); + for (int i = index; i < pageCount; i++) { + pageList.push_back(m_wizard->page(idList.at(i))); + m_wizard->removePage(idList.at(i)); + } + int newId = idBefore + delta; + const WizardPageList::const_iterator wcend = pageList.constEnd(); + for (WizardPageList::const_iterator it = pageList.constBegin(); it != wcend; ++it) { + m_wizard->setPage(newId, *it); + newId += delta; + } + } else { + // Gap found, just insert + m_wizard->setPage(newId, newPage); + } + // Might be at -1 after adding the first page + setCurrentIndex(index); +} + +void QWizardContainer::remove(int index) +{ + if (index < 0) + return; + + const IdList idList = m_wizard->pageIds(); + if (index >= idList.size()) + return; + + m_wizard->removePage(idList.at(index)); + // goto next page, preferably + const int newSize = idList.size() - 1; + if (index < newSize) { + setCurrentIndex(index); + } else { + if (newSize > 0) + setCurrentIndex(newSize - 1); + } +} + +// ---------------- QWizardPagePropertySheet +const char *QWizardPagePropertySheet::pageIdProperty = "pageId"; + +QWizardPagePropertySheet::QWizardPagePropertySheet(QWizardPage *object, QObject *parent) : + QDesignerPropertySheet(object, parent), + m_pageIdIndex(createFakeProperty(QLatin1String(pageIdProperty), QString())) +{ + setAttribute(m_pageIdIndex, true); +} + +bool QWizardPagePropertySheet::reset(int index) +{ + if (index == m_pageIdIndex) { + setProperty(index, QString()); + return true; + } + return QDesignerPropertySheet::reset(index); +} + +// ---------------- QWizardPropertySheet +QWizardPropertySheet::QWizardPropertySheet(QWizard *object, QObject *parent) : + QDesignerPropertySheet(object, parent), + m_startId(QLatin1String("startId")) +{ +} + +bool QWizardPropertySheet::isVisible(int index) const +{ + if (propertyName(index) == m_startId) + return false; + return QDesignerPropertySheet::isVisible(index); +} +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/qwizard_container.h b/src/designer/src/components/formeditor/qwizard_container.h new file mode 100644 index 000000000..43a1e5f62 --- /dev/null +++ b/src/designer/src/components/formeditor/qwizard_container.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWIZARD_CONTAINER_H +#define QWIZARD_CONTAINER_H + +#include + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QWizardPage; + +namespace qdesigner_internal { + +// Container for QWizard. Care must be taken to position +// the QWizard at some valid page after removal/insertion +// as it is not used to having its pages ripped out. +class QWizardContainer: public QObject, public QDesignerContainerExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerContainerExtension) +public: + explicit QWizardContainer(QWizard *widget, QObject *parent = 0); + + virtual int count() const; + virtual QWidget *widget(int index) const; + virtual int currentIndex() const; + virtual void setCurrentIndex(int index); + virtual void addWidget(QWidget *widget); + virtual void insertWidget(int index, QWidget *widget); + virtual void remove(int index); + +private: + QWizard *m_wizard; +}; + +// QWizardPagePropertySheet: Introduces a attribute string fake property +// "pageId" that allows for specifying enumeration values (uic only). +// This breaks the pattern of having a "currentSth" property for the +// container, but was deemed to make sense here since the Page has +// its own "title" properties. +class QWizardPagePropertySheet: public QDesignerPropertySheet +{ + Q_OBJECT +public: + explicit QWizardPagePropertySheet(QWizardPage *object, QObject *parent = 0); + + virtual bool reset(int index); + + static const char *pageIdProperty; + +private: + const int m_pageIdIndex; +}; + +// QWizardPropertySheet: Hides the "startId" property. It cannot be used +// as QWizard cannot handle setting it as a property before the actual +// page is added. + +class QWizardPropertySheet: public QDesignerPropertySheet +{ + Q_OBJECT +public: + explicit QWizardPropertySheet(QWizard *object, QObject *parent = 0); + virtual bool isVisible(int index) const; + +private: + const QString m_startId; +}; + +// Factories +typedef QDesignerPropertySheetFactory QWizardPropertySheetFactory; +typedef QDesignerPropertySheetFactory QWizardPagePropertySheetFactory; +typedef ExtensionFactory QWizardContainerFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QWIZARD_CONTAINER_H diff --git a/src/designer/src/components/formeditor/qworkspace_container.cpp b/src/designer/src/components/formeditor/qworkspace_container.cpp new file mode 100644 index 000000000..ca7de1c56 --- /dev/null +++ b/src/designer/src/components/formeditor/qworkspace_container.cpp @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qworkspace_container.h" +#include "qmdiarea_container.h" + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +QWorkspaceContainer::QWorkspaceContainer(QWorkspace *widget, QObject *parent) + : QObject(parent), + m_workspace(widget) +{ +} + +int QWorkspaceContainer::count() const +{ + return m_workspace->windowList(QWorkspace::CreationOrder).count(); +} + +QWidget *QWorkspaceContainer::widget(int index) const +{ + if (index < 0) + return 0; + return m_workspace->windowList(QWorkspace::CreationOrder).at(index); +} + +int QWorkspaceContainer::currentIndex() const +{ + if (QWidget *aw = m_workspace->activeWindow()) + return m_workspace->windowList(QWorkspace::CreationOrder).indexOf(aw); + return -1; +} + +void QWorkspaceContainer::setCurrentIndex(int index) +{ + m_workspace->setActiveWindow(m_workspace->windowList(QWorkspace::CreationOrder).at(index)); +} + +void QWorkspaceContainer::addWidget(QWidget *widget) +{ + QWidget *frame = m_workspace->addWindow(widget, Qt::Window); + frame->show(); + m_workspace->cascade(); + QMdiAreaContainer::positionNewMdiChild(m_workspace, frame); +} + +void QWorkspaceContainer::insertWidget(int, QWidget *widget) +{ + addWidget(widget); +} + +void QWorkspaceContainer::remove(int /* index */) +{ + // nothing to do here, reparenting to formwindow is apparently sufficient +} +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/qworkspace_container.h b/src/designer/src/components/formeditor/qworkspace_container.h new file mode 100644 index 000000000..f595044f4 --- /dev/null +++ b/src/designer/src/components/formeditor/qworkspace_container.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWORKSPACE_CONTAINER_H +#define QWORKSPACE_CONTAINER_H + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QWorkspaceContainer: public QObject, public QDesignerContainerExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerContainerExtension) +public: + explicit QWorkspaceContainer(QWorkspace *widget, QObject *parent = 0); + + virtual int count() const; + virtual QWidget *widget(int index) const; + virtual int currentIndex() const; + virtual void setCurrentIndex(int index); + virtual void addWidget(QWidget *widget); + virtual void insertWidget(int index, QWidget *widget); + virtual void remove(int index); + +private: + QWorkspace *m_workspace; +}; + +typedef ExtensionFactory QWorkspaceContainerFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QWORKSPACE_CONTAINER_H diff --git a/src/designer/src/components/formeditor/spacer_propertysheet.cpp b/src/designer/src/components/formeditor/spacer_propertysheet.cpp new file mode 100644 index 000000000..6ea37c4d4 --- /dev/null +++ b/src/designer/src/components/formeditor/spacer_propertysheet.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "spacer_propertysheet.h" +#include "qdesigner_widget_p.h" +#include "formwindow.h" +#include "spacer_widget_p.h" + +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal +{ +SpacerPropertySheet::SpacerPropertySheet(Spacer *object, QObject *parent) + : QDesignerPropertySheet(object, parent) +{ + clearFakeProperties(); +} + +SpacerPropertySheet::~SpacerPropertySheet() +{ +} + +bool SpacerPropertySheet::isVisible(int index) const +{ + static const QString spacerGroup = QLatin1String("Spacer"); + return propertyGroup(index) == spacerGroup; +} + +void SpacerPropertySheet::setProperty(int index, const QVariant &value) +{ + QDesignerPropertySheet::setProperty(index, value); +} + +bool SpacerPropertySheet::dynamicPropertiesAllowed() const +{ + return false; +} +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/spacer_propertysheet.h b/src/designer/src/components/formeditor/spacer_propertysheet.h new file mode 100644 index 000000000..256e3fd71 --- /dev/null +++ b/src/designer/src/components/formeditor/spacer_propertysheet.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SPACER_PROPERTYSHEET_H +#define SPACER_PROPERTYSHEET_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class SpacerPropertySheet: public QDesignerPropertySheet +{ + Q_OBJECT + Q_INTERFACES(QDesignerPropertySheetExtension) +public: + explicit SpacerPropertySheet(Spacer *object, QObject *parent = 0); + virtual ~SpacerPropertySheet(); + + virtual void setProperty(int index, const QVariant &value); + virtual bool isVisible(int index) const; + + virtual bool dynamicPropertiesAllowed() const; +}; + +typedef QDesignerPropertySheetFactory SpacerPropertySheetFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // SPACER_PROPERTYSHEET_H diff --git a/src/designer/src/components/formeditor/templateoptionspage.cpp b/src/designer/src/components/formeditor/templateoptionspage.cpp new file mode 100644 index 000000000..d81abc12d --- /dev/null +++ b/src/designer/src/components/formeditor/templateoptionspage.cpp @@ -0,0 +1,183 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "templateoptionspage.h" +#include "ui_templateoptionspage.h" + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// ----------------- TemplateOptionsWidget +TemplateOptionsWidget::TemplateOptionsWidget(QDesignerFormEditorInterface *core, QWidget *parent) : + QWidget(parent), + m_core(core), + m_ui(new Ui::TemplateOptionsWidget) +{ + m_ui->setupUi(this); + + m_ui->m_addTemplatePathButton->setIcon( + qdesigner_internal::createIconSet(QString::fromUtf8("plus.png"))); + m_ui->m_removeTemplatePathButton->setIcon( + qdesigner_internal::createIconSet(QString::fromUtf8("minus.png"))); + + connect(m_ui->m_templatePathListWidget, SIGNAL(itemSelectionChanged()), + this, SLOT(templatePathSelectionChanged())); + connect(m_ui->m_addTemplatePathButton, SIGNAL(clicked()), this, SLOT(addTemplatePath())); + connect(m_ui->m_removeTemplatePathButton, SIGNAL(clicked()), this, SLOT(removeTemplatePath())); +} + +TemplateOptionsWidget::~TemplateOptionsWidget() +{ + delete m_ui; +} + +QStringList TemplateOptionsWidget::templatePaths() const +{ + QStringList rc; + const int count = m_ui->m_templatePathListWidget->count(); + for (int i = 0; i < count; i++) { + rc += m_ui->m_templatePathListWidget->item(i)->text(); + } + return rc; +} + +void TemplateOptionsWidget::setTemplatePaths(const QStringList &l) +{ + // add paths and select 0 + m_ui->m_templatePathListWidget->clear(); + if (l.empty()) { + // disable button + templatePathSelectionChanged(); + } else { + const QStringList::const_iterator cend = l.constEnd(); + for (QStringList::const_iterator it = l.constBegin(); it != cend; ++it) + m_ui->m_templatePathListWidget->addItem(*it); + m_ui->m_templatePathListWidget->setCurrentItem(m_ui->m_templatePathListWidget->item(0)); + } +} + +void TemplateOptionsWidget::addTemplatePath() +{ + const QString templatePath = chooseTemplatePath(m_core, this); + if (templatePath.isEmpty()) + return; + + const QList existing + = m_ui->m_templatePathListWidget->findItems(templatePath, Qt::MatchExactly); + if (!existing.empty()) + return; + + QListWidgetItem *newItem = new QListWidgetItem(templatePath); + m_ui->m_templatePathListWidget->addItem(newItem); + m_ui->m_templatePathListWidget->setCurrentItem(newItem); +} + +void TemplateOptionsWidget::removeTemplatePath() +{ + const QList selectedPaths + = m_ui->m_templatePathListWidget->selectedItems(); + if (selectedPaths.empty()) + return; + delete selectedPaths.front(); +} + +void TemplateOptionsWidget::templatePathSelectionChanged() +{ + const QList selectedPaths = m_ui->m_templatePathListWidget->selectedItems(); + m_ui->m_removeTemplatePathButton->setEnabled(!selectedPaths.empty()); +} + +QString TemplateOptionsWidget::chooseTemplatePath(QDesignerFormEditorInterface *core, QWidget *parent) +{ + QString rc = core->dialogGui()->getExistingDirectory(parent, + tr("Pick a directory to save templates in")); + if (rc.isEmpty()) + return rc; + + if (rc.endsWith(QDir::separator())) + rc.remove(rc.size() - 1, 1); + return rc; +} + +// ----------------- TemplateOptionsPage +TemplateOptionsPage::TemplateOptionsPage(QDesignerFormEditorInterface *core) : + m_core(core) +{ +} + +QString TemplateOptionsPage::name() const +{ + //: Tab in preferences dialog + return QCoreApplication::translate("TemplateOptionsPage", "Template Paths"); +} + +QWidget *TemplateOptionsPage::createPage(QWidget *parent) +{ + m_widget = new TemplateOptionsWidget(m_core, parent); + m_initialTemplatePaths = QDesignerSharedSettings(m_core).additionalFormTemplatePaths(); + m_widget->setTemplatePaths(m_initialTemplatePaths); + return m_widget; +} + +void TemplateOptionsPage::apply() +{ + if (m_widget) { + const QStringList newTemplatePaths = m_widget->templatePaths(); + if (newTemplatePaths != m_initialTemplatePaths) { + QDesignerSharedSettings settings(m_core); + settings.setAdditionalFormTemplatePaths(newTemplatePaths); + m_initialTemplatePaths = newTemplatePaths; + } + } +} + +void TemplateOptionsPage::finish() +{ +} +} +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/templateoptionspage.h b/src/designer/src/components/formeditor/templateoptionspage.h new file mode 100644 index 000000000..98d468caa --- /dev/null +++ b/src/designer/src/components/formeditor/templateoptionspage.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_TEMPLATEOPTIONS_H +#define QDESIGNER_TEMPLATEOPTIONS_H + +#include + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +namespace Ui { + class TemplateOptionsWidget; +} + +/* Present the user with a list of form template paths to save + * form templates. */ +class TemplateOptionsWidget : public QWidget +{ + Q_OBJECT + Q_DISABLE_COPY(TemplateOptionsWidget) +public: + explicit TemplateOptionsWidget(QDesignerFormEditorInterface *core, + QWidget *parent = 0); + ~TemplateOptionsWidget(); + + + QStringList templatePaths() const; + void setTemplatePaths(const QStringList &l); + + static QString chooseTemplatePath(QDesignerFormEditorInterface *core, QWidget *parent); + +private slots: + void addTemplatePath(); + void removeTemplatePath(); + void templatePathSelectionChanged(); + +private: + QDesignerFormEditorInterface *m_core; + Ui::TemplateOptionsWidget *m_ui; +}; + +class TemplateOptionsPage : public QDesignerOptionsPageInterface +{ + Q_DISABLE_COPY(TemplateOptionsPage) +public: + explicit TemplateOptionsPage(QDesignerFormEditorInterface *core); + + virtual QString name() const; + virtual QWidget *createPage(QWidget *parent); + virtual void apply(); + virtual void finish(); + +private: + QDesignerFormEditorInterface *m_core; + QStringList m_initialTemplatePaths; + QPointer m_widget; +}; + +} + +QT_END_NAMESPACE + +#endif // QDESIGNER_TEMPLATEOPTIONS_H diff --git a/src/designer/src/components/formeditor/templateoptionspage.ui b/src/designer/src/components/formeditor/templateoptionspage.ui new file mode 100644 index 000000000..3427ffeb8 --- /dev/null +++ b/src/designer/src/components/formeditor/templateoptionspage.ui @@ -0,0 +1,59 @@ + + qdesigner_internal::TemplateOptionsWidget + + + + 0 + 0 + 376 + 387 + + + + Form + + + + + + Additional Template Paths + + + + + + + + + ... + + + + + + + ... + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + diff --git a/src/designer/src/components/formeditor/tool_widgeteditor.cpp b/src/designer/src/components/formeditor/tool_widgeteditor.cpp new file mode 100644 index 000000000..456967f59 --- /dev/null +++ b/src/designer/src/components/formeditor/tool_widgeteditor.cpp @@ -0,0 +1,363 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "tool_widgeteditor.h" +#include "formwindow.h" + +// sdk +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +WidgetEditorTool::WidgetEditorTool(FormWindow *formWindow) + : QDesignerFormWindowToolInterface(formWindow), + m_formWindow(formWindow), + m_action(new QAction(tr("Edit Widgets"), this)), + m_specialDockDrag(false) +{ +} + +QAction *WidgetEditorTool::action() const +{ + return m_action; +} + +WidgetEditorTool::~WidgetEditorTool() +{ +} + +QDesignerFormEditorInterface *WidgetEditorTool::core() const +{ + return m_formWindow->core(); +} + +QDesignerFormWindowInterface *WidgetEditorTool::formWindow() const +{ + return m_formWindow; +} + +bool WidgetEditorTool::mainWindowSeparatorEvent(QWidget *widget, QEvent *event) +{ + QMainWindow *mw = qobject_cast(widget); + if (mw == 0) + return false; + + if (event->type() != QEvent::MouseButtonPress + && event->type() != QEvent::MouseMove + && event->type() != QEvent::MouseButtonRelease) + return false; + + QMouseEvent *e = static_cast(event); + + if (event->type() == QEvent::MouseButtonPress) { + if (mw->isSeparator(e->pos())) { + m_separator_drag_mw = mw; + return true; + } + return false; + } + + if (event->type() == QEvent::MouseMove) + return m_separator_drag_mw == mw; + + if (event->type() == QEvent::MouseButtonRelease) { + if (m_separator_drag_mw != mw) + return false; + m_separator_drag_mw = 0; + return true; + } + + return false; +} + +bool WidgetEditorTool::handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event) +{ + const bool passive = core()->widgetFactory()->isPassiveInteractor(widget) != 0 + || mainWindowSeparatorEvent(widget, event); // separators in QMainWindow + // are no longer widgets + switch (event->type()) { + case QEvent::Resize: + case QEvent::Move: + m_formWindow->updateSelection(widget); + break; + + case QEvent::FocusOut: + case QEvent::FocusIn: // Popup cancelled over a form widget: Reset its focus frame + return !(passive || widget == m_formWindow || widget == m_formWindow->mainContainer()); + + case QEvent::Wheel: // Prevent spinboxes and combos from reacting + return !passive; + + case QEvent::KeyPress: + return !passive && handleKeyPressEvent(widget, managedWidget, static_cast(event)); + + case QEvent::KeyRelease: + return !passive && handleKeyReleaseEvent(widget, managedWidget, static_cast(event)); + + case QEvent::MouseMove: + return !passive && handleMouseMoveEvent(widget, managedWidget, static_cast(event)); + + case QEvent::MouseButtonPress: + return !passive && handleMousePressEvent(widget, managedWidget, static_cast(event)); + + case QEvent::MouseButtonRelease: + return !passive && handleMouseReleaseEvent(widget, managedWidget, static_cast(event)); + + case QEvent::MouseButtonDblClick: + return !passive && handleMouseButtonDblClickEvent(widget, managedWidget, static_cast(event)); + + case QEvent::ContextMenu: + return !passive && handleContextMenu(widget, managedWidget, static_cast(event)); + + case QEvent::DragEnter: + return handleDragEnterMoveEvent(widget, managedWidget, static_cast(event), true); + case QEvent::DragMove: + return handleDragEnterMoveEvent(widget, managedWidget, static_cast(event), false); + case QEvent::DragLeave: + return handleDragLeaveEvent(widget, managedWidget, static_cast(event)); + case QEvent::Drop: + return handleDropEvent(widget, managedWidget, static_cast(event)); + default: + break; + + } // end switch + + return false; +} + +// ### remove me + +bool WidgetEditorTool::handleContextMenu(QWidget *widget, QWidget *managedWidget, QContextMenuEvent *e) +{ + return m_formWindow->handleContextMenu(widget, managedWidget, e); +} + +bool WidgetEditorTool::handleMouseButtonDblClickEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e) +{ + return m_formWindow->handleMouseButtonDblClickEvent(widget, managedWidget, e); +} + +bool WidgetEditorTool::handleMousePressEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e) +{ + return m_formWindow->handleMousePressEvent(widget, managedWidget, e); +} + +bool WidgetEditorTool::handleMouseMoveEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e) +{ + return m_formWindow->handleMouseMoveEvent(widget, managedWidget, e); +} + +bool WidgetEditorTool::handleMouseReleaseEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e) +{ + return m_formWindow->handleMouseReleaseEvent(widget, managedWidget, e); +} + +bool WidgetEditorTool::handleKeyPressEvent(QWidget *widget, QWidget *managedWidget, QKeyEvent *e) +{ + return m_formWindow->handleKeyPressEvent(widget, managedWidget, e); +} + +bool WidgetEditorTool::handleKeyReleaseEvent(QWidget *widget, QWidget *managedWidget, QKeyEvent *e) +{ + return m_formWindow->handleKeyReleaseEvent(widget, managedWidget, e); +} + +bool WidgetEditorTool::handlePaintEvent(QWidget *widget, QWidget *managedWidget, QPaintEvent *e) +{ + Q_UNUSED(widget); + Q_UNUSED(managedWidget); + Q_UNUSED(e); + + return false; +} + +void WidgetEditorTool::detectDockDrag(const QDesignerMimeData *mimeData) +{ + m_specialDockDrag = false; + if (!mimeData) + return; + + QMainWindow *mw = qobject_cast(m_formWindow->mainContainer()); + if (!mw) + return; + + const QList item_list = mimeData->items(); + + foreach (QDesignerDnDItemInterface *item, item_list) { + if (item->decoration() && item->decoration()->property("_q_dockDrag").toBool()) + m_specialDockDrag = true; + + } +} + +bool WidgetEditorTool::handleDragEnterMoveEvent(QWidget *widget, QWidget * /*managedWidget*/, QDragMoveEvent *e, bool isEnter) +{ + const QDesignerMimeData *mimeData = qobject_cast(e->mimeData()); + if (!mimeData) + return false; + + if (!m_formWindow->hasFeature(QDesignerFormWindowInterface::EditFeature)) { + e->ignore(); + return true; + } + + if (isEnter) + detectDockDrag(mimeData); + + + QPoint globalPos = QPoint(0, 0); + if (m_specialDockDrag) { + m_lastDropTarget = 0; + QMainWindow *mw = qobject_cast(m_formWindow->mainContainer()); + if (mw) + m_lastDropTarget = mw->centralWidget(); + } else { + // If custom widgets have acceptDrops=true, the event occurs for them + const QPoint formPos = widget != m_formWindow ? widget->mapTo(m_formWindow, e->pos()) : e->pos(); + globalPos = m_formWindow->mapToGlobal(formPos); + const FormWindowBase::WidgetUnderMouseMode wum = mimeData->items().size() == 1 ? FormWindowBase::FindSingleSelectionDropTarget : FormWindowBase::FindMultiSelectionDropTarget; + QWidget *dropTarget = m_formWindow->widgetUnderMouse(formPos, wum); + if (m_lastDropTarget && dropTarget != m_lastDropTarget) + m_formWindow->highlightWidget(m_lastDropTarget, m_lastDropTarget->mapFromGlobal(globalPos), FormWindow::Restore); + m_lastDropTarget = dropTarget; + } + + if (m_lastDropTarget) + m_formWindow->highlightWidget(m_lastDropTarget, m_lastDropTarget->mapFromGlobal(globalPos), FormWindow::Highlight); + + if (isEnter || m_lastDropTarget) + mimeData->acceptEvent(e); + else + e->ignore(); + return true; +} + +bool WidgetEditorTool::handleDropEvent(QWidget *widget, QWidget *, QDropEvent *e) +{ + const QDesignerMimeData *mimeData = qobject_cast(e->mimeData()); + if (!mimeData) + return false; + + if (!m_lastDropTarget || + !m_formWindow->hasFeature(QDesignerFormWindowInterface::EditFeature)) { + e->ignore(); + return true; + } + // FormWindow determines the position from the decoration. + const QPoint globalPos = widget->mapToGlobal(e->pos()); + mimeData->moveDecoration(globalPos); + if (m_specialDockDrag) { + if (!m_formWindow->dropDockWidget(mimeData->items().at(0), globalPos)) { + e->ignore(); + return true; + } + } else if (!m_formWindow->dropWidgets(mimeData->items(), m_lastDropTarget, globalPos)) { + e->ignore(); + return true; + } + mimeData->acceptEvent(e); + return true; +} + +bool WidgetEditorTool::restoreDropHighlighting() +{ + if (!m_lastDropTarget) + return false; + + m_formWindow->highlightWidget(m_lastDropTarget, m_lastDropTarget->mapFromGlobal(QCursor::pos()), FormWindow::Restore); + m_lastDropTarget = 0; + return true; +} + +bool WidgetEditorTool::handleDragLeaveEvent(QWidget *, QWidget *, QDragLeaveEvent *event) +{ + if (restoreDropHighlighting()) { + event->accept(); + return true; + } + return false; +} + +QWidget *WidgetEditorTool::editor() const +{ + Q_ASSERT(formWindow() != 0); + return formWindow()->mainContainer(); +} + +void WidgetEditorTool::activated() +{ + if (core()->widgetBox()) + core()->widgetBox()->setEnabled(true); + + if (m_formWindow == 0) + return; + + QList sel = m_formWindow->selectedWidgets(); + foreach (QWidget *w, sel) + m_formWindow->raiseSelection(w); +} + +void WidgetEditorTool::deactivated() +{ + if (core()->widgetBox()) + core()->widgetBox()->setEnabled(false); + + if (m_formWindow == 0) + return; + + m_formWindow->clearSelection(); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/tool_widgeteditor.h b/src/designer/src/components/formeditor/tool_widgeteditor.h new file mode 100644 index 000000000..369c2fc14 --- /dev/null +++ b/src/designer/src/components/formeditor/tool_widgeteditor.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TOOL_WIDGETEDITOR_H +#define TOOL_WIDGETEDITOR_H + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QAction; +class QMainWindow; + +namespace qdesigner_internal { + +class FormWindow; +class QDesignerMimeData; + +class WidgetEditorTool: public QDesignerFormWindowToolInterface +{ + Q_OBJECT +public: + explicit WidgetEditorTool(FormWindow *formWindow); + virtual ~WidgetEditorTool(); + + virtual QDesignerFormEditorInterface *core() const; + virtual QDesignerFormWindowInterface *formWindow() const; + virtual QWidget *editor() const; + virtual QAction *action() const; + + virtual void activated(); + virtual void deactivated(); + + virtual bool handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event); + + bool handleContextMenu(QWidget *widget, QWidget *managedWidget, QContextMenuEvent *e); + bool handleMouseButtonDblClickEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e); + bool handleMousePressEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e); + bool handleMouseMoveEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e); + bool handleMouseReleaseEvent(QWidget *widget, QWidget *managedWidget, QMouseEvent *e); + bool handleKeyPressEvent(QWidget *widget, QWidget *managedWidget, QKeyEvent *e); + bool handleKeyReleaseEvent(QWidget *widget, QWidget *managedWidget, QKeyEvent *e); + bool handlePaintEvent(QWidget *widget, QWidget *managedWidget, QPaintEvent *e); + + bool handleDragEnterMoveEvent(QWidget *widget, QWidget *managedWidget, QDragMoveEvent *e, bool isEnter); + bool handleDragLeaveEvent(QWidget *widget, QWidget *managedWidget, QDragLeaveEvent *e); + bool handleDropEvent(QWidget *widget, QWidget *managedWidget, QDropEvent *e); + +private: + bool restoreDropHighlighting(); + void detectDockDrag(const QDesignerMimeData *mimeData); + + FormWindow *m_formWindow; + QAction *m_action; + + bool mainWindowSeparatorEvent(QWidget *widget, QEvent *event); + QPointer m_separator_drag_mw; + QPointer m_lastDropTarget; + bool m_specialDockDrag; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // TOOL_WIDGETEDITOR_H diff --git a/src/designer/src/components/formeditor/widgetselection.cpp b/src/designer/src/components/formeditor/widgetselection.cpp new file mode 100644 index 000000000..501859130 --- /dev/null +++ b/src/designer/src/components/formeditor/widgetselection.cpp @@ -0,0 +1,746 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "widgetselection.h" +#include "formwindow.h" +#include "formwindowmanager.h" + +// sdk +#include +#include + +// shared +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { +enum { debugWidgetSelection = 0 }; + +// Return the layout the widget is in +template +static inline Layout *managedLayoutOf(const QDesignerFormEditorInterface *core, + QWidget *w, + const Layout * /* vs6dummy */ = 0) +{ + if (QWidget *p = w->parentWidget()) + if (QLayout *l = LayoutInfo::managedLayout(core, p)) + return qobject_cast(l); + return 0; +} + +// ----------- WidgetHandle +WidgetHandle::WidgetHandle(FormWindow *parent, WidgetHandle::Type t, WidgetSelection *s) : + InvisibleWidget(parent->formContainer()), + m_widget(0), + m_type(t), + m_formWindow( parent), + m_sel(s), + m_active(true) +{ + setMouseTracking(false); + setAutoFillBackground(true); + + setBackgroundRole(m_active ? QPalette::Text : QPalette::Dark); + setFixedSize(6, 6); + + updateCursor(); +} + +void WidgetHandle::updateCursor() +{ +#ifndef QT_NO_CURSOR + if (!m_active) { + setCursor(Qt::ArrowCursor); + return; + } + + switch (m_type) { + case LeftTop: + setCursor(Qt::SizeFDiagCursor); + break; + case Top: + setCursor(Qt::SizeVerCursor); + break; + case RightTop: + setCursor(Qt::SizeBDiagCursor); + break; + case Right: + setCursor(Qt::SizeHorCursor); + break; + case RightBottom: + setCursor(Qt::SizeFDiagCursor); + break; + case Bottom: + setCursor(Qt::SizeVerCursor); + break; + case LeftBottom: + setCursor(Qt::SizeBDiagCursor); + break; + case Left: + setCursor(Qt::SizeHorCursor); + break; + default: + Q_ASSERT(0); + } +#endif +} + +QDesignerFormEditorInterface *WidgetHandle::core() const +{ + if (m_formWindow) + return m_formWindow->core(); + + return 0; +} + +void WidgetHandle::setActive(bool a) +{ + m_active = a; + setBackgroundRole(m_active ? QPalette::Text : QPalette::Dark); + updateCursor(); +} + +void WidgetHandle::setWidget(QWidget *w) +{ + m_widget = w; +} + +void WidgetHandle::paintEvent(QPaintEvent *) +{ + QDesignerFormWindowManagerInterface *m = m_formWindow->core()->formWindowManager(); + + QStylePainter p(this); + if (m_formWindow->currentWidget() == m_widget) { + p.setPen(m->activeFormWindow() == m_formWindow ? Qt::blue : Qt::red); + p.drawRect(0, 0, width() - 1, height() - 1); + } +} + +void WidgetHandle::mousePressEvent(QMouseEvent *e) +{ + e->accept(); + + if (!m_formWindow->hasFeature(FormWindow::EditFeature)) + return; + + if (!(m_widget && e->button() == Qt::LeftButton)) + return; + + if (!(m_active)) + return; + + QWidget *container = m_widget->parentWidget(); + + m_origPressPos = container->mapFromGlobal(e->globalPos()); + m_geom = m_origGeom = m_widget->geometry(); +} + +void WidgetHandle::mouseMoveEvent(QMouseEvent *e) +{ + if (!(m_widget && m_active && e->buttons() & Qt::LeftButton)) + return; + + e->accept(); + + QWidget *container = m_widget->parentWidget(); + + const QPoint rp = container->mapFromGlobal(e->globalPos()); + const QPoint d = rp - m_origPressPos; + + const QRect pr = container->rect(); + + qdesigner_internal::Grid grid; + if (const qdesigner_internal::FormWindowBase *fwb = qobject_cast(m_formWindow)) + grid = fwb->designerGrid(); + + switch (m_type) { + + case LeftTop: { + if (rp.x() > pr.width() - 2 * width() || rp.y() > pr.height() - 2 * height()) + return; + + int w = m_origGeom.width() - d.x(); + m_geom.setWidth(w); + w = grid.widgetHandleAdjustX(w); + + int h = m_origGeom.height() - d.y(); + m_geom.setHeight(h); + h = grid.widgetHandleAdjustY(h); + + const int dx = m_widget->width() - w; + const int dy = m_widget->height() - h; + + trySetGeometry(m_widget, m_widget->x() + dx, m_widget->y() + dy, w, h); + } break; + + case Top: { + if (rp.y() > pr.height() - 2 * height()) + return; + + int h = m_origGeom.height() - d.y(); + m_geom.setHeight(h); + h = grid.widgetHandleAdjustY(h); + + const int dy = m_widget->height() - h; + trySetGeometry(m_widget, m_widget->x(), m_widget->y() + dy, m_widget->width(), h); + } break; + + case RightTop: { + if (rp.x() < 2 * width() || rp.y() > pr.height() - 2 * height()) + return; + + int h = m_origGeom.height() - d.y(); + m_geom.setHeight(h); + h = grid.widgetHandleAdjustY(h); + + const int dy = m_widget->height() - h; + + int w = m_origGeom.width() + d.x(); + m_geom.setWidth(w); + w = grid.widgetHandleAdjustX(w); + + trySetGeometry(m_widget, m_widget->x(), m_widget->y() + dy, w, h); + } break; + + case Right: { + if (rp.x() < 2 * width()) + return; + + int w = m_origGeom.width() + d.x(); + m_geom.setWidth(w); + w = grid.widgetHandleAdjustX(w); + + tryResize(m_widget, w, m_widget->height()); + } break; + + case RightBottom: { + if (rp.x() < 2 * width() || rp.y() < 2 * height()) + return; + + int w = m_origGeom.width() + d.x(); + m_geom.setWidth(w); + w = grid.widgetHandleAdjustX(w); + + int h = m_origGeom.height() + d.y(); + m_geom.setHeight(h); + h = grid.widgetHandleAdjustY(h); + + tryResize(m_widget, w, h); + } break; + + case Bottom: { + if (rp.y() < 2 * height()) + return; + + int h = m_origGeom.height() + d.y(); + m_geom.setHeight(h); + h = grid.widgetHandleAdjustY(h); + + tryResize(m_widget, m_widget->width(), h); + } break; + + case LeftBottom: { + if (rp.x() > pr.width() - 2 * width() || rp.y() < 2 * height()) + return; + + int w = m_origGeom.width() - d.x(); + m_geom.setWidth(w); + w = grid.widgetHandleAdjustX(w); + + int h = m_origGeom.height() + d.y(); + m_geom.setHeight(h); + h = grid.widgetHandleAdjustY(h); + + int dx = m_widget->width() - w; + + trySetGeometry(m_widget, m_widget->x() + dx, m_widget->y(), w, h); + } break; + + case Left: { + if (rp.x() > pr.width() - 2 * width()) + return; + + int w = m_origGeom.width() - d.x(); + m_geom.setWidth(w); + w = grid.widgetHandleAdjustX(w); + + const int dx = m_widget->width() - w; + + trySetGeometry(m_widget, m_widget->x() + dx, m_widget->y(), w, m_widget->height()); + } break; + + default: break; + + } // end switch + + m_sel->updateGeometry(); + + if (LayoutInfo::layoutType(m_formWindow->core(), m_widget) != LayoutInfo::NoLayout) + m_formWindow->updateChildSelections(m_widget); +} + +void WidgetHandle::mouseReleaseEvent(QMouseEvent *e) +{ + if (e->button() != Qt::LeftButton || !m_active) + return; + + e->accept(); + + if (!m_formWindow->hasFeature(FormWindow::EditFeature)) + return; + + switch (WidgetSelection::widgetState(m_formWindow->core(), m_widget)) { + case WidgetSelection::UnlaidOut: + if (m_geom != m_widget->geometry()) { + SetPropertyCommand *cmd = new SetPropertyCommand(m_formWindow); + cmd->init(m_widget, QLatin1String("geometry"), m_widget->geometry()); + cmd->setOldValue(m_origGeom); + m_formWindow->commandHistory()->push(cmd); + m_formWindow->emitSelectionChanged(); + } + break; + case WidgetSelection::LaidOut: + break; + case WidgetSelection::ManagedGridLayout: + changeGridLayoutItemSpan(); + break; + case WidgetSelection::ManagedFormLayout: + changeFormLayoutItemSpan(); + break; + } +} + +// Match the left/right widget handle mouse movements to form layout span-changing operations +static inline int formLayoutLeftHandleOperation(int dx, unsigned possibleOperations) +{ + if (dx < 0) { + if (possibleOperations & ChangeFormLayoutItemRoleCommand::FieldToSpanning) + return ChangeFormLayoutItemRoleCommand::FieldToSpanning; + return 0; + } + if (possibleOperations & ChangeFormLayoutItemRoleCommand::SpanningToField) + return ChangeFormLayoutItemRoleCommand::SpanningToField; + return 0; +} + +static inline int formLayoutRightHandleOperation(int dx, unsigned possibleOperations) +{ + if (dx < 0) { + if (possibleOperations & ChangeFormLayoutItemRoleCommand::SpanningToLabel) + return ChangeFormLayoutItemRoleCommand::SpanningToLabel; + return 0; + } + if (possibleOperations & ChangeFormLayoutItemRoleCommand::LabelToSpanning) + return ChangeFormLayoutItemRoleCommand::LabelToSpanning; + return 0; +} + +// Change form layout item horizontal span +void WidgetHandle::changeFormLayoutItemSpan() +{ + QUndoCommand *cmd = 0; + // Figure out command according to the movement + const int dx = m_widget->geometry().center().x() - m_origGeom.center().x(); + if (qAbs(dx) >= QApplication::startDragDistance()) { + int operation = 0; + if (const unsigned possibleOperations = ChangeFormLayoutItemRoleCommand::possibleOperations(m_formWindow->core(), m_widget)) { + switch (m_type) { + case WidgetHandle::Left: + operation = formLayoutLeftHandleOperation(dx, possibleOperations); + break; + case WidgetHandle::Right: + operation = formLayoutRightHandleOperation(dx, possibleOperations); + break; + default: + break; + } + if (operation) { + ChangeFormLayoutItemRoleCommand *fcmd = new ChangeFormLayoutItemRoleCommand(m_formWindow); + fcmd->init(m_widget, static_cast(operation)); + cmd = fcmd; + } + } + } + if (cmd) { + m_formWindow->commandHistory()->push(cmd); + } else { + // Cancelled/Invalid. Restore the size of the widget. + if (QFormLayout *form = managedLayoutOf(m_formWindow->core(), m_widget)) { + form->invalidate(); + form->activate(); + m_formWindow->clearSelection(false); + m_formWindow->selectWidget(m_widget); + } + } +} + +void WidgetHandle::changeGridLayoutItemSpan() +{ + QDesignerLayoutDecorationExtension *deco = qt_extension(core()->extensionManager(), m_widget->parentWidget()); + if (!deco) + return; + QGridLayout *grid = managedLayoutOf(m_formWindow->core(), m_widget); + if (!grid) + return; + + const QSize size = m_widget->parentWidget()->size(); + + const int index = deco->indexOf(m_widget); + const QRect info = deco->itemInfo(index); + const int top = deco->findItemAt(info.top() - 1, info.left()); + const int left = deco->findItemAt(info.top(), info.left() - 1); + const int bottom = deco->findItemAt(info.bottom() + 1, info.left()); + const int right = deco->findItemAt(info.top(), info.right() + 1); + + const QPoint pt = m_origGeom.center() - m_widget->geometry().center(); + + ChangeLayoutItemGeometry *cmd = 0; + + switch (m_type) { + default: + break; + + case WidgetHandle::Top: { + if (pt.y() < 0 && info.height() > 1) { + cmd = new ChangeLayoutItemGeometry(m_formWindow); + cmd->init(m_widget, info.y() + 1, info.x(), info.height() - 1, info.width()); + } else if (pt.y() > 0 && top != -1 && grid->itemAt(top)->spacerItem()) { + cmd = new ChangeLayoutItemGeometry(m_formWindow); + cmd->init(m_widget, info.y() - 1, info.x(), info.height() + 1, info.width()); + } + } + break; + + case WidgetHandle::Left: { + if (pt.x() < 0 && info.width() > 1) { + cmd = new ChangeLayoutItemGeometry(m_formWindow); + cmd->init(m_widget, info.y(), info.x() + 1, info.height(), info.width() - 1); + } else if (pt.x() > 0 && left != -1 && grid->itemAt(left)->spacerItem()) { + cmd = new ChangeLayoutItemGeometry(m_formWindow); + cmd->init(m_widget, info.y(), info.x() - 1, info.height(), info.width() + 1); + } + } + break; + + case WidgetHandle::Right: { + if (pt.x() > 0 && info.width() > 1) { + cmd = new ChangeLayoutItemGeometry(m_formWindow); + cmd->init(m_widget, info.y(), info.x(), info.height(), info.width() - 1); + } else if (pt.x() < 0 && right != -1 && grid->itemAt(right)->spacerItem()) { + cmd = new ChangeLayoutItemGeometry(m_formWindow); + cmd->init(m_widget, info.y(), info.x(), info.height(), info.width() + 1); + } + } + break; + + case WidgetHandle::Bottom: { + if (pt.y() > 0 && info.width() > 1) { + cmd = new ChangeLayoutItemGeometry(m_formWindow); + cmd->init(m_widget, info.y(), info.x(), info.height() - 1, info.width()); + } else if (pt.y() < 0 && bottom != -1 && grid->itemAt(bottom)->spacerItem()) { + cmd = new ChangeLayoutItemGeometry(m_formWindow); + cmd->init(m_widget, info.y(), info.x(), info.height() + 1, info.width()); + } + } + break; + } + + if (cmd != 0) { + m_formWindow->commandHistory()->push(cmd); + } else { + grid->invalidate(); + grid->activate(); + m_formWindow->clearSelection(false); + m_formWindow->selectWidget(m_widget); + } +} + +void WidgetHandle::trySetGeometry(QWidget *w, int x, int y, int width, int height) +{ + if (!m_formWindow->hasFeature(FormWindow::EditFeature)) + return; + + int minw = w->minimumSize().width(); + minw = qMax(minw, 2 * m_formWindow->grid().x()); + + int minh = w->minimumSize().height(); + minh = qMax(minh, 2 * m_formWindow->grid().y()); + + if (qMax(minw, width) > w->maximumWidth() || + qMax(minh, height) > w->maximumHeight()) + return; + + if (width < minw && x != w->x()) + x -= minw - width; + + if (height < minh && y != w->y()) + y -= minh - height; + + w->setGeometry(x, y, qMax(minw, width), qMax(minh, height)); +} + +void WidgetHandle::tryResize(QWidget *w, int width, int height) +{ + int minw = w->minimumSize().width(); + minw = qMax(minw, 16); + + int minh = w->minimumSize().height(); + minh = qMax(minh, 16); + + w->resize(qMax(minw, width), qMax(minh, height)); +} + +// ------------------ WidgetSelection + +WidgetSelection::WidgetState WidgetSelection::widgetState(const QDesignerFormEditorInterface *core, QWidget *w) +{ + bool isManaged; + const LayoutInfo::Type lt = LayoutInfo::laidoutWidgetType(core, w, &isManaged); + if (lt == LayoutInfo::NoLayout) + return UnlaidOut; + if (!isManaged) + return LaidOut; + switch (lt) { + case LayoutInfo::Grid: + return ManagedGridLayout; + case LayoutInfo::Form: + return ManagedFormLayout; + default: + break; + } + return LaidOut; +} + +WidgetSelection::WidgetSelection(FormWindow *parent) : + m_widget(0), + m_formWindow(parent) +{ + for (int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i) + m_handles[i] = new WidgetHandle(m_formWindow, static_cast(i), this); + hide(); +} + +void WidgetSelection::setWidget(QWidget *w) +{ + if (m_widget != 0) + m_widget->removeEventFilter(this); + + if (w == 0) { + hide(); + m_widget = 0; + return; + } + + m_widget = w; + + m_widget->installEventFilter(this); + + updateActive(); + + updateGeometry(); + show(); +} + +void WidgetSelection::updateActive() +{ + const WidgetState ws = widgetState(m_formWindow->core(), m_widget); + bool active[WidgetHandle::TypeCount]; + qFill(active, active + WidgetHandle::TypeCount, false); + // Determine active handles + switch (ws) { + case UnlaidOut: + qFill(active, active + WidgetHandle::TypeCount, true); + break; + case ManagedGridLayout: // Grid: Allow changing span + active[WidgetHandle::Left] = active[WidgetHandle::Top] = active[WidgetHandle::Right] = active[WidgetHandle::Bottom] = true; + break; + case ManagedFormLayout: // Form: Allow changing column span + if (const unsigned operation = ChangeFormLayoutItemRoleCommand::possibleOperations(m_formWindow->core(), m_widget)) { + active[WidgetHandle::Left] = operation & (ChangeFormLayoutItemRoleCommand::SpanningToField|ChangeFormLayoutItemRoleCommand::FieldToSpanning); + active[WidgetHandle::Right] = operation & (ChangeFormLayoutItemRoleCommand::SpanningToLabel|ChangeFormLayoutItemRoleCommand::LabelToSpanning); + } + break; + default: + break; + } + + for (int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i) + if (WidgetHandle *h = m_handles[i]) { + h->setWidget(m_widget); + h->setActive(active[i]); + } +} + +bool WidgetSelection::isUsed() const +{ + return m_widget != 0; +} + +void WidgetSelection::updateGeometry() +{ + if (!m_widget || !m_widget->parentWidget()) + return; + + QPoint p = m_widget->parentWidget()->mapToGlobal(m_widget->pos()); + p = m_formWindow->formContainer()->mapFromGlobal(p); + const QRect r(p, m_widget->size()); + + const int w = 6; + const int h = 6; + + for (int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i) { + WidgetHandle *hndl = m_handles[ i ]; + if (!hndl) + continue; + switch (i) { + case WidgetHandle::LeftTop: + hndl->move(r.x() - w / 2, r.y() - h / 2); + break; + case WidgetHandle::Top: + hndl->move(r.x() + r.width() / 2 - w / 2, r.y() - h / 2); + break; + case WidgetHandle::RightTop: + hndl->move(r.x() + r.width() - w / 2, r.y() - h / 2); + break; + case WidgetHandle::Right: + hndl->move(r.x() + r.width() - w / 2, r.y() + r.height() / 2 - h / 2); + break; + case WidgetHandle::RightBottom: + hndl->move(r.x() + r.width() - w / 2, r.y() + r.height() - h / 2); + break; + case WidgetHandle::Bottom: + hndl->move(r.x() + r.width() / 2 - w / 2, r.y() + r.height() - h / 2); + break; + case WidgetHandle::LeftBottom: + hndl->move(r.x() - w / 2, r.y() + r.height() - h / 2); + break; + case WidgetHandle::Left: + hndl->move(r.x() - w / 2, r.y() + r.height() / 2 - h / 2); + break; + default: + break; + } + } +} + +void WidgetSelection::hide() +{ + for (int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i) { + WidgetHandle *h = m_handles[ i ]; + if (h) + h->hide(); + } +} + +void WidgetSelection::show() +{ + for (int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i) { + WidgetHandle *h = m_handles[ i ]; + if (h) { + h->show(); + h->raise(); + } + } +} + +void WidgetSelection::update() +{ + for (int i = WidgetHandle::LeftTop; i < WidgetHandle::TypeCount; ++i) { + WidgetHandle *h = m_handles[ i ]; + if (h) + h->update(); + } +} + +QWidget *WidgetSelection::widget() const +{ + return m_widget; +} + +QDesignerFormEditorInterface *WidgetSelection::core() const +{ + if (m_formWindow) + return m_formWindow->core(); + + return 0; +} + +bool WidgetSelection::eventFilter(QObject *object, QEvent *event) +{ + if (object != widget()) + return false; + + switch (event->type()) { + default: break; + + case QEvent::Move: + case QEvent::Resize: + updateGeometry(); + break; + case QEvent::ZOrderChange: + show(); + break; + } // end switch + + return false; +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/formeditor/widgetselection.h b/src/designer/src/components/formeditor/widgetselection.h new file mode 100644 index 000000000..987bd4b51 --- /dev/null +++ b/src/designer/src/components/formeditor/widgetselection.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WIDGETSELECTION_H +#define WIDGETSELECTION_H + +#include "formeditor_global.h" +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QMouseEvent; +class QPaintEvent; + +namespace qdesigner_internal { + +class FormWindow; +class WidgetSelection; + +class QT_FORMEDITOR_EXPORT WidgetHandle: public InvisibleWidget +{ + Q_OBJECT +public: + enum Type + { + LeftTop, + Top, + RightTop, + Right, + RightBottom, + Bottom, + LeftBottom, + Left, + + TypeCount + }; + + WidgetHandle(FormWindow *parent, Type t, WidgetSelection *s); + void setWidget(QWidget *w); + void setActive(bool a); + void updateCursor(); + + void setEnabled(bool) {} + + QDesignerFormEditorInterface *core() const; + +protected: + void paintEvent(QPaintEvent *e); + void mousePressEvent(QMouseEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void mouseReleaseEvent(QMouseEvent *e); + +private: + void changeGridLayoutItemSpan(); + void changeFormLayoutItemSpan(); + void trySetGeometry(QWidget *w, int x, int y, int width, int height); + void tryResize(QWidget *w, int width, int height); + +private: + QWidget *m_widget; + const Type m_type; + QPoint m_origPressPos; + FormWindow *m_formWindow; + WidgetSelection *m_sel; + QRect m_geom, m_origGeom; + bool m_active; +}; + +class QT_FORMEDITOR_EXPORT WidgetSelection: public QObject +{ + Q_OBJECT +public: + WidgetSelection(FormWindow *parent); + + void setWidget(QWidget *w); + bool isUsed() const; + + void updateActive(); + void updateGeometry(); + void hide(); + void show(); + void update(); + + QWidget *widget() const; + + QDesignerFormEditorInterface *core() const; + + virtual bool eventFilter(QObject *object, QEvent *event); + + enum WidgetState { UnlaidOut, LaidOut, ManagedGridLayout, ManagedFormLayout }; + static WidgetState widgetState(const QDesignerFormEditorInterface *core, QWidget *w); + +private: + WidgetHandle *m_handles[WidgetHandle::TypeCount]; + QPointer m_widget; + FormWindow *m_formWindow; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // WIDGETSELECTION_H diff --git a/src/designer/src/components/lib/lib.pro b/src/designer/src/components/lib/lib.pro new file mode 100644 index 000000000..50a8b00fa --- /dev/null +++ b/src/designer/src/components/lib/lib.pro @@ -0,0 +1,77 @@ +TEMPLATE = lib +TARGET = QtDesignerComponents +contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols +CONFIG += qt depend_prl no_objective_c designer +win32|mac: CONFIG += debug_and_release +QTDIR_build { + DESTDIR = $$QT_BUILD_TREE/lib + !wince*:DLLDESTDIR = $$QT_BUILD_TREE/bin +} + +# QtDesignerComponents uses +DEFINES += QT_STATICPLUGIN + +isEmpty(QT_MAJOR_VERSION) { + VERSION=4.3.0 +} else { + VERSION=$${QT_MAJOR_VERSION}.$${QT_MINOR_VERSION}.$${QT_PATCH_VERSION} +} + +include(../../../../../src/qt_targets.pri) +QMAKE_TARGET_PRODUCT = Designer +QMAKE_TARGET_DESCRIPTION = Graphical user interface designer. + +#load up the headers info +CONFIG += qt_install_headers +HEADERS_PRI = $$QT_BUILD_TREE/include/QtDesigner/headers.pri +include($$HEADERS_PRI, "", true)|clear(HEADERS_PRI) + +#mac frameworks +mac:!static:contains(QT_CONFIG, qt_framework) { + QMAKE_FRAMEWORK_BUNDLE_NAME = $$TARGET + CONFIG += lib_bundle qt_no_framework_direct_includes qt_framework + CONFIG(debug, debug|release):!build_pass:CONFIG += build_all +} + +SOURCES += qdesigner_components.cpp + +!contains(CONFIG, static) { + DEFINES += QDESIGNER_COMPONENTS_LIBRARY + CONFIG += dll + LIBS += -lQtDesigner +} else { + DEFINES += QT_DESIGNER_STATIC +} + +INCLUDEPATH += . .. \ + $$PWD/../../lib/components \ + $$PWD/../../lib/sdk \ + $$PWD/../../lib/extension \ + $$PWD/../../lib/uilib \ + $$PWD/../../lib/shared + +include(../propertyeditor/propertyeditor.pri) +include(../objectinspector/objectinspector.pri) +include(../signalsloteditor/signalsloteditor.pri) +include(../formeditor/formeditor.pri) +include(../widgetbox/widgetbox.pri) +include(../buddyeditor/buddyeditor.pri) +include(../taskmenu/taskmenu.pri) +include(../tabordereditor/tabordereditor.pri) + +PRECOMPILED_HEADER= lib_pch.h + +include(../../sharedcomponents.pri) +include(../component.pri) + +unix|win32-g++* { + QMAKE_PKGCONFIG_REQUIRES = QtCore QtDesigner QtGui QtXml + contains(QT_CONFIG, script): QMAKE_PKGCONFIG_REQUIRES += QtScript +} + +target.path=$$[QT_INSTALL_LIBS] +INSTALLS += target +win32 { + dlltarget.path=$$[QT_INSTALL_BINS] + INSTALLS += dlltarget +} diff --git a/src/designer/src/components/lib/lib_pch.h b/src/designer/src/components/lib/lib_pch.h new file mode 100644 index 000000000..7f2765a79 --- /dev/null +++ b/src/designer/src/components/lib/lib_pch.h @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include diff --git a/src/designer/src/components/lib/qdesigner_components.cpp b/src/designer/src/components/lib/qdesigner_components.cpp new file mode 100644 index 000000000..9b7457f46 --- /dev/null +++ b/src/designer/src/components/lib/qdesigner_components.cpp @@ -0,0 +1,277 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include "qtresourceview_p.h" +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +// ### keep it in sync with Q_IMPORT_PLUGIN in qplugin.h +#define DECLARE_PLUGIN_INSTANCE(PLUGIN) \ + extern QT_PREPEND_NAMESPACE(QObject) *qt_plugin_instance_##PLUGIN(); \ + class Static##PLUGIN##PluginInstance { public: \ + Static##PLUGIN##PluginInstance() { \ + QT_PREPEND_NAMESPACE(qRegisterStaticPluginInstanceFunction) \ + (&qt_plugin_instance_##PLUGIN); \ + } \ + }; + +#define INIT_PLUGIN_INSTANCE(PLUGIN) \ + do { \ + Static##PLUGIN##PluginInstance instance; \ + Q_UNUSED(instance); \ + } while (0) + +DECLARE_PLUGIN_INSTANCE(SignalSlotEditorPlugin) +DECLARE_PLUGIN_INSTANCE(BuddyEditorPlugin) +DECLARE_PLUGIN_INSTANCE(TabOrderEditorPlugin) + +static void initResources() +{ + // Q_INIT_RESOURCE only usable in functions in global namespace + Q_INIT_RESOURCE(formeditor); + Q_INIT_RESOURCE(widgetbox); + Q_INIT_RESOURCE(propertyeditor); +} + + +static void initInstances() +{ + static bool plugins_initialized = false; + + if (!plugins_initialized) { + INIT_PLUGIN_INSTANCE(SignalSlotEditorPlugin); + INIT_PLUGIN_INSTANCE(BuddyEditorPlugin); + INIT_PLUGIN_INSTANCE(TabOrderEditorPlugin); + plugins_initialized = true; + } +} + +QT_BEGIN_NAMESPACE + +/*! + \class QDesignerComponents + \brief The QDesignerComponents class provides a central resource for the various components + used in the \QD user interface. + \inmodule QtDesigner + \internal + + The QDesignerComponents class is a factory for each of the standard components present + in the \QD user interface. It is mostly useful for developers who want to implement + a standalone form editing environment using \QD's components, or who need to integrate + \QD's components into an existing integrated development environment (IDE). + + \sa QDesignerFormEditorInterface, QDesignerObjectInspectorInterface, + QDesignerPropertyEditorInterface, QDesignerWidgetBoxInterface +*/ + +/*! + Initializes the resources used by the components.*/ +void QDesignerComponents::initializeResources() +{ + initResources(); +} + +/*! + Initializes the plugins used by the components.*/ +void QDesignerComponents::initializePlugins(QDesignerFormEditorInterface *core) +{ + qdesigner_internal::QDesignerIntegration::initializePlugins(core); +} + +/*! + Constructs a form editor interface with the given \a parent.*/ +QDesignerFormEditorInterface *QDesignerComponents::createFormEditor(QObject *parent) +{ + initInstances(); + return new qdesigner_internal::FormEditor(parent); +} + +/*! + Returns a new task menu with the given \a parent for the \a core interface.*/ +QObject *QDesignerComponents::createTaskMenu(QDesignerFormEditorInterface *core, QObject *parent) +{ + return new qdesigner_internal::TaskMenuComponent(core, parent); +} + +static inline int qtMajorVersion(int qtVersion) { return qtVersion >> 16; } +static inline int qtMinorVersion(int qtVersion) { return (qtVersion >> 8) & 0xFF; } +static inline void setMinorVersion(int minorVersion, int *qtVersion) +{ + *qtVersion &= ~0xFF00; + *qtVersion |= minorVersion << 8; +} + +// Build the version-dependent name of the user widget box file, '$HOME.designer/widgetbox4.4.xml' +static inline QString widgetBoxFileName(int qtVersion, const QDesignerLanguageExtension *lang = 0) +{ + QString rc; { + const QChar dot = QLatin1Char('.'); + QTextStream str(&rc); + str << QDir::homePath() << QDir::separator() << QLatin1String(".designer") << QDir::separator() + << QLatin1String("widgetbox"); + // The naming convention using the version was introduced with 4.4 + const int major = qtMajorVersion(qtVersion); + const int minor = qtMinorVersion(qtVersion); + if (major >= 4 && minor >= 4) + str << major << dot << minor; + if (lang) + str << dot << lang->uiExtension(); + str << QLatin1String(".xml"); + } + return rc; +} + +/*! + Returns a new widget box interface with the given \a parent for the \a core interface.*/ +QDesignerWidgetBoxInterface *QDesignerComponents::createWidgetBox(QDesignerFormEditorInterface *core, QWidget *parent) +{ + qdesigner_internal::WidgetBox *widgetBox = new qdesigner_internal::WidgetBox(core, parent); + + const QDesignerLanguageExtension *lang = qt_extension(core->extensionManager(), core); + + do { + if (lang) { + const QString languageWidgetBox = lang->widgetBoxContents(); + if (!languageWidgetBox.isEmpty()) { + widgetBox->loadContents(lang->widgetBoxContents()); + break; + } + } + + widgetBox->setFileName(QLatin1String(":/trolltech/widgetbox/widgetbox.xml")); + widgetBox->load(); + } while (false); + + const QString userWidgetBoxFile = widgetBoxFileName(QT_VERSION, lang); + + widgetBox->setFileName(userWidgetBoxFile); + if (!QFileInfo(userWidgetBoxFile).exists()) { + // check previous version, that is, are we running the new version for the first time + // If so, try to copy the old widget box file + if (const int minv = qtMinorVersion(QT_VERSION)) { + int oldVersion = QT_VERSION; + setMinorVersion(minv - 1, &oldVersion); + const QString oldWidgetBoxFile = widgetBoxFileName(oldVersion, lang); + if (QFileInfo(oldWidgetBoxFile).exists()) + QFile::copy(oldWidgetBoxFile, userWidgetBoxFile); + } + } + widgetBox->load(); + + return widgetBox; +} + +/*! + Returns a new property editor interface with the given \a parent for the \a core interface.*/ +QDesignerPropertyEditorInterface *QDesignerComponents::createPropertyEditor(QDesignerFormEditorInterface *core, QWidget *parent) +{ + return new qdesigner_internal::PropertyEditor(core, parent); +} + +/*! + Returns a new object inspector interface with the given \a parent for the \a core interface.*/ +QDesignerObjectInspectorInterface *QDesignerComponents::createObjectInspector(QDesignerFormEditorInterface *core, QWidget *parent) +{ + return new qdesigner_internal::ObjectInspector(core, parent); +} + +/*! + Returns a new action editor interface with the given \a parent for the \a core interface.*/ +QDesignerActionEditorInterface *QDesignerComponents::createActionEditor(QDesignerFormEditorInterface *core, QWidget *parent) +{ + return new qdesigner_internal::ActionEditor(core, parent); +} + +/*! + Returns a new resource editor with the given \a parent for the \a core interface.*/ +QWidget *QDesignerComponents::createResourceEditor(QDesignerFormEditorInterface *core, QWidget *parent) +{ + if (QDesignerLanguageExtension *lang = qt_extension(core->extensionManager(), core)) { + QWidget *w = lang->createResourceBrowser(parent); + if (w) + return w; + } + QtResourceView *resourceView = new QtResourceView(core, parent); + resourceView->setResourceModel(core->resourceModel()); + resourceView->setSettingsKey(QLatin1String("ResourceBrowser")); + qdesigner_internal::QDesignerIntegration *designerIntegration = qobject_cast(core->integration()); + // Note for integrators: make sure you call createResourceEditor() after you instantiated your subclass of designer integration + // (designer doesn't do that since by default editing resources is enabled) + if (designerIntegration) + resourceView->setResourceEditingEnabled(designerIntegration->isResourceEditingEnabled()); + return resourceView; +} + +/*! + Returns a new signal-slot editor with the given \a parent for the \a core interface.*/ +QWidget *QDesignerComponents::createSignalSlotEditor(QDesignerFormEditorInterface *core, QWidget *parent) +{ + return new qdesigner_internal::SignalSlotEditorWindow(core, parent); +} + +QT_END_NAMESPACE + diff --git a/src/designer/src/components/objectinspector/objectinspector.cpp b/src/designer/src/components/objectinspector/objectinspector.cpp new file mode 100644 index 000000000..8bcd49e15 --- /dev/null +++ b/src/designer/src/components/objectinspector/objectinspector.cpp @@ -0,0 +1,835 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "objectinspector.h" +#include "objectinspectormodel_p.h" +#include "formwindow.h" + +// sdk +#include +#include +#include +#include +#include +#include +#include +#include + +// shared +#include +#include +#include +#include +#include +#include +#include + +// Qt +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace { + // Selections: Basically, ObjectInspector has to ensure a consistent + // selection, that is, either form-managed widgets (represented + // by the cursor interface selection), or unmanaged widgets/objects, + // for example actions, container pages, menu bars, tool bars + // and the like. The selection state of the latter is managed only in the object inspector. + // As soon as a managed widget is selected, unmanaged objects + // have to be unselected + // Normally, an empty selection is not allowed, the main container + // should be selected in this case (applyCursorSelection()). + // An exception is when clearSelection is called directly for example + // by the action editor that puts an unassociated action into the property + // editor. A hack exists to avoid the update in this case. + + enum SelectionType { + NoSelection, + // A QObject that has a meta database entry + QObjectSelection, + // Unmanaged widget, menu bar or the like + UnmanagedWidgetSelection, + // A widget managed by the form window cursor + ManagedWidgetSelection }; + + typedef QVector QObjectVector; +} + +static inline SelectionType selectionType(const QDesignerFormWindowInterface *fw, QObject *o) +{ + if (!o->isWidgetType()) + return fw->core()->metaDataBase()->item(o) ? QObjectSelection : NoSelection; + return fw->isManaged(qobject_cast(o)) ? ManagedWidgetSelection : UnmanagedWidgetSelection; +} + +// Return an offset for dropping (when dropping widgets on the object +// inspector, we fake a position on the form based on the widget dropped on). +// Position the dropped widget with form grid offset to avoid overlapping unless we +// drop on a layout. Position doesn't matter in the layout case +// and this enables us to drop on a squeezed layout widget of size zero + +static inline QPoint dropPointOffset(const qdesigner_internal::FormWindowBase *fw, const QWidget *dropTarget) +{ + if (!dropTarget || dropTarget->layout()) + return QPoint(0, 0); + return QPoint(fw->designerGrid().deltaX(), fw->designerGrid().deltaY()); +} + +namespace qdesigner_internal { +// Delegate with object name validator for the object name column +class ObjectInspectorDelegate : public QItemDelegate { +public: + explicit ObjectInspectorDelegate(QObject *parent = 0); + + virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const; +}; + +ObjectInspectorDelegate::ObjectInspectorDelegate(QObject *parent) : + QItemDelegate(parent) +{ +} + +QWidget *ObjectInspectorDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex &index) const +{ + if (index.column() != ObjectInspectorModel::ObjectNameColumn) + return QItemDelegate::createEditor(parent, option, index); + // Object name editor + const bool isMainContainer = !index.parent().isValid(); + return new TextPropertyEditor(parent, TextPropertyEditor::EmbeddingTreeView, + isMainContainer ? ValidationObjectNameScope : ValidationObjectName); +} + +// ------------ ObjectInspectorTreeView: +// - Makes the Space key start editing +// - Suppresses a range selection by dragging or Shift-up/down, which does not really work due +// to the need to maintain a consistent selection. + +class ObjectInspectorTreeView : public QTreeView { +public: + ObjectInspectorTreeView(QWidget *parent = 0) : QTreeView(parent) {} + +protected: + virtual void mouseMoveEvent (QMouseEvent * event); + virtual void keyPressEvent(QKeyEvent *event); + +}; + +void ObjectInspectorTreeView::mouseMoveEvent(QMouseEvent *event) +{ + event->ignore(); // suppress a range selection by dragging +} + +void ObjectInspectorTreeView::keyPressEvent(QKeyEvent *event) +{ + bool handled = false; + switch (event->key()) { + case Qt::Key_Up: + case Qt::Key_Down: // suppress shift-up/down range selection + if (event->modifiers() & Qt::ShiftModifier) { + event->ignore(); + handled = true; + } + break; + case Qt::Key_Space: { // Space pressed: Start editing + const QModelIndex index = currentIndex(); + if (index.isValid() && index.column() == 0 && !model()->hasChildren(index) && model()->flags(index) & Qt::ItemIsEditable) { + event->accept(); + handled = true; + edit(index); + } + } + break; + default: + break; + } + if (!handled) + QTreeView::keyPressEvent(event); +} + +// ------------ ObjectInspectorPrivate + +class ObjectInspector::ObjectInspectorPrivate { +public: + ObjectInspectorPrivate(QDesignerFormEditorInterface *core); + ~ObjectInspectorPrivate(); + + QTreeView *treeView() const { return m_treeView; } + ItemViewFindWidget *findWidget() const { return m_findWidget; } + QDesignerFormEditorInterface *core() const { return m_core; } + const QPointer &formWindow() const { return m_formWindow; } + + void clear(); + void setFormWindow(QDesignerFormWindowInterface *fwi); + + QWidget *managedWidgetAt(const QPoint &global_mouse_pos); + + void restoreDropHighlighting(); + void handleDragEnterMoveEvent(const QWidget *objectInspectorWidget, QDragMoveEvent * event, bool isDragEnter); + void dropEvent (QDropEvent * event); + + void clearSelection(); + bool selectObject(QObject *o); + void slotSelectionChanged(const QItemSelection & selected, const QItemSelection &deselected); + void getSelection(Selection &s) const; + + void slotHeaderDoubleClicked(int column) { m_treeView->resizeColumnToContents(column); } + void slotPopupContextMenu(QWidget *parent, const QPoint &pos); + +private: + void setFormWindowBlocked(QDesignerFormWindowInterface *fwi); + void applyCursorSelection(); + void synchronizeSelection(const QItemSelection & selected, const QItemSelection &deselected); + bool checkManagedWidgetSelection(const QModelIndexList &selection); + void showContainersCurrentPage(QWidget *widget); + + enum SelectionFlags { AddToSelection = 1, MakeCurrent = 2}; + void selectIndexRange(const QModelIndexList &indexes, unsigned flags); + + QDesignerFormEditorInterface *m_core; + QTreeView *m_treeView; + ObjectInspectorModel *m_model; + ItemViewFindWidget *m_findWidget; + QPointer m_formWindow; + QPointer m_formFakeDropTarget; + bool m_withinClearSelection; +}; + +ObjectInspector::ObjectInspectorPrivate::ObjectInspectorPrivate(QDesignerFormEditorInterface *core) : + m_core(core), + m_treeView(new ObjectInspectorTreeView), + m_model(new ObjectInspectorModel(m_treeView)), + m_findWidget(new ItemViewFindWidget( + ItemViewFindWidget::NarrowLayout | ItemViewFindWidget::NoWholeWords)), + m_withinClearSelection(false) +{ + m_treeView->setModel(m_model); + m_treeView->setItemDelegate(new ObjectInspectorDelegate); + m_treeView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + m_treeView->header()->setResizeMode(1, QHeaderView::Stretch); + m_treeView->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_treeView->setAlternatingRowColors(true); + m_treeView->setTextElideMode (Qt::ElideMiddle); + + m_treeView->setContextMenuPolicy(Qt::CustomContextMenu); +} + +ObjectInspector::ObjectInspectorPrivate::~ObjectInspectorPrivate() +{ + delete m_treeView->itemDelegate(); +} + +void ObjectInspector::ObjectInspectorPrivate::clearSelection() +{ + m_withinClearSelection = true; + m_treeView->clearSelection(); + m_withinClearSelection = false; +} + +QWidget *ObjectInspector::ObjectInspectorPrivate::managedWidgetAt(const QPoint &global_mouse_pos) +{ + if (!m_formWindow) + return 0; + + const QPoint pos = m_treeView->viewport()->mapFromGlobal(global_mouse_pos); + QObject *o = m_model->objectAt(m_treeView->indexAt(pos)); + + if (!o || !o->isWidgetType()) + return 0; + + QWidget *rc = qobject_cast(o); + if (!m_formWindow->isManaged(rc)) + return 0; + return rc; +} + +void ObjectInspector::ObjectInspectorPrivate::showContainersCurrentPage(QWidget *widget) +{ + if (!widget) + return; + + FormWindow *fw = FormWindow::findFormWindow(widget); + if (!fw) + return; + + QWidget *w = widget->parentWidget(); + bool macroStarted = false; + // Find a multipage container (tab widgets, etc.) in the hierarchy and set the right page. + while (w != 0) { + if (fw->isManaged(w)) { // Rule out unmanaged internal scroll areas, for example, on QToolBoxes. + if (QDesignerContainerExtension *c = qt_extension(m_core->extensionManager(), w)) { + const int count = c->count(); + if (count > 1 && !c->widget(c->currentIndex())->isAncestorOf(widget)) { + for (int i = 0; i < count; i++) + if (c->widget(i)->isAncestorOf(widget)) { + if (macroStarted == false) { + macroStarted = true; + fw->beginCommand(tr("Change Current Page")); + } + ChangeCurrentPageCommand *cmd = new ChangeCurrentPageCommand(fw); + cmd->init(w, i); + fw->commandHistory()->push(cmd); + break; + } + } + } + } + w = w->parentWidget(); + } + if (macroStarted == true) + fw->endCommand(); +} + +void ObjectInspector::ObjectInspectorPrivate::restoreDropHighlighting() +{ + if (m_formFakeDropTarget) { + if (m_formWindow) { + m_formWindow->highlightWidget(m_formFakeDropTarget, QPoint(5, 5), FormWindow::Restore); + } + m_formFakeDropTarget = 0; + } +} + +void ObjectInspector::ObjectInspectorPrivate::handleDragEnterMoveEvent(const QWidget *objectInspectorWidget, QDragMoveEvent * event, bool isDragEnter) +{ + if (!m_formWindow) { + event->ignore(); + return; + } + + const QDesignerMimeData *mimeData = qobject_cast(event->mimeData()); + if (!mimeData) { + event->ignore(); + return; + } + + QWidget *dropTarget = 0; + QPoint fakeDropTargetOffset = QPoint(0, 0); + if (QWidget *managedWidget = managedWidgetAt(objectInspectorWidget->mapToGlobal(event->pos()))) { + fakeDropTargetOffset = dropPointOffset(m_formWindow, managedWidget); + // pretend we drag over the managed widget on the form + const QPoint fakeFormPos = m_formWindow->mapFromGlobal(managedWidget->mapToGlobal(fakeDropTargetOffset)); + const FormWindowBase::WidgetUnderMouseMode wum = mimeData->items().size() == 1 ? FormWindowBase::FindSingleSelectionDropTarget : FormWindowBase::FindMultiSelectionDropTarget; + dropTarget = m_formWindow->widgetUnderMouse(fakeFormPos, wum); + } + + if (m_formFakeDropTarget && dropTarget != m_formFakeDropTarget) + m_formWindow->highlightWidget(m_formFakeDropTarget, fakeDropTargetOffset, FormWindow::Restore); + + m_formFakeDropTarget = dropTarget; + if (m_formFakeDropTarget) + m_formWindow->highlightWidget(m_formFakeDropTarget, fakeDropTargetOffset, FormWindow::Highlight); + + // Do not refuse drag enter even if the area is not droppable + if (isDragEnter || m_formFakeDropTarget) + mimeData->acceptEvent(event); + else + event->ignore(); +} +void ObjectInspector::ObjectInspectorPrivate::dropEvent (QDropEvent * event) +{ + if (!m_formWindow || !m_formFakeDropTarget) { + event->ignore(); + return; + } + + const QDesignerMimeData *mimeData = qobject_cast(event->mimeData()); + if (!mimeData) { + event->ignore(); + return; + } + const QPoint fakeGlobalDropFormPos = m_formFakeDropTarget->mapToGlobal(dropPointOffset(m_formWindow , m_formFakeDropTarget)); + mimeData->moveDecoration(fakeGlobalDropFormPos + mimeData->hotSpot()); + if (!m_formWindow->dropWidgets(mimeData->items(), m_formFakeDropTarget, fakeGlobalDropFormPos)) { + event->ignore(); + return; + } + mimeData->acceptEvent(event); +} + +bool ObjectInspector::ObjectInspectorPrivate::selectObject(QObject *o) +{ + if (!m_core->metaDataBase()->item(o)) + return false; + + typedef QSet ModelIndexSet; + + const QModelIndexList objectIndexes = m_model->indexesOf(o); + if (objectIndexes.empty()) + return false; + + QItemSelectionModel *selectionModel = m_treeView->selectionModel(); + const ModelIndexSet currentSelectedItems = selectionModel->selectedRows(0).toSet(); + + // Change in selection? + if (!currentSelectedItems.empty() && currentSelectedItems == objectIndexes.toSet()) + return true; + + // do select and update + selectIndexRange(objectIndexes, MakeCurrent); + return true; +} + +void ObjectInspector::ObjectInspectorPrivate::selectIndexRange(const QModelIndexList &indexes, unsigned flags) +{ + if (indexes.empty()) + return; + + QItemSelectionModel::SelectionFlags selectFlags = QItemSelectionModel::Select|QItemSelectionModel::Rows; + if (!(flags & AddToSelection)) + selectFlags |= QItemSelectionModel::Clear; + if (flags & MakeCurrent) + selectFlags |= QItemSelectionModel::Current; + + QItemSelectionModel *selectionModel = m_treeView->selectionModel(); + const QModelIndexList::const_iterator cend = indexes.constEnd(); + for (QModelIndexList::const_iterator it = indexes.constBegin(); it != cend; ++it) + if (it->column() == 0) { + selectionModel->select(*it, selectFlags); + selectFlags &= ~(QItemSelectionModel::Clear|QItemSelectionModel::Current); + } + if (flags & MakeCurrent) + m_treeView->scrollTo(indexes.front(), QAbstractItemView::EnsureVisible); +} + +void ObjectInspector::ObjectInspectorPrivate::clear() +{ + m_formFakeDropTarget = 0; + m_formWindow = 0; +} + +// Form window cursor is in state 'main container only' +static inline bool mainContainerIsCurrent(const QDesignerFormWindowInterface *fw) +{ + const QDesignerFormWindowCursorInterface *cursor = fw->cursor(); + if (cursor->selectedWidgetCount() > 1) + return false; + const QWidget *current = cursor->current(); + return current == fw || current == fw->mainContainer(); +} + +void ObjectInspector::ObjectInspectorPrivate::setFormWindow(QDesignerFormWindowInterface *fwi) +{ + const bool blocked = m_treeView->selectionModel()->blockSignals(true); + { + UpdateBlocker ub(m_treeView); + setFormWindowBlocked(fwi); + } + + m_treeView->update(); + m_treeView->selectionModel()->blockSignals(blocked); +} + +void ObjectInspector::ObjectInspectorPrivate::setFormWindowBlocked(QDesignerFormWindowInterface *fwi) +{ + FormWindowBase *fw = qobject_cast(fwi); + const bool formWindowChanged = m_formWindow != fw; + + m_formWindow = fw; + + const int oldWidth = m_treeView->columnWidth(0); + const int xoffset = m_treeView->horizontalScrollBar()->value(); + const int yoffset = m_treeView->verticalScrollBar()->value(); + + if (formWindowChanged) + m_formFakeDropTarget = 0; + + switch (m_model->update(m_formWindow)) { + case ObjectInspectorModel::NoForm: + clear(); + return; + case ObjectInspectorModel::Rebuilt: // Complete rebuild: Just apply cursor selection + applyCursorSelection(); + m_treeView->expandAll(); + if (formWindowChanged) { + m_treeView->resizeColumnToContents(0); + } else { + m_treeView->setColumnWidth(0, oldWidth); + m_treeView->horizontalScrollBar()->setValue(xoffset); + m_treeView->verticalScrollBar()->setValue(yoffset); + } + break; + case ObjectInspectorModel::Updated: { + // Same structure (property changed or click on the form) + // We maintain a selection of unmanaged objects + // only if the cursor is in state "mainContainer() == current". + // and we have a non-managed selection. + // Else we take over the cursor selection. + bool applySelection = !mainContainerIsCurrent(m_formWindow); + if (!applySelection) { + const QModelIndexList currentIndexes = m_treeView->selectionModel()->selectedRows(0); + if (currentIndexes.empty()) { + applySelection = true; + } else { + applySelection = selectionType(m_formWindow, m_model->objectAt(currentIndexes.front())) == ManagedWidgetSelection; + } + } + if (applySelection) + applyCursorSelection(); + } + break; + } +} + +// Apply selection of form window cursor to object inspector, set current +void ObjectInspector::ObjectInspectorPrivate::applyCursorSelection() +{ + const QDesignerFormWindowCursorInterface *cursor = m_formWindow->cursor(); + const int count = cursor->selectedWidgetCount(); + if (!count) + return; + + // Set the current widget first which also clears the selection + QWidget *currentWidget = cursor->current(); + if (currentWidget) + selectIndexRange(m_model->indexesOf(currentWidget), MakeCurrent); + else + m_treeView->selectionModel()->clearSelection(); + + for (int i = 0;i < count; i++) { + QWidget *widget = cursor->selectedWidget(i); + if (widget != currentWidget) + selectIndexRange(m_model->indexesOf(widget), AddToSelection); + } +} + +// Synchronize managed widget in the form (select in cursor). Block updates +static int selectInCursor(FormWindowBase *fw, const QObjectVector &objects, bool value) +{ + int rc = 0; + const bool blocked = fw->blockSelectionChanged(true); + const QObjectVector::const_iterator ocend = objects.constEnd(); + for (QObjectVector::const_iterator it = objects.constBegin(); it != ocend; ++it) + if (selectionType(fw, *it) == ManagedWidgetSelection) { + fw->selectWidget(static_cast(*it), value); + rc++; + } + fw->blockSelectionChanged(blocked); + return rc; +} + +void ObjectInspector::ObjectInspectorPrivate::slotSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected) +{ + if (m_formWindow) { + synchronizeSelection(selected, deselected); + QMetaObject::invokeMethod(m_core->formWindowManager(), "slotUpdateActions"); + } +} + +// Convert indexes to object vectors taking into account that +// some index lists are multicolumn ranges +static inline QObjectVector indexesToObjects(const ObjectInspectorModel *model, const QModelIndexList &indexes) +{ + if (indexes.empty()) + return QObjectVector(); + QObjectVector rc; + rc.reserve(indexes.size()); + const QModelIndexList::const_iterator icend = indexes.constEnd(); + for (QModelIndexList::const_iterator it = indexes.constBegin(); it != icend; ++it) + if (it->column() == 0) + rc.push_back(model->objectAt(*it)); + return rc; +} + +// Check if any managed widgets are selected. If so, iterate over +// selection and deselect all unmanaged objects +bool ObjectInspector::ObjectInspectorPrivate::checkManagedWidgetSelection(const QModelIndexList &rowSelection) +{ + bool isManagedWidgetSelection = false; + QItemSelectionModel *selectionModel = m_treeView->selectionModel(); + const QModelIndexList::const_iterator cscend = rowSelection.constEnd(); + for (QModelIndexList::const_iterator it = rowSelection.constBegin(); it != cscend; ++it) { + QObject *object = m_model->objectAt(*it); + if (selectionType(m_formWindow, object) == ManagedWidgetSelection) { + isManagedWidgetSelection = true; + break; + } + } + + if (!isManagedWidgetSelection) + return false; + // Need to unselect unmanaged ones + const bool blocked = selectionModel->blockSignals(true); + for (QModelIndexList::const_iterator it = rowSelection.constBegin(); it != cscend; ++it) { + QObject *object = m_model->objectAt(*it); + if (selectionType(m_formWindow, object) != ManagedWidgetSelection) + selectionModel->select(*it, QItemSelectionModel::Deselect|QItemSelectionModel::Rows); + } + selectionModel->blockSignals(blocked); + return true; +} + +void ObjectInspector::ObjectInspectorPrivate::synchronizeSelection(const QItemSelection & selectedSelection, const QItemSelection &deselectedSelection) +{ + // Synchronize form window cursor. + const QObjectVector deselected = indexesToObjects(m_model, deselectedSelection.indexes()); + const QObjectVector newlySelected = indexesToObjects(m_model, selectedSelection.indexes()); + + const QModelIndexList currentSelectedIndexes = m_treeView->selectionModel()->selectedRows(0); + + int deselectedManagedWidgetCount = 0; + if (!deselected.empty()) + deselectedManagedWidgetCount = selectInCursor(m_formWindow, deselected, false); + + if (newlySelected.empty()) { // Nothing selected + if (currentSelectedIndexes.empty()) // Do not allow a null-selection, reset to main container + m_formWindow->clearSelection(!m_withinClearSelection); + return; + } + + const int selectManagedWidgetCount = selectInCursor(m_formWindow, newlySelected, true); + // Check consistency: Make sure either managed widgets or unmanaged objects are selected. + // No newly-selected managed widgets: Unless there are ones in the (old) current selection, + // select the unmanaged object + if (selectManagedWidgetCount == 0) { + if (checkManagedWidgetSelection(currentSelectedIndexes)) { + // Managed selection exists, refuse and update if necessary + if (deselectedManagedWidgetCount != 0 || selectManagedWidgetCount != 0) + m_formWindow->emitSelectionChanged(); + return; + } + // And now for the unmanaged selection + m_formWindow->clearSelection(false); + QObject *unmanagedObject = newlySelected.front(); + m_core->propertyEditor()->setObject(unmanagedObject); + m_core->propertyEditor()->setEnabled(true); + // open container page if it is a single widget + if (newlySelected.size() == 1 && unmanagedObject->isWidgetType()) + showContainersCurrentPage(static_cast(unmanagedObject)); + return; + } + // Open container page if it is a single widget + if (newlySelected.size() == 1) { + QObject *object = newlySelected.back(); + if (object->isWidgetType()) + showContainersCurrentPage(static_cast(object)); + } + + // A managed widget was newly selected. Make sure there are no unmanaged objects + // in the whole unless just single selection + if (currentSelectedIndexes.size() > selectManagedWidgetCount) + checkManagedWidgetSelection(currentSelectedIndexes); + // Update form + if (deselectedManagedWidgetCount != 0 || selectManagedWidgetCount != 0) + m_formWindow->emitSelectionChanged(); +} + + +void ObjectInspector::ObjectInspectorPrivate::getSelection(Selection &s) const +{ + s.clear(); + + if (!m_formWindow) + return; + + const QModelIndexList currentSelectedIndexes = m_treeView->selectionModel()->selectedRows(0); + if (currentSelectedIndexes.empty()) + return; + + // sort objects + foreach (const QModelIndex &index, currentSelectedIndexes) + if (QObject *object = m_model->objectAt(index)) + switch (selectionType(m_formWindow, object)) { + case NoSelection: + break; + case QObjectSelection: + // It is actually possible to select an action twice if it is in a menu bar + // and in a tool bar. + if (!s.objects.contains(object)) + s.objects.push_back(object); + break; + case UnmanagedWidgetSelection: + s.unmanaged.push_back(qobject_cast(object)); + break; + case ManagedWidgetSelection: + s.managed.push_back(qobject_cast(object)); + break; + } +} + +// Utility to create a task menu +static inline QMenu *createTaskMenu(QObject *object, QDesignerFormWindowInterface *fw) +{ + // 1) Objects + if (!object->isWidgetType()) + return FormWindowBase::createExtensionTaskMenu(fw, object, false); + // 2) Unmanaged widgets + QWidget *w = static_cast(object); + if (!fw->isManaged(w)) + return FormWindowBase::createExtensionTaskMenu(fw, w, false); + // 3) Mananaged widgets + if (qdesigner_internal::FormWindowBase *fwb = qobject_cast(fw)) + return fwb->initializePopupMenu(w); + return 0; +} + +void ObjectInspector::ObjectInspectorPrivate::slotPopupContextMenu(QWidget * /*parent*/, const QPoint &pos) +{ + if (m_formWindow == 0 || m_formWindow->currentTool() != 0) + return; + + const QModelIndex index = m_treeView->indexAt (pos); + if (QObject *object = m_model->objectAt(m_treeView->indexAt(pos))) + if (QMenu *menu = createTaskMenu(object, m_formWindow)) { + menu->exec(m_treeView->viewport()->mapToGlobal(pos)); + delete menu; + } +} + +// ------------ ObjectInspector +ObjectInspector::ObjectInspector(QDesignerFormEditorInterface *core, QWidget *parent) : + QDesignerObjectInspector(parent), + m_impl(new ObjectInspectorPrivate(core)) +{ + QVBoxLayout *vbox = new QVBoxLayout(this); + vbox->setMargin(0); + + QTreeView *treeView = m_impl->treeView(); + vbox->addWidget(treeView); + + connect(treeView, SIGNAL(customContextMenuRequested(QPoint)), + this, SLOT(slotPopupContextMenu(QPoint))); + + connect(treeView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + this, SLOT(slotSelectionChanged(QItemSelection,QItemSelection))); + + connect(treeView->header(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(slotHeaderDoubleClicked(int))); + setAcceptDrops(true); + + ItemViewFindWidget *findWidget = m_impl->findWidget(); + vbox->addWidget(findWidget); + + findWidget->setItemView(treeView); + QAction *findAction = new QAction( + ItemViewFindWidget::findIconSet(), + tr("&Find in Text..."), + this); + findAction->setShortcut(QKeySequence::Find); + findAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); + addAction(findAction); + connect(findAction, SIGNAL(triggered(bool)), findWidget, SLOT(activate())); +} + +ObjectInspector::~ObjectInspector() +{ + delete m_impl; +} + +QDesignerFormEditorInterface *ObjectInspector::core() const +{ + return m_impl->core(); +} + +void ObjectInspector::slotPopupContextMenu(const QPoint &pos) +{ + m_impl->slotPopupContextMenu(this, pos); +} + +void ObjectInspector::setFormWindow(QDesignerFormWindowInterface *fwi) +{ + m_impl->setFormWindow(fwi); +} + +void ObjectInspector::slotSelectionChanged(const QItemSelection & selected, const QItemSelection &deselected) +{ + m_impl->slotSelectionChanged(selected, deselected); +} + +void ObjectInspector::getSelection(Selection &s) const +{ + m_impl->getSelection(s); +} + +bool ObjectInspector::selectObject(QObject *o) +{ + return m_impl->selectObject(o); +} + +void ObjectInspector::clearSelection() +{ + m_impl->clearSelection(); +} + +void ObjectInspector::slotHeaderDoubleClicked(int column) +{ + m_impl->slotHeaderDoubleClicked(column); +} + +void ObjectInspector::mainContainerChanged() +{ + // Invalidate references to objects kept in items + if (sender() == m_impl->formWindow()) + setFormWindow(0); +} + +void ObjectInspector::dragEnterEvent (QDragEnterEvent * event) +{ + m_impl->handleDragEnterMoveEvent(this, event, true); +} + +void ObjectInspector::dragMoveEvent(QDragMoveEvent * event) +{ + m_impl->handleDragEnterMoveEvent(this, event, false); +} + +void ObjectInspector::dragLeaveEvent(QDragLeaveEvent * /* event*/) +{ + m_impl->restoreDropHighlighting(); +} + +void ObjectInspector::dropEvent (QDropEvent * event) +{ + m_impl->dropEvent(event); + +QT_END_NAMESPACE +} +} diff --git a/src/designer/src/components/objectinspector/objectinspector.h b/src/designer/src/components/objectinspector/objectinspector.h new file mode 100644 index 000000000..ebf4da2ce --- /dev/null +++ b/src/designer/src/components/objectinspector/objectinspector.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef OBJECTINSPECTOR_H +#define OBJECTINSPECTOR_H + +#include "objectinspector_global.h" +#include "qdesigner_objectinspector_p.h" + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; + +class QItemSelection; + +namespace qdesigner_internal { + +class QT_OBJECTINSPECTOR_EXPORT ObjectInspector: public QDesignerObjectInspector +{ + Q_OBJECT +public: + explicit ObjectInspector(QDesignerFormEditorInterface *core, QWidget *parent = 0); + virtual ~ObjectInspector(); + + virtual QDesignerFormEditorInterface *core() const; + + virtual void getSelection(Selection &s) const; + virtual bool selectObject(QObject *o); + virtual void clearSelection(); + + void setFormWindow(QDesignerFormWindowInterface *formWindow); + +public slots: + virtual void mainContainerChanged(); + +private slots: + void slotSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected); + void slotPopupContextMenu(const QPoint &pos); + void slotHeaderDoubleClicked(int column); + +protected: + virtual void dragEnterEvent (QDragEnterEvent * event); + virtual void dragMoveEvent(QDragMoveEvent * event); + virtual void dragLeaveEvent(QDragLeaveEvent * event); + virtual void dropEvent (QDropEvent * event); + +private: + class ObjectInspectorPrivate; + ObjectInspectorPrivate *m_impl; +}; + +} // namespace qdesigner_internal + +#endif // OBJECTINSPECTOR_H + +QT_END_NAMESPACE diff --git a/src/designer/src/components/objectinspector/objectinspector.pri b/src/designer/src/components/objectinspector/objectinspector.pri new file mode 100644 index 000000000..565f78bdc --- /dev/null +++ b/src/designer/src/components/objectinspector/objectinspector.pri @@ -0,0 +1,16 @@ +# --- The Find widget is also linked into the designer_shared library. +# Avoid conflict when linking statically +contains(CONFIG, static) { + INCLUDEPATH *= $$QT_SOURCE_TREE/tools/shared/findwidget +} else { + include(../../../../shared/findwidget/findwidget.pri) +} + +INCLUDEPATH += $$PWD + +HEADERS += $$PWD/objectinspector.h \ + $$PWD/objectinspectormodel_p.h \ + $$PWD/objectinspector_global.h + +SOURCES += $$PWD/objectinspector.cpp \ + $$PWD/objectinspectormodel.cpp diff --git a/src/designer/src/components/objectinspector/objectinspector_global.h b/src/designer/src/components/objectinspector/objectinspector_global.h new file mode 100644 index 000000000..08ddf6e68 --- /dev/null +++ b/src/designer/src/components/objectinspector/objectinspector_global.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef OBJECTINSPECTOR_GLOBAL_H +#define OBJECTINSPECTOR_GLOBAL_H + +#include + +QT_BEGIN_NAMESPACE + +#ifdef Q_OS_WIN +#ifdef QT_OBJECTINSPECTOR_LIBRARY +# define QT_OBJECTINSPECTOR_EXPORT +#else +# define QT_OBJECTINSPECTOR_EXPORT +#endif +#else +#define QT_OBJECTINSPECTOR_EXPORT +#endif + +#endif // OBJECTINSPECTOR_GLOBAL_H + +QT_END_NAMESPACE diff --git a/src/designer/src/components/objectinspector/objectinspectormodel.cpp b/src/designer/src/components/objectinspector/objectinspectormodel.cpp new file mode 100644 index 000000000..20f0ff18f --- /dev/null +++ b/src/designer/src/components/objectinspector/objectinspectormodel.cpp @@ -0,0 +1,516 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "objectinspectormodel_p.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace { + enum { DataRole = 1000 }; +} + +static inline QObject *objectOfItem(const QStandardItem *item) { + return qvariant_cast(item->data(DataRole)); +} + +static bool sortEntry(const QObject *a, const QObject *b) +{ + return a->objectName() < b->objectName(); +} + +static bool sameIcon(const QIcon &i1, const QIcon &i2) +{ + if (i1.isNull() && i2.isNull()) + return true; + if (i1.isNull() != i2.isNull()) + return false; + return i1.serialNumber() == i2.serialNumber(); +} + +static inline bool isNameColumnEditable(const QObject *) +{ + return true; +} + +static qdesigner_internal::ObjectData::StandardItemList createModelRow(const QObject *o) +{ + qdesigner_internal::ObjectData::StandardItemList rc; + const Qt::ItemFlags baseFlags = Qt::ItemIsSelectable|Qt::ItemIsDropEnabled|Qt::ItemIsEnabled; + for (int i = 0; i < qdesigner_internal::ObjectInspectorModel::NumColumns; i++) { + QStandardItem *item = new QStandardItem; + Qt::ItemFlags flags = baseFlags; + if (i == qdesigner_internal::ObjectInspectorModel::ObjectNameColumn && isNameColumnEditable(o)) + flags |= Qt::ItemIsEditable; + item->setFlags(flags); + rc += item; + } + return rc; +} + +static inline bool isQLayoutWidget(const QObject *o) +{ + return o->metaObject() == &QLayoutWidget::staticMetaObject; +} + +namespace qdesigner_internal { + + // context kept while building a model, just there to reduce string allocations + struct ModelRecursionContext { + explicit ModelRecursionContext(QDesignerFormEditorInterface *core, const QString &sepName); + + const QString designerPrefix; + const QString separator; + + QDesignerFormEditorInterface *core; + const QDesignerWidgetDataBaseInterface *db; + const QDesignerMetaDataBaseInterface *mdb; + }; + + ModelRecursionContext::ModelRecursionContext(QDesignerFormEditorInterface *c, const QString &sepName) : + designerPrefix(QLatin1String("QDesigner")), + separator(sepName), + core(c), + db(c->widgetDataBase()), + mdb(c->metaDataBase()) + { + } + + // ------------ ObjectData/ ObjectModel: + // Whenever the selection changes, ObjectInspector::setFormWindow is + // called. To avoid rebuilding the tree every time (loosing expanded state) + // a model is first built from the object tree by recursion. + // As a tree is difficult to represent, a flat list of entries (ObjectData) + // containing object and parent object is used. + // ObjectData has an overloaded operator== that compares the object pointers. + // Structural changes which cause a rebuild can be detected by + // comparing the lists of ObjectData. If it is the same, only the item data (class name [changed by promotion], + // object name and icon) are checked and the existing items are updated. + + ObjectData::ObjectData() : + m_parent(0), + m_object(0), + m_type(Object), + m_managedLayoutType(LayoutInfo::NoLayout) + { + } + + ObjectData::ObjectData(QObject *parent, QObject *object, const ModelRecursionContext &ctx) : + m_parent(parent), + m_object(object), + m_type(Object), + m_className(QLatin1String(object->metaObject()->className())), + m_objectName(object->objectName()), + m_managedLayoutType(LayoutInfo::NoLayout) + { + + // 1) set entry + if (object->isWidgetType()) { + initWidget(static_cast(object), ctx); + } else { + initObject(ctx); + } + if (m_className.startsWith(ctx.designerPrefix)) + m_className.remove(1, ctx.designerPrefix.size() - 1); + } + + void ObjectData::initObject(const ModelRecursionContext &ctx) + { + // Check objects: Action? + if (const QAction *act = qobject_cast(m_object)) { + if (act->isSeparator()) { // separator is reserved + m_objectName = ctx.separator; + m_type = SeparatorAction; + } else { + m_type = Action; + } + m_classIcon = act->icon(); + } else { + m_type = Object; + } + } + + void ObjectData::initWidget(QWidget *w, const ModelRecursionContext &ctx) + { + // Check for extension container, QLayoutwidget, or normal container + bool isContainer = false; + if (const QDesignerWidgetDataBaseItemInterface *widgetItem = ctx.db->item(ctx.db->indexOfObject(w, true))) { + m_classIcon = widgetItem->icon(); + m_className = widgetItem->name(); + isContainer = widgetItem->isContainer(); + } + + // We might encounter temporary states with no layouts when re-layouting. + // Just default to Widget handling for the moment. + if (isQLayoutWidget(w)) { + if (const QLayout *layout = w->layout()) { + m_type = LayoutWidget; + m_managedLayoutType = LayoutInfo::layoutType(ctx.core, layout); + m_className = QLatin1String(layout->metaObject()->className()); + m_objectName = layout->objectName(); + } + return; + } + + if (qt_extension(ctx.core->extensionManager(), w)) { + m_type = ExtensionContainer; + return; + } + if (isContainer) { + m_type = LayoutableContainer; + m_managedLayoutType = LayoutInfo::managedLayoutType(ctx.core, w); + return; + } + m_type = ChildWidget; + } + + bool ObjectData::equals(const ObjectData & me) const + { + return m_parent == me.m_parent && m_object == me.m_object; + } + + unsigned ObjectData::compare(const ObjectData & rhs) const + { + unsigned rc = 0; + if (m_className != rhs.m_className) + rc |= ClassNameChanged; + if (m_objectName != rhs.m_objectName) + rc |= ObjectNameChanged; + if (!sameIcon(m_classIcon, rhs.m_classIcon)) + rc |= ClassIconChanged; + if (m_type != rhs.m_type) + rc |= TypeChanged; + if (m_managedLayoutType != rhs.m_managedLayoutType) + rc |= LayoutTypeChanged; + return rc; + } + + void ObjectData::setItemsDisplayData(const StandardItemList &row, const ObjectInspectorIcons &icons, unsigned mask) const + { + if (mask & ObjectNameChanged) + row[ObjectInspectorModel::ObjectNameColumn]->setText(m_objectName); + if (mask & ClassNameChanged) { + row[ObjectInspectorModel::ClassNameColumn]->setText(m_className); + row[ObjectInspectorModel::ClassNameColumn]->setToolTip(m_className); + } + // Set a layout icon only for containers. Note that QLayoutWidget don't have + // real class icons + if (mask & (ClassIconChanged|TypeChanged|LayoutTypeChanged)) { + switch (m_type) { + case LayoutWidget: + row[ObjectInspectorModel::ObjectNameColumn]->setIcon(icons.layoutIcons[m_managedLayoutType]); + row[ObjectInspectorModel::ClassNameColumn]->setIcon(icons.layoutIcons[m_managedLayoutType]); + break; + case LayoutableContainer: + row[ObjectInspectorModel::ObjectNameColumn]->setIcon(icons.layoutIcons[m_managedLayoutType]); + row[ObjectInspectorModel::ClassNameColumn]->setIcon(m_classIcon); + break; + default: + row[ObjectInspectorModel::ObjectNameColumn]->setIcon(QIcon()); + row[ObjectInspectorModel::ClassNameColumn]->setIcon(m_classIcon); + break; + } + } + } + + void ObjectData::setItems(const StandardItemList &row, const ObjectInspectorIcons &icons) const + { + const QVariant object = QVariant::fromValue(m_object); + row[ObjectInspectorModel::ObjectNameColumn]->setData(object, DataRole); + row[ObjectInspectorModel::ClassNameColumn]->setData(object, DataRole); + setItemsDisplayData(row, icons, ClassNameChanged|ObjectNameChanged|ClassIconChanged|TypeChanged|LayoutTypeChanged); + } + + typedef QList ObjectModel; + + // Recursive routine that creates the model by traversing the form window object tree. + void createModelRecursion(const QDesignerFormWindowInterface *fwi, + QObject *parent, + QObject *object, + ObjectModel &model, + const ModelRecursionContext &ctx) + { + typedef QList ButtonGroupList; + typedef QList ActionList; + + // 1) Create entry + const ObjectData entry(parent, object, ctx); + model.push_back(entry); + + // 2) recurse over widget children via container extension or children list + const QDesignerContainerExtension *containerExtension = 0; + if (entry.type() == ObjectData::ExtensionContainer) { + containerExtension = qt_extension(fwi->core()->extensionManager(), object); + Q_ASSERT(containerExtension); + const int count = containerExtension->count(); + for (int i=0; i < count; ++i) { + QObject *page = containerExtension->widget(i); + Q_ASSERT(page != 0); + createModelRecursion(fwi, object, page, model, ctx); + } + } + + QObjectList children = object->children(); + if (!children.empty()) { + ButtonGroupList buttonGroups; + qSort(children.begin(), children.end(), sortEntry); + const QObjectList::const_iterator cend = children.constEnd(); + for (QObjectList::const_iterator it = children.constBegin(); it != cend; ++it) { + // Managed child widgets unless we had a container extension + if ((*it)->isWidgetType()) { + if (!containerExtension) { + QWidget *widget = qobject_cast(*it); + if (fwi->isManaged(widget)) + createModelRecursion(fwi, object, widget, model, ctx); + } + } else { + if (ctx.mdb->item(*it)) { + if (QButtonGroup *bg = qobject_cast(*it)) + buttonGroups.push_back(bg); + } // Has MetaDataBase entry + } + } + // Add button groups + if (!buttonGroups.empty()) { + const ButtonGroupList::const_iterator bgcend = buttonGroups.constEnd(); + for (ButtonGroupList::const_iterator bgit = buttonGroups.constBegin(); bgit != bgcend; ++bgit) + createModelRecursion(fwi, object, *bgit, model, ctx); + } + } // has children + if (object->isWidgetType()) { + // Add actions + const ActionList actions = static_cast(object)->actions(); + if (!actions.empty()) { + const ActionList::const_iterator cend = actions.constEnd(); + for (ActionList::const_iterator it = actions.constBegin(); it != cend; ++it) + if (ctx.mdb->item(*it)) { + QAction *action = *it; + QObject *obj = action; + if (action->menu()) + obj = action->menu(); + createModelRecursion(fwi, object, obj, model, ctx); + } + } + } + } + + // ------------ ObjectInspectorModel + ObjectInspectorModel::ObjectInspectorModel(QObject *parent) : + QStandardItemModel(0, NumColumns, parent) + { + QStringList headers; + headers += QCoreApplication::translate("ObjectInspectorModel", "Object"); + headers += QCoreApplication::translate("ObjectInspectorModel", "Class"); + Q_ASSERT(headers.size() == NumColumns); + setColumnCount(NumColumns); + setHorizontalHeaderLabels(headers); + // Icons + m_icons.layoutIcons[LayoutInfo::NoLayout] = createIconSet(QLatin1String("editbreaklayout.png")); + m_icons.layoutIcons[LayoutInfo::HSplitter] = createIconSet(QLatin1String("edithlayoutsplit.png")); + m_icons.layoutIcons[LayoutInfo::VSplitter] = createIconSet(QLatin1String("editvlayoutsplit.png")); + m_icons.layoutIcons[LayoutInfo::HBox] = createIconSet(QLatin1String("edithlayout.png")); + m_icons.layoutIcons[LayoutInfo::VBox] = createIconSet(QLatin1String("editvlayout.png")); + m_icons.layoutIcons[LayoutInfo::Grid] = createIconSet(QLatin1String("editgrid.png")); + m_icons.layoutIcons[LayoutInfo::Form] = createIconSet(QLatin1String("editform.png")); + } + + void ObjectInspectorModel::clearItems() + { + m_objectIndexMultiMap.clear(); + m_model.clear(); + reset(); // force editors to be closed in views + removeRow(0); + } + + ObjectInspectorModel::UpdateResult ObjectInspectorModel::update(QDesignerFormWindowInterface *fw) + { + QWidget *mainContainer = fw ? fw->mainContainer() : static_cast(0); + if (!mainContainer) { + clearItems(); + m_formWindow = 0; + return NoForm; + } + m_formWindow = fw; + // Build new model and compare to previous one. If the structure is + // identical, just update, else rebuild + ObjectModel newModel; + + static const QString separator = QCoreApplication::translate("ObjectInspectorModel", "separator"); + const ModelRecursionContext ctx(fw->core(), separator); + createModelRecursion(fw, 0, mainContainer, newModel, ctx); + + if (newModel == m_model) { + updateItemContents(m_model, newModel); + return Updated; + } + + rebuild(newModel); + m_model = newModel; + return Rebuilt; + } + + QObject *ObjectInspectorModel::objectAt(const QModelIndex &index) const + { + if (index.isValid()) + if (const QStandardItem *item = itemFromIndex(index)) + return objectOfItem(item); + return 0; + } + + // Missing Qt API: get a row + ObjectInspectorModel::StandardItemList ObjectInspectorModel::rowAt(QModelIndex index) const + { + StandardItemList rc; + while (true) { + rc += itemFromIndex(index); + const int nextColumn = index.column() + 1; + if (nextColumn >= NumColumns) + break; + index = index.sibling(index.row(), nextColumn); + } + return rc; + } + + // Rebuild the tree in case the model has completely changed. + void ObjectInspectorModel::rebuild(const ObjectModel &newModel) + { + clearItems(); + if (newModel.empty()) + return; + + const ObjectModel::const_iterator mcend = newModel.constEnd(); + ObjectModel::const_iterator it = newModel.constBegin(); + // Set up root element + StandardItemList rootRow = createModelRow(it->object()); + it->setItems(rootRow, m_icons); + appendRow(rootRow); + m_objectIndexMultiMap.insert(it->object(), indexFromItem(rootRow.front())); + for (++it; it != mcend; ++it) { + // Add to parent item, found via map + const QModelIndex parentIndex = m_objectIndexMultiMap.value(it->parent(), QModelIndex()); + Q_ASSERT(parentIndex.isValid()); + QStandardItem *parentItem = itemFromIndex(parentIndex); + StandardItemList row = createModelRow(it->object()); + it->setItems(row, m_icons); + parentItem->appendRow(row); + m_objectIndexMultiMap.insert(it->object(), indexFromItem(row.front())); + } + } + + // Update item data in case the model has the same structure + void ObjectInspectorModel::updateItemContents(ObjectModel &oldModel, const ObjectModel &newModel) + { + // Change text and icon. Keep a set of changed object + // as for example actions might occur several times in the tree. + typedef QSet QObjectSet; + + QObjectSet changedObjects; + + const int size = newModel.size(); + Q_ASSERT(oldModel.size() == size); + for (int i = 0; i < size; i++) { + const ObjectData &newEntry = newModel[i]; + ObjectData &entry = oldModel[i]; + // Has some data changed? + if (const unsigned changedMask = entry.compare(newEntry)) { + entry = newEntry; + QObject * o = entry.object(); + if (!changedObjects.contains(o)) { + changedObjects.insert(o); + const QModelIndexList indexes = m_objectIndexMultiMap.values(o); + foreach (const QModelIndex &index, indexes) + entry.setItemsDisplayData(rowAt(index), m_icons, changedMask); + } + } + } + } + + QVariant ObjectInspectorModel::data(const QModelIndex &index, int role) const + { + const QVariant rc = QStandardItemModel::data(index, role); + // Return if the string is empty for the display role + // only (else, editing starts with ). + if (role == Qt::DisplayRole && rc.type() == QVariant::String) { + const QString s = rc.toString(); + if (s.isEmpty()) { + static const QString noName = QCoreApplication::translate("ObjectInspectorModel", ""); + return QVariant(noName); + } + } + return rc; + } + + bool ObjectInspectorModel::setData(const QModelIndex &index, const QVariant &value, int role) + { + if (role != Qt::EditRole || !m_formWindow) + return false; + + QObject *object = objectAt(index); + if (!object) + return false; + // Is this a layout widget? + const QString nameProperty = isQLayoutWidget(object) ? QLatin1String("layoutName") : QLatin1String("objectName"); + m_formWindow->commandHistory()->push(createTextPropertyCommand(nameProperty, value.toString(), object, m_formWindow)); + return true; + } +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/objectinspector/objectinspectormodel_p.h b/src/designer/src/components/objectinspector/objectinspectormodel_p.h new file mode 100644 index 000000000..499a99afb --- /dev/null +++ b/src/designer/src/components/objectinspector/objectinspectormodel_p.h @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef OBJECTINSPECTORMODEL_H +#define OBJECTINSPECTORMODEL_H + +#include + +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + + // Data structure containing the fixed item type icons + struct ObjectInspectorIcons { + QIcon layoutIcons[LayoutInfo::UnknownLayout + 1]; + }; + + struct ModelRecursionContext; + + // Data structure representing one item of the object inspector. + class ObjectData { + public: + enum Type { + Object, + Action, + SeparatorAction, + ChildWidget, // A child widget + LayoutableContainer, // A container that can be laid out + LayoutWidget, // A QLayoutWidget + ExtensionContainer // QTabWidget and the like, container extension + }; + + typedef QList StandardItemList; + + explicit ObjectData(QObject *parent, QObject *object, const ModelRecursionContext &ctx); + ObjectData(); + + inline Type type() const { return m_type; } + inline QObject *object() const { return m_object; } + inline QObject *parent() const { return m_parent; } + inline QString objectName() const { return m_objectName; } + + bool equals(const ObjectData & me) const; + + enum ChangedMask { ClassNameChanged = 1, ObjectNameChanged = 2, + ClassIconChanged = 4, TypeChanged = 8, + LayoutTypeChanged = 16}; + + unsigned compare(const ObjectData & me) const; + + // Initially set up a row + void setItems(const StandardItemList &row, const ObjectInspectorIcons &icons) const; + // Update row data according to change mask + void setItemsDisplayData(const StandardItemList &row, const ObjectInspectorIcons &icons, unsigned mask) const; + + private: + void initObject(const ModelRecursionContext &ctx); + void initWidget(QWidget *w, const ModelRecursionContext &ctx); + + QObject *m_parent; + QObject *m_object; + Type m_type; + QString m_className; + QString m_objectName; + QIcon m_classIcon; + LayoutInfo::Type m_managedLayoutType; + }; + + inline bool operator==(const ObjectData &e1, const ObjectData &e2) { return e1.equals(e2); } + inline bool operator!=(const ObjectData &e1, const ObjectData &e2) { return !e1.equals(e2); } + + typedef QList ObjectModel; + + // QStandardItemModel for ObjectInspector. Uses ObjectData/ObjectModel + // internally for its updates. + class ObjectInspectorModel : public QStandardItemModel { + public: + typedef QList StandardItemList; + enum { ObjectNameColumn, ClassNameColumn, NumColumns }; + + explicit ObjectInspectorModel(QObject *parent); + + enum UpdateResult { NoForm, Rebuilt, Updated }; + UpdateResult update(QDesignerFormWindowInterface *fw); + + const QModelIndexList indexesOf(QObject *o) const { return m_objectIndexMultiMap.values(o); } + QObject *objectAt(const QModelIndex &index) const; + + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + private: + typedef QMultiMap ObjectIndexMultiMap; + + void rebuild(const ObjectModel &newModel); + void updateItemContents(ObjectModel &oldModel, const ObjectModel &newModel); + void clearItems(); + StandardItemList rowAt(QModelIndex index) const; + + ObjectInspectorIcons m_icons; + ObjectIndexMultiMap m_objectIndexMultiMap; + ObjectModel m_model; + QPointer m_formWindow; + }; +} // namespace qdesigner_internal + +#endif // OBJECTINSPECTORMODEL_H + +QT_END_NAMESPACE diff --git a/src/designer/src/components/propertyeditor/brushpropertymanager.cpp b/src/designer/src/components/propertyeditor/brushpropertymanager.cpp new file mode 100644 index 000000000..973de63bb --- /dev/null +++ b/src/designer/src/components/propertyeditor/brushpropertymanager.cpp @@ -0,0 +1,298 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "brushpropertymanager.h" +#include "qtpropertymanager.h" +#include "qtvariantproperty.h" +#include "qtpropertybrowserutils_p.h" + +#include +#include +#include + +static const char *brushStyles[] = { +QT_TRANSLATE_NOOP("BrushPropertyManager", "No brush"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Solid"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Dense 1"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Dense 2"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Dense 3"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Dense 4"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Dense 5"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Dense 6"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Dense 7"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Horizontal"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Vertical"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Cross"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Backward diagonal"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Forward diagonal"), +QT_TRANSLATE_NOOP("BrushPropertyManager", "Crossing diagonal"), +}; + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +BrushPropertyManager::BrushPropertyManager() +{ +} + +int BrushPropertyManager::brushStyleToIndex(Qt::BrushStyle st) +{ + switch (st) { + case Qt::NoBrush: return 0; + case Qt::SolidPattern: return 1; + case Qt::Dense1Pattern: return 2; + case Qt::Dense2Pattern: return 3; + case Qt::Dense3Pattern: return 4; + case Qt::Dense4Pattern: return 5; + case Qt::Dense5Pattern: return 6; + case Qt::Dense6Pattern: return 7; + case Qt::Dense7Pattern: return 8; + case Qt::HorPattern: return 9; + case Qt::VerPattern: return 10; + case Qt::CrossPattern: return 11; + case Qt::BDiagPattern: return 12; + case Qt::FDiagPattern: return 13; + case Qt::DiagCrossPattern: return 14; + default: break; + } + return 0; +} + +Qt::BrushStyle BrushPropertyManager::brushStyleIndexToStyle(int brushStyleIndex) +{ + switch (brushStyleIndex) { + case 0: return Qt::NoBrush; + case 1: return Qt::SolidPattern; + case 2: return Qt::Dense1Pattern; + case 3: return Qt::Dense2Pattern; + case 4: return Qt::Dense3Pattern; + case 5: return Qt::Dense4Pattern; + case 6: return Qt::Dense5Pattern; + case 7: return Qt::Dense6Pattern; + case 8: return Qt::Dense7Pattern; + case 9: return Qt::HorPattern; + case 10: return Qt::VerPattern; + case 11: return Qt::CrossPattern; + case 12: return Qt::BDiagPattern; + case 13: return Qt::FDiagPattern; + case 14: return Qt::DiagCrossPattern; + } + return Qt::NoBrush; +} + + +typedef QMap EnumIndexIconMap; + +static void clearBrushIcons(); +Q_GLOBAL_STATIC_WITH_INITIALIZER(EnumIndexIconMap, brushIcons, qAddPostRoutine(clearBrushIcons)) + +static void clearBrushIcons() +{ + brushIcons()->clear(); +} + +const BrushPropertyManager::EnumIndexIconMap &BrushPropertyManager::brushStyleIcons() +{ + // Create a map of icons for the brush style editor + if (brushIcons()->empty()) { + const int brushStyleCount = sizeof(brushStyles)/sizeof(const char *); + QBrush brush(Qt::black); + const QIcon solidIcon = QtPropertyBrowserUtils::brushValueIcon(brush); + for (int i = 0; i < brushStyleCount; i++) { + const Qt::BrushStyle style = brushStyleIndexToStyle(i); + brush.setStyle(style); + brushIcons()->insert(i, QtPropertyBrowserUtils::brushValueIcon(brush)); + } + } + return *(brushIcons()); +} + +QString BrushPropertyManager::brushStyleIndexToString(int brushStyleIndex) +{ + const int brushStyleCount = sizeof(brushStyles)/sizeof(const char *); + return brushStyleIndex < brushStyleCount ? QCoreApplication::translate("BrushPropertyManager", brushStyles[brushStyleIndex]) : QString(); +} + +void BrushPropertyManager::initializeProperty(QtVariantPropertyManager *vm, QtProperty *property, int enumTypeId) +{ + m_brushValues.insert(property, QBrush()); + // style + QtVariantProperty *styleSubProperty = vm->addProperty(enumTypeId, QCoreApplication::translate("BrushPropertyManager", "Style")); + property->addSubProperty(styleSubProperty); + QStringList styles; + const int brushStyleCount = sizeof(brushStyles)/sizeof(const char *); + for (int i = 0; i < brushStyleCount; i++) + styles.push_back(QCoreApplication::translate("BrushPropertyManager", brushStyles[i])); + styleSubProperty->setAttribute(QLatin1String("enumNames"), styles); + styleSubProperty->setAttribute(QLatin1String("enumIcons"), QVariant::fromValue(brushStyleIcons())); + m_brushPropertyToStyleSubProperty.insert(property, styleSubProperty); + m_brushStyleSubPropertyToProperty.insert(styleSubProperty, property); + // color + QtVariantProperty *colorSubProperty = vm->addProperty(QVariant::Color, QCoreApplication::translate("BrushPropertyManager", "Color")); + property->addSubProperty(colorSubProperty); + m_brushPropertyToColorSubProperty.insert(property, colorSubProperty); + m_brushColorSubPropertyToProperty.insert(colorSubProperty, property); +} + +bool BrushPropertyManager::uninitializeProperty(QtProperty *property) +{ + const PropertyBrushMap::iterator brit = m_brushValues.find(property); // Brushes + if (brit == m_brushValues.end()) + return false; + m_brushValues.erase(brit); + // style + PropertyToPropertyMap::iterator subit = m_brushPropertyToStyleSubProperty.find(property); + if (subit != m_brushPropertyToStyleSubProperty.end()) { + QtProperty *styleProp = subit.value(); + m_brushStyleSubPropertyToProperty.remove(styleProp); + m_brushPropertyToStyleSubProperty.erase(subit); + delete styleProp; + } + // color + subit = m_brushPropertyToColorSubProperty.find(property); + if (subit != m_brushPropertyToColorSubProperty.end()) { + QtProperty *colorProp = subit.value(); + m_brushColorSubPropertyToProperty.remove(colorProp); + m_brushPropertyToColorSubProperty.erase(subit); + delete colorProp; + } + return true; +} + +void BrushPropertyManager::slotPropertyDestroyed(QtProperty *property) +{ + PropertyToPropertyMap::iterator subit = m_brushStyleSubPropertyToProperty.find(property); + if (subit != m_brushStyleSubPropertyToProperty.end()) { + m_brushPropertyToStyleSubProperty[subit.value()] = 0; + m_brushStyleSubPropertyToProperty.erase(subit); + } + subit = m_brushColorSubPropertyToProperty.find(property); + if (subit != m_brushColorSubPropertyToProperty.end()) { + m_brushPropertyToColorSubProperty[subit.value()] = 0; + m_brushColorSubPropertyToProperty.erase(subit); + } +} + + +BrushPropertyManager::ValueChangedResult BrushPropertyManager::valueChanged(QtVariantPropertyManager *vm, QtProperty *property, const QVariant &value) +{ + switch (value.type()) { + case QVariant::Int: // Style subproperty? + if (QtProperty *brushProperty = m_brushStyleSubPropertyToProperty.value(property, 0)) { + const QBrush oldValue = m_brushValues.value(brushProperty); + QBrush newBrush = oldValue; + const int index = value.toInt(); + newBrush.setStyle(brushStyleIndexToStyle(index)); + if (newBrush == oldValue) + return Unchanged; + vm->variantProperty(brushProperty)->setValue(newBrush); + return Changed; + } + break; + case QVariant::Color: // Color subproperty? + if (QtProperty *brushProperty = m_brushColorSubPropertyToProperty.value(property, 0)) { + const QBrush oldValue = m_brushValues.value(brushProperty); + QBrush newBrush = oldValue; + newBrush.setColor(qvariant_cast(value)); + if (newBrush == oldValue) + return Unchanged; + vm->variantProperty(brushProperty)->setValue(newBrush); + return Changed; + } + break; + default: + break; + } + return NoMatch; +} + +BrushPropertyManager::ValueChangedResult BrushPropertyManager::setValue(QtVariantPropertyManager *vm, QtProperty *property, const QVariant &value) +{ + if (value.type() != QVariant::Brush) + return NoMatch; + const PropertyBrushMap::iterator brit = m_brushValues.find(property); + if (brit == m_brushValues.end()) + return NoMatch; + + const QBrush newBrush = qvariant_cast(value); + if (newBrush == brit.value()) + return Unchanged; + brit.value() = newBrush; + if (QtProperty *styleProperty = m_brushPropertyToStyleSubProperty.value(property)) + vm->variantProperty(styleProperty)->setValue(brushStyleToIndex(newBrush.style())); + if (QtProperty *colorProperty = m_brushPropertyToColorSubProperty.value(property)) + vm->variantProperty(colorProperty)->setValue(newBrush.color()); + + return Changed; +} + +bool BrushPropertyManager::valueText(const QtProperty *property, QString *text) const +{ + const PropertyBrushMap::const_iterator brit = m_brushValues.constFind(const_cast(property)); + if (brit == m_brushValues.constEnd()) + return false; + const QBrush &brush = brit.value(); + const QString styleName = brushStyleIndexToString(brushStyleToIndex(brush.style())); + *text = QCoreApplication::translate("BrushPropertyManager", "[%1, %2]").arg(styleName).arg(QtPropertyBrowserUtils::colorValueText(brush.color())); + return true; +} + +bool BrushPropertyManager::valueIcon(const QtProperty *property, QIcon *icon) const +{ + const PropertyBrushMap::const_iterator brit = m_brushValues.constFind(const_cast(property)); + if (brit == m_brushValues.constEnd()) + return false; + *icon = QtPropertyBrowserUtils::brushValueIcon(brit.value()); + return true; +} + +bool BrushPropertyManager::value(const QtProperty *property, QVariant *v) const +{ + const PropertyBrushMap::const_iterator brit = m_brushValues.constFind(const_cast(property)); + if (brit == m_brushValues.constEnd()) + return false; + qVariantSetValue(*v, brit.value()); + return true; +} +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/propertyeditor/brushpropertymanager.h b/src/designer/src/components/propertyeditor/brushpropertymanager.h new file mode 100644 index 000000000..5c008e2c4 --- /dev/null +++ b/src/designer/src/components/propertyeditor/brushpropertymanager.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BRUSHPROPERTYMANAGER_H +#define BRUSHPROPERTYMANAGER_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QtProperty; +class QtVariantPropertyManager; + +class QString; +class QVariant; + +namespace qdesigner_internal { + +// BrushPropertyManager: A mixin for DesignerPropertyManager that manages brush properties. + +class BrushPropertyManager { + BrushPropertyManager(const BrushPropertyManager&); + BrushPropertyManager &operator=(const BrushPropertyManager&); + +public: + BrushPropertyManager(); + + void initializeProperty(QtVariantPropertyManager *vm, QtProperty *property, int enumTypeId); + bool uninitializeProperty(QtProperty *property); + + // Call from slotValueChanged(). + enum ValueChangedResult { NoMatch, Unchanged, Changed }; + ValueChangedResult valueChanged(QtVariantPropertyManager *vm, QtProperty *property, const QVariant &value); + ValueChangedResult setValue(QtVariantPropertyManager *vm, QtProperty *property, const QVariant &value); + + bool valueText(const QtProperty *property, QString *text) const; + bool valueIcon(const QtProperty *property, QIcon *icon) const; + bool value(const QtProperty *property, QVariant *v) const; + + // Call from QtPropertyManager's propertyDestroyed signal + void slotPropertyDestroyed(QtProperty *property); + +private: + static int brushStyleToIndex(Qt::BrushStyle st); + static Qt::BrushStyle brushStyleIndexToStyle(int brushStyleIndex); + static QString brushStyleIndexToString(int brushStyleIndex); + + typedef QMap EnumIndexIconMap; + static const EnumIndexIconMap &brushStyleIcons(); + + typedef QMap PropertyToPropertyMap; + PropertyToPropertyMap m_brushPropertyToStyleSubProperty; + PropertyToPropertyMap m_brushPropertyToColorSubProperty; + PropertyToPropertyMap m_brushStyleSubPropertyToProperty; + PropertyToPropertyMap m_brushColorSubPropertyToProperty; + + typedef QMap PropertyBrushMap; + PropertyBrushMap m_brushValues; +}; + +} + +QT_END_NAMESPACE + +#endif // BRUSHPROPERTYMANAGER_H diff --git a/src/designer/src/components/propertyeditor/designerpropertymanager.cpp b/src/designer/src/components/propertyeditor/designerpropertymanager.cpp new file mode 100644 index 000000000..78fb9aaf0 --- /dev/null +++ b/src/designer/src/components/propertyeditor/designerpropertymanager.cpp @@ -0,0 +1,2836 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "designerpropertymanager.h" +#include "qtpropertymanager.h" +#include "paletteeditorbutton.h" +#include "qlonglongvalidator.h" +#include "stringlisteditorbutton.h" +#include "qtresourceview_p.h" +#include "qtpropertybrowserutils_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +static const char *resettableAttributeC = "resettable"; +static const char *flagsAttributeC = "flags"; +static const char *validationModesAttributeC = "validationMode"; +static const char *superPaletteAttributeC = "superPalette"; +static const char *defaultResourceAttributeC = "defaultResource"; +static const char *fontAttributeC = "font"; +static const char *themeAttributeC = "theme"; + +class DesignerFlagPropertyType +{ +}; + + +class DesignerAlignmentPropertyType +{ +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(DesignerFlagPropertyType) +Q_DECLARE_METATYPE(DesignerAlignmentPropertyType) + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// ------------ TextEditor +class TextEditor : public QWidget +{ + Q_OBJECT +public: + TextEditor(QDesignerFormEditorInterface *core, QWidget *parent); + + TextPropertyValidationMode textPropertyValidationMode() const; + void setTextPropertyValidationMode(TextPropertyValidationMode vm); + + void setRichTextDefaultFont(const QFont &font) { m_richTextDefaultFont = font; } + QFont richTextDefaultFont() const { return m_richTextDefaultFont; } + + void setSpacing(int spacing); + + TextPropertyEditor::UpdateMode updateMode() const { return m_editor->updateMode(); } + void setUpdateMode(TextPropertyEditor::UpdateMode um) { m_editor->setUpdateMode(um); } + + void setIconThemeModeEnabled(bool enable); + +public slots: + void setText(const QString &text); + +signals: + void textChanged(const QString &text); + +private slots: + void buttonClicked(); + void resourceActionActivated(); + void fileActionActivated(); +private: + TextPropertyEditor *m_editor; + IconThemeEditor *m_themeEditor; + bool m_iconThemeModeEnabled; + QFont m_richTextDefaultFont; + QToolButton *m_button; + QMenu *m_menu; + QAction *m_resourceAction; + QAction *m_fileAction; + QHBoxLayout *m_layout; + QDesignerFormEditorInterface *m_core; +}; + +TextEditor::TextEditor(QDesignerFormEditorInterface *core, QWidget *parent) : + QWidget(parent), + m_editor(new TextPropertyEditor(this)), + m_themeEditor(new IconThemeEditor(this, false)), + m_iconThemeModeEnabled(false), + m_richTextDefaultFont(QApplication::font()), + m_button(new QToolButton(this)), + m_menu(new QMenu(this)), + m_resourceAction(new QAction(tr("Choose Resource..."), this)), + m_fileAction(new QAction(tr("Choose File..."), this)), + m_layout(new QHBoxLayout(this)), + m_core(core) +{ + m_themeEditor->setVisible(false); + m_button->setVisible(false); + + m_layout->addWidget(m_editor); + m_layout->addWidget(m_themeEditor); + m_button->setText(tr("...")); + m_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored); + m_button->setFixedWidth(20); + m_layout->addWidget(m_button); + m_layout->setMargin(0); + m_layout->setSpacing(0); + + connect(m_resourceAction, SIGNAL(triggered()), this, SLOT(resourceActionActivated())); + connect(m_fileAction, SIGNAL(triggered()), this, SLOT(fileActionActivated())); + connect(m_editor, SIGNAL(textChanged(QString)), this, SIGNAL(textChanged(QString))); + connect(m_themeEditor, SIGNAL(edited(QString)), this, SIGNAL(textChanged(QString))); + connect(m_button, SIGNAL(clicked()), this, SLOT(buttonClicked())); + + setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); + setFocusProxy(m_editor); + + m_menu->addAction(m_resourceAction); + m_menu->addAction(m_fileAction); +} + +void TextEditor::setSpacing(int spacing) +{ + m_layout->setSpacing(spacing); +} + +void TextEditor::setIconThemeModeEnabled(bool enable) +{ + if (m_iconThemeModeEnabled == enable) + return; // nothing changes + m_iconThemeModeEnabled = enable; + m_editor->setVisible(!enable); + m_themeEditor->setVisible(enable); + if (enable) { + m_themeEditor->setTheme(m_editor->text()); + setFocusProxy(m_themeEditor); + } else { + m_editor->setText(m_themeEditor->theme()); + setFocusProxy(m_editor); + } +} + +TextPropertyValidationMode TextEditor::textPropertyValidationMode() const +{ + return m_editor->textPropertyValidationMode(); +} + +void TextEditor::setTextPropertyValidationMode(TextPropertyValidationMode vm) +{ + m_editor->setTextPropertyValidationMode(vm); + if (vm == ValidationURL) { + m_button->setMenu(m_menu); + m_button->setFixedWidth(30); + m_button->setPopupMode(QToolButton::MenuButtonPopup); + } else { + m_button->setMenu(0); + m_button->setFixedWidth(20); + m_button->setPopupMode(QToolButton::DelayedPopup); + } + m_button->setVisible(vm == ValidationStyleSheet || vm == ValidationRichText || vm == ValidationMultiLine || vm == ValidationURL); +} + +void TextEditor::setText(const QString &text) +{ + if (m_iconThemeModeEnabled) + m_themeEditor->setTheme(text); + else + m_editor->setText(text); +} + +void TextEditor::buttonClicked() +{ + const QString oldText = m_editor->text(); + QString newText; + switch (textPropertyValidationMode()) { + case ValidationStyleSheet: { + StyleSheetEditorDialog dlg(m_core, this); + dlg.setText(oldText); + if (dlg.exec() != QDialog::Accepted) + return; + newText = dlg.text(); + } + break; + case ValidationRichText: { + RichTextEditorDialog dlg(m_core, this); + dlg.setDefaultFont(m_richTextDefaultFont); + dlg.setText(oldText); + if (dlg.showDialog() != QDialog::Accepted) + return; + newText = dlg.text(Qt::AutoText); + } + break; + case ValidationMultiLine: { + PlainTextEditorDialog dlg(m_core, this); + dlg.setDefaultFont(m_richTextDefaultFont); + dlg.setText(oldText); + if (dlg.showDialog() != QDialog::Accepted) + return; + newText = dlg.text(); + } + break; + case ValidationURL: { + QString oldPath = oldText; + if (oldPath.isEmpty() || oldPath.startsWith(QLatin1String("qrc:"))) + resourceActionActivated(); + else + fileActionActivated(); + } + return; + default: + return; + } + if (newText != oldText) { + m_editor->setText(newText); + emit textChanged(newText); + } +} + +void TextEditor::resourceActionActivated() +{ + QString oldPath = m_editor->text(); + if (oldPath.startsWith(QLatin1String("qrc:"))) + oldPath.remove(0, 4); + // returns ':/file' + QString newPath = IconSelector::choosePixmapResource(m_core, m_core->resourceModel(), oldPath, this); + if (newPath.startsWith(QLatin1Char(':'))) + newPath.remove(0, 1); + if (newPath.isEmpty() || newPath == oldPath) + return; + const QString newText = QLatin1String("qrc:") + newPath; + m_editor->setText(newText); + emit textChanged(newText); +} + +void TextEditor::fileActionActivated() +{ + QString oldPath = m_editor->text(); + if (oldPath.startsWith(QLatin1String("file:"))) + oldPath = oldPath.mid(5); + const QString newPath = m_core->dialogGui()->getOpenFileName(this, tr("Choose a File"), oldPath); + if (newPath.isEmpty() || newPath == oldPath) + return; + const QString newText = QUrl::fromLocalFile(newPath).toString(); + m_editor->setText(newText); + emit textChanged(newText); +} + +// ------------ ThemeInputDialog + +class IconThemeDialog : public QDialog +{ + Q_OBJECT +public: + static QString getTheme(QWidget *parent, const QString &theme, bool *ok); +private: + IconThemeDialog(QWidget *parent); + IconThemeEditor *m_editor; +}; + +IconThemeDialog::IconThemeDialog(QWidget *parent) + : QDialog(parent) +{ + setWindowTitle(tr("Set Icon From Theme")); + + QVBoxLayout *layout = new QVBoxLayout(this); + QLabel *label = new QLabel(tr("Input icon name from the current theme:"), this); + m_editor = new IconThemeEditor(this); + QDialogButtonBox *buttons = new QDialogButtonBox(this); + buttons->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + + layout->addWidget(label); + layout->addWidget(m_editor); + layout->addWidget(buttons); + + connect(buttons, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttons, SIGNAL(rejected()), this, SLOT(reject())); +} + +QString IconThemeDialog::getTheme(QWidget *parent, const QString &theme, bool *ok) +{ + IconThemeDialog dlg(parent); + dlg.m_editor->setTheme(theme); + if (dlg.exec() == QDialog::Accepted) { + *ok = true; + return dlg.m_editor->theme(); + } + *ok = false; + return QString(); +} + +// ------------ PixmapEditor +class PixmapEditor : public QWidget +{ + Q_OBJECT +public: + PixmapEditor(QDesignerFormEditorInterface *core, QWidget *parent); + + void setSpacing(int spacing); + void setPixmapCache(DesignerPixmapCache *cache); + void setIconThemeModeEnabled(bool enabled); +public slots: + void setPath(const QString &path); + void setTheme(const QString &theme); + void setDefaultPixmap(const QPixmap &pixmap); + +signals: + void pathChanged(const QString &path); + void themeChanged(const QString &theme); + +protected: + void contextMenuEvent(QContextMenuEvent *event); + +private slots: + void defaultActionActivated(); + void resourceActionActivated(); + void fileActionActivated(); + void themeActionActivated(); + void copyActionActivated(); + void pasteActionActivated(); + void clipboardDataChanged(); +private: + void updateLabels(); + bool m_iconThemeModeEnabled; + QDesignerFormEditorInterface *m_core; + QLabel *m_pixmapLabel; + QLabel *m_pathLabel; + QToolButton *m_button; + QAction *m_resourceAction; + QAction *m_fileAction; + QAction *m_themeAction; + QAction *m_copyAction; + QAction *m_pasteAction; + QHBoxLayout *m_layout; + QPixmap m_defaultPixmap; + QString m_path; + QString m_theme; + DesignerPixmapCache *m_pixmapCache; +}; + +PixmapEditor::PixmapEditor(QDesignerFormEditorInterface *core, QWidget *parent) : + QWidget(parent), + m_iconThemeModeEnabled(false), + m_core(core), + m_pixmapLabel(new QLabel(this)), + m_pathLabel(new QLabel(this)), + m_button(new QToolButton(this)), + m_resourceAction(new QAction(tr("Choose Resource..."), this)), + m_fileAction(new QAction(tr("Choose File..."), this)), + m_themeAction(new QAction(tr("Set Icon From Theme..."), this)), + m_copyAction(new QAction(createIconSet(QLatin1String("editcopy.png")), tr("Copy Path"), this)), + m_pasteAction(new QAction(createIconSet(QLatin1String("editpaste.png")), tr("Paste Path"), this)), + m_layout(new QHBoxLayout(this)), + m_pixmapCache(0) +{ + m_layout->addWidget(m_pixmapLabel); + m_layout->addWidget(m_pathLabel); + m_button->setText(tr("...")); + m_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Ignored); + m_button->setFixedWidth(30); + m_button->setPopupMode(QToolButton::MenuButtonPopup); + m_layout->addWidget(m_button); + m_layout->setMargin(0); + m_layout->setSpacing(0); + m_pixmapLabel->setFixedWidth(16); + m_pixmapLabel->setAlignment(Qt::AlignCenter); + m_pathLabel->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed)); + m_themeAction->setVisible(false); + + QMenu *menu = new QMenu(this); + menu->addAction(m_resourceAction); + menu->addAction(m_fileAction); + menu->addAction(m_themeAction); + + m_button->setMenu(menu); + m_button->setText(tr("...")); + + connect(m_button, SIGNAL(clicked()), this, SLOT(defaultActionActivated())); + connect(m_resourceAction, SIGNAL(triggered()), this, SLOT(resourceActionActivated())); + connect(m_fileAction, SIGNAL(triggered()), this, SLOT(fileActionActivated())); + connect(m_themeAction, SIGNAL(triggered()), this, SLOT(themeActionActivated())); + connect(m_copyAction, SIGNAL(triggered()), this, SLOT(copyActionActivated())); + connect(m_pasteAction, SIGNAL(triggered()), this, SLOT(pasteActionActivated())); + setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Ignored)); + setFocusProxy(m_button); + + connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(clipboardDataChanged())); + clipboardDataChanged(); +} + +void PixmapEditor::setPixmapCache(DesignerPixmapCache *cache) +{ + m_pixmapCache = cache; +} + +void PixmapEditor::setIconThemeModeEnabled(bool enabled) +{ + if (m_iconThemeModeEnabled == enabled) + return; + m_iconThemeModeEnabled = enabled; + m_themeAction->setVisible(enabled); +} + +void PixmapEditor::setSpacing(int spacing) +{ + m_layout->setSpacing(spacing); +} + +void PixmapEditor::setPath(const QString &path) +{ + m_path = path; + updateLabels(); +} + +void PixmapEditor::setTheme(const QString &theme) +{ + m_theme = theme; + updateLabels(); +} + +void PixmapEditor::updateLabels() +{ + if (m_iconThemeModeEnabled && QIcon::hasThemeIcon(m_theme)) { + m_pixmapLabel->setPixmap(QIcon::fromTheme(m_theme).pixmap(16, 16)); + m_pathLabel->setText(tr("[Theme] %1").arg(m_theme)); + m_copyAction->setEnabled(true); + } else { + if (m_path.isEmpty()) { + m_pathLabel->setText(m_path); + m_pixmapLabel->setPixmap(m_defaultPixmap); + m_copyAction->setEnabled(false); + } else { + m_pathLabel->setText(QFileInfo(m_path).fileName()); + if (m_pixmapCache) + m_pixmapLabel->setPixmap(QIcon(m_pixmapCache->pixmap(PropertySheetPixmapValue(m_path))).pixmap(16, 16)); + m_copyAction->setEnabled(true); + } + } +} + +void PixmapEditor::setDefaultPixmap(const QPixmap &pixmap) +{ + m_defaultPixmap = QIcon(pixmap).pixmap(16, 16); + const bool hasThemeIcon = m_iconThemeModeEnabled && QIcon::hasThemeIcon(m_theme); + if (!hasThemeIcon && m_path.isEmpty()) + m_pixmapLabel->setPixmap(m_defaultPixmap); +} + +void PixmapEditor::contextMenuEvent(QContextMenuEvent *event) +{ + QMenu menu(this); + menu.addAction(m_copyAction); + menu.addAction(m_pasteAction); + menu.exec(event->globalPos()); + event->accept(); +} + +void PixmapEditor::defaultActionActivated() +{ + if (m_iconThemeModeEnabled && QIcon::hasThemeIcon(m_theme)) { + themeActionActivated(); + return; + } + // Default to resource + const PropertySheetPixmapValue::PixmapSource ps = m_path.isEmpty() ? PropertySheetPixmapValue::ResourcePixmap : PropertySheetPixmapValue::getPixmapSource(m_core, m_path); + switch (ps) { + case PropertySheetPixmapValue::LanguageResourcePixmap: + case PropertySheetPixmapValue::ResourcePixmap: + resourceActionActivated(); + break; + case PropertySheetPixmapValue::FilePixmap: + fileActionActivated(); + break; + } +} + +void PixmapEditor::resourceActionActivated() +{ + const QString oldPath = m_path; + const QString newPath = IconSelector::choosePixmapResource(m_core, m_core->resourceModel(), oldPath, this); + if (!newPath.isEmpty() && newPath != oldPath) { + setTheme(QString()); + setPath(newPath); + emit pathChanged(newPath); + } +} + +void PixmapEditor::fileActionActivated() +{ + const QString newPath = IconSelector::choosePixmapFile(m_path, m_core->dialogGui(), this); + if (!newPath.isEmpty() && newPath != m_path) { + setTheme(QString()); + setPath(newPath); + emit pathChanged(newPath); + } +} + +void PixmapEditor::themeActionActivated() +{ + bool ok; + const QString newTheme = IconThemeDialog::getTheme(this, m_theme, &ok); + if (ok && newTheme != m_theme) { + setTheme(newTheme); + setPath(QString()); + emit themeChanged(newTheme); + } +} + +void PixmapEditor::copyActionActivated() +{ + QClipboard *clipboard = QApplication::clipboard(); + if (m_iconThemeModeEnabled && QIcon::hasThemeIcon(m_theme)) + clipboard->setText(m_theme); + else + clipboard->setText(m_path); +} + +void PixmapEditor::pasteActionActivated() +{ + QClipboard *clipboard = QApplication::clipboard(); + QString subtype = QLatin1String("plain"); + QString text = clipboard->text(subtype); + if (!text.isNull()) { + QStringList list = text.split(QLatin1Char('\n')); + if (list.size() > 0) { + text = list.at(0); + if (m_iconThemeModeEnabled && QIcon::hasThemeIcon(text)) { + setTheme(text); + setPath(QString()); + emit themeChanged(text); + } else { + setPath(text); + setTheme(QString()); + emit pathChanged(text); + } + } + } +} + +void PixmapEditor::clipboardDataChanged() +{ + QClipboard *clipboard = QApplication::clipboard(); + QString subtype = QLatin1String("plain"); + const QString text = clipboard->text(subtype); + m_pasteAction->setEnabled(!text.isNull()); +} + +// --------------- ResetWidget +class ResetWidget : public QWidget +{ + Q_OBJECT +public: + ResetWidget(QtProperty *property, QWidget *parent = 0); + + void setWidget(QWidget *widget); + void setResetEnabled(bool enabled); + void setValueText(const QString &text); + void setValueIcon(const QIcon &icon); + void setSpacing(int spacing); +signals: + void resetProperty(QtProperty *property); +private slots: + void slotClicked(); +private: + QtProperty *m_property; + QLabel *m_textLabel; + QLabel *m_iconLabel; + QToolButton *m_button; + int m_spacing; +}; + +ResetWidget::ResetWidget(QtProperty *property, QWidget *parent) : + QWidget(parent), + m_property(property), + m_textLabel(new QLabel(this)), + m_iconLabel(new QLabel(this)), + m_button(new QToolButton(this)), + m_spacing(-1) +{ + m_textLabel->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed)); + m_iconLabel->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + m_button->setToolButtonStyle(Qt::ToolButtonIconOnly); + m_button->setIcon(createIconSet(QLatin1String("resetproperty.png"))); + m_button->setIconSize(QSize(8,8)); + m_button->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding)); + connect(m_button, SIGNAL(clicked()), this, SLOT(slotClicked())); + QLayout *layout = new QHBoxLayout(this); + layout->setMargin(0); + layout->setSpacing(m_spacing); + layout->addWidget(m_iconLabel); + layout->addWidget(m_textLabel); + layout->addWidget(m_button); + setFocusProxy(m_textLabel); + setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); +} + +void ResetWidget::setSpacing(int spacing) +{ + m_spacing = spacing; + layout()->setSpacing(m_spacing); +} + +void ResetWidget::setWidget(QWidget *widget) +{ + if (m_textLabel) { + delete m_textLabel; + m_textLabel = 0; + } + if (m_iconLabel) { + delete m_iconLabel; + m_iconLabel = 0; + } + delete layout(); + QLayout *layout = new QHBoxLayout(this); + layout->setMargin(0); + layout->setSpacing(m_spacing); + layout->addWidget(widget); + layout->addWidget(m_button); + setFocusProxy(widget); +} + +void ResetWidget::setResetEnabled(bool enabled) +{ + m_button->setEnabled(enabled); +} + +void ResetWidget::setValueText(const QString &text) +{ + if (m_textLabel) + m_textLabel->setText(text); +} + +void ResetWidget::setValueIcon(const QIcon &icon) +{ + QPixmap pix = icon.pixmap(QSize(16, 16)); + if (m_iconLabel) { + m_iconLabel->setVisible(!pix.isNull()); + m_iconLabel->setPixmap(pix); + } +} + +void ResetWidget::slotClicked() +{ + emit resetProperty(m_property); +} + + +// ------------ DesignerPropertyManager: + +DesignerPropertyManager::DesignerPropertyManager(QDesignerFormEditorInterface *core, QObject *parent) : + QtVariantPropertyManager(parent), + m_changingSubValue(false), + m_core(core), + m_sourceOfChange(0) +{ + connect(this, SIGNAL(valueChanged(QtProperty*,QVariant)), this, SLOT(slotValueChanged(QtProperty*,QVariant))); + connect(this, SIGNAL(propertyDestroyed(QtProperty*)), this, SLOT(slotPropertyDestroyed(QtProperty*))); +} + +DesignerPropertyManager::~DesignerPropertyManager() +{ + clear(); +} + +int DesignerPropertyManager::bitCount(int mask) const +{ + int count = 0; + for (; mask; count++) + mask &= mask - 1; // clear the least significant bit set + return count; +} + +int DesignerPropertyManager::alignToIndexH(uint align) const +{ + if (align & Qt::AlignLeft) + return 0; + if (align & Qt::AlignHCenter) + return 1; + if (align & Qt::AlignRight) + return 2; + if (align & Qt::AlignJustify) + return 3; + return 0; +} + +int DesignerPropertyManager::alignToIndexV(uint align) const +{ + if (align & Qt::AlignTop) + return 0; + if (align & Qt::AlignVCenter) + return 1; + if (align & Qt::AlignBottom) + return 2; + return 1; +} + +uint DesignerPropertyManager::indexHToAlign(int idx) const +{ + switch (idx) { + case 0: return Qt::AlignLeft; + case 1: return Qt::AlignHCenter; + case 2: return Qt::AlignRight; + case 3: return Qt::AlignJustify; + default: break; + } + return Qt::AlignLeft; +} + +uint DesignerPropertyManager::indexVToAlign(int idx) const +{ + switch (idx) { + case 0: return Qt::AlignTop; + case 1: return Qt::AlignVCenter; + case 2: return Qt::AlignBottom; + default: break; + } + return Qt::AlignVCenter; +} + +QString DesignerPropertyManager::indexHToString(int idx) const +{ + switch (idx) { + case 0: return tr("AlignLeft"); + case 1: return tr("AlignHCenter"); + case 2: return tr("AlignRight"); + case 3: return tr("AlignJustify"); + default: break; + } + return tr("AlignLeft"); +} + +QString DesignerPropertyManager::indexVToString(int idx) const +{ + switch (idx) { + case 0: return tr("AlignTop"); + case 1: return tr("AlignVCenter"); + case 2: return tr("AlignBottom"); + default: break; + } + return tr("AlignVCenter"); +} + +void DesignerPropertyManager::slotValueChanged(QtProperty *property, const QVariant &value) +{ + if (m_changingSubValue) + return; + bool enableSubPropertyHandling = true; + + if (QtProperty *flagProperty = m_flagToProperty.value(property, 0)) { + const QList subFlags = m_propertyToFlags.value(flagProperty); + const int subFlagCount = subFlags.count(); + // flag changed + const bool subValue = variantProperty(property)->value().toBool(); + const int subIndex = subFlags.indexOf(property); + if (subIndex < 0) + return; + + uint newValue = 0; + + m_changingSubValue = true; + + FlagData data = m_flagValues.value(flagProperty); + const QList values = data.values; + // Compute new value, without including (additional) supermasks + if (values.at(subIndex) == 0) { + for (int i = 0; i < subFlagCount; ++i) { + QtVariantProperty *subFlag = variantProperty(subFlags.at(i)); + subFlag->setValue(i == subIndex); + } + } else { + if (subValue) + newValue = values.at(subIndex); // value mask of subValue + for (int i = 0; i < subFlagCount; ++i) { + QtVariantProperty *subFlag = variantProperty(subFlags.at(i)); + if (subFlag->value().toBool() && bitCount(values.at(i)) == 1) + newValue |= values.at(i); + } + if (newValue == 0) { + // Uncheck all items except 0-mask + for (int i = 0; i < subFlagCount; ++i) { + QtVariantProperty *subFlag = variantProperty(subFlags.at(i)); + subFlag->setValue(values.at(i) == 0); + } + } else if (newValue == data.val) { + if (!subValue && bitCount(values.at(subIndex)) > 1) { + // We unchecked something, but the original value still holds + variantProperty(property)->setValue(true); + } + } else { + // Make sure 0-mask is not selected + for (int i = 0; i < subFlagCount; ++i) { + QtVariantProperty *subFlag = variantProperty(subFlags.at(i)); + if (values.at(i) == 0) + subFlag->setValue(false); + } + // Check/uncheck proper masks + if (subValue) { + // Make sure submasks and supermasks are selected + for (int i = 0; i < subFlagCount; ++i) { + QtVariantProperty *subFlag = variantProperty(subFlags.at(i)); + const uint vi = values.at(i); + if ((vi != 0) && ((vi & newValue) == vi) && !subFlag->value().toBool()) + subFlag->setValue(true); + } + } else { + // Make sure supermasks are not selected if they're no longer valid + for (int i = 0; i < subFlagCount; ++i) { + QtVariantProperty *subFlag = variantProperty(subFlags.at(i)); + const uint vi = values.at(i); + if (subFlag->value().toBool() && ((vi & newValue) != vi)) + subFlag->setValue(false); + } + } + } + } + m_changingSubValue = false; + data.val = newValue; + QVariant v; + v.setValue(data.val); + variantProperty(flagProperty)->setValue(v); + } else if (QtProperty *alignProperty = m_alignHToProperty.value(property, 0)) { + const uint v = m_alignValues.value(alignProperty); + const uint newValue = indexHToAlign(value.toInt()) | indexVToAlign(alignToIndexV(v)); + if (v == newValue) + return; + + variantProperty(alignProperty)->setValue(newValue); + } else if (QtProperty *alignProperty = m_alignVToProperty.value(property, 0)) { + const uint v = m_alignValues.value(alignProperty); + const uint newValue = indexVToAlign(value.toInt()) | indexHToAlign(alignToIndexH(v)); + if (v == newValue) + return; + + variantProperty(alignProperty)->setValue(newValue); + } else if (QtProperty *stringProperty = m_commentToString.value(property, 0)) { + const PropertySheetStringValue v = m_stringValues.value(stringProperty); + PropertySheetStringValue newValue = v; + newValue.setComment(value.toString()); + if (v == newValue) + return; + + variantProperty(stringProperty)->setValue(QVariant::fromValue(newValue)); + } else if (QtProperty *stringProperty = m_translatableToString.value(property, 0)) { + const PropertySheetStringValue v = m_stringValues.value(stringProperty); + PropertySheetStringValue newValue = v; + newValue.setTranslatable(value.toBool()); + if (v == newValue) + return; + + variantProperty(stringProperty)->setValue(QVariant::fromValue(newValue)); + } else if (QtProperty *stringProperty = m_disambiguationToString.value(property, 0)) { + const PropertySheetStringValue v = m_stringValues.value(stringProperty); + PropertySheetStringValue newValue = v; + newValue.setDisambiguation(value.toString()); + if (v == newValue) + return; + + variantProperty(stringProperty)->setValue(QVariant::fromValue(newValue)); + } else if (QtProperty *keySequenceProperty = m_commentToKeySequence.value(property, 0)) { + const PropertySheetKeySequenceValue v = m_keySequenceValues.value(keySequenceProperty); + PropertySheetKeySequenceValue newValue = v; + newValue.setComment(value.toString()); + if (v == newValue) + return; + + variantProperty(keySequenceProperty)->setValue(QVariant::fromValue(newValue)); + } else if (QtProperty *keySequenceProperty = m_translatableToKeySequence.value(property, 0)) { + const PropertySheetKeySequenceValue v = m_keySequenceValues.value(keySequenceProperty); + PropertySheetKeySequenceValue newValue = v; + newValue.setTranslatable(value.toBool()); + if (v == newValue) + return; + + variantProperty(keySequenceProperty)->setValue(QVariant::fromValue(newValue)); + } else if (QtProperty *keySequenceProperty = m_disambiguationToKeySequence.value(property, 0)) { + const PropertySheetKeySequenceValue v = m_keySequenceValues.value(keySequenceProperty); + PropertySheetKeySequenceValue newValue = v; + newValue.setDisambiguation(value.toString()); + if (v == newValue) + return; + + variantProperty(keySequenceProperty)->setValue(QVariant::fromValue(newValue)); + } else if (QtProperty *iProperty = m_iconSubPropertyToProperty.value(property, 0)) { + QtVariantProperty *iconProperty = variantProperty(iProperty); + PropertySheetIconValue icon = qvariant_cast(iconProperty->value()); + QMap >::ConstIterator itState = m_iconSubPropertyToState.constFind(property); + if (itState != m_iconSubPropertyToState.constEnd()) { + QPair pair = m_iconSubPropertyToState.value(property); + icon.setPixmap(pair.first, pair.second, qvariant_cast(value)); + } else { // must be theme property + icon.setTheme(value.toString()); + } + QtProperty *origSourceOfChange = m_sourceOfChange; + if (!origSourceOfChange) + m_sourceOfChange = property; + iconProperty->setValue(QVariant::fromValue(icon)); + if (!origSourceOfChange) + m_sourceOfChange = origSourceOfChange; + } else if (m_iconValues.contains(property)) { + enableSubPropertyHandling = m_sourceOfChange; + } else { + if (m_brushManager.valueChanged(this, property, value) == BrushPropertyManager::Unchanged) + return; + if (m_fontManager.valueChanged(this, property, value) == FontPropertyManager::Unchanged) + return; + } + + emit valueChanged(property, value, enableSubPropertyHandling); +} + +void DesignerPropertyManager::slotPropertyDestroyed(QtProperty *property) +{ + if (QtProperty *flagProperty = m_flagToProperty.value(property, 0)) { + PropertyToPropertyListMap::iterator it = m_propertyToFlags.find(flagProperty); + QList &propertyList = it.value(); + propertyList.replace(propertyList.indexOf(property), 0); + m_flagToProperty.remove(property); + } else if (QtProperty *alignProperty = m_alignHToProperty.value(property, 0)) { + m_propertyToAlignH.remove(alignProperty); + m_alignHToProperty.remove(property); + } else if (QtProperty *alignProperty = m_alignVToProperty.value(property, 0)) { + m_propertyToAlignV.remove(alignProperty); + m_alignVToProperty.remove(property); + } else if (QtProperty *stringCommentProperty = m_commentToString.value(property, 0)) { + m_stringToComment.remove(stringCommentProperty); + m_commentToString.remove(property); + } else if (QtProperty *stringTranslatableProperty = m_translatableToString.value(property, 0)) { + m_stringToTranslatable.remove(stringTranslatableProperty); + m_translatableToString.remove(property); + } else if (QtProperty *stringDisambiguationProperty = m_disambiguationToString.value(property, 0)) { + m_stringToDisambiguation.remove(stringDisambiguationProperty); + m_disambiguationToString.remove(property); + } else if (QtProperty *keySequenceCommentProperty = m_commentToKeySequence.value(property, 0)) { + m_keySequenceToComment.remove(keySequenceCommentProperty); + m_commentToKeySequence.remove(property); + } else if (QtProperty *keySequenceTranslatableProperty = m_translatableToKeySequence.value(property, 0)) { + m_keySequenceToTranslatable.remove(keySequenceTranslatableProperty); + m_translatableToKeySequence.remove(property); + } else if (QtProperty *keySequenceDisambiguationProperty = m_disambiguationToKeySequence.value(property, 0)) { + m_keySequenceToDisambiguation.remove(keySequenceDisambiguationProperty); + m_disambiguationToKeySequence.remove(property); + } else if (QtProperty *iconProperty = m_iconSubPropertyToProperty.value(property, 0)) { + if (m_propertyToTheme.value(iconProperty) == property) { + m_propertyToTheme.remove(iconProperty); + } else { + QMap, QtProperty *> >::iterator it = + m_propertyToIconSubProperties.find(iconProperty); + QPair state = m_iconSubPropertyToState.value(property); + QMap, QtProperty *> &propertyList = it.value(); + propertyList.remove(state); + m_iconSubPropertyToState.remove(property); + } + m_iconSubPropertyToProperty.remove(property); + } else { + m_fontManager.slotPropertyDestroyed(property); + m_brushManager.slotPropertyDestroyed(property); + } +} + +QStringList DesignerPropertyManager::attributes(int propertyType) const +{ + if (!isPropertyTypeSupported(propertyType)) + return QStringList(); + + QStringList list = QtVariantPropertyManager::attributes(propertyType); + if (propertyType == designerFlagTypeId()) { + list.append(QLatin1String(flagsAttributeC)); + } else if (propertyType == designerPixmapTypeId()) { + list.append(QLatin1String(defaultResourceAttributeC)); + } else if (propertyType == designerIconTypeId()) { + list.append(QLatin1String(defaultResourceAttributeC)); + } else if (propertyType == designerStringTypeId() || propertyType == QVariant::String) { + list.append(QLatin1String(validationModesAttributeC)); + list.append(QLatin1String(fontAttributeC)); + list.append(QLatin1String(themeAttributeC)); + } else if (propertyType == QVariant::Palette) { + list.append(QLatin1String(superPaletteAttributeC)); + } + list.append(QLatin1String(resettableAttributeC)); + return list; +} + +int DesignerPropertyManager::attributeType(int propertyType, const QString &attribute) const +{ + if (!isPropertyTypeSupported(propertyType)) + return 0; + + if (propertyType == designerFlagTypeId() && attribute == QLatin1String(flagsAttributeC)) + return designerFlagListTypeId(); + if (propertyType == designerPixmapTypeId() && attribute == QLatin1String(defaultResourceAttributeC)) + return QVariant::Pixmap; + if (propertyType == designerIconTypeId() && attribute == QLatin1String(defaultResourceAttributeC)) + return QVariant::Icon; + if (attribute == QLatin1String(resettableAttributeC)) + return QVariant::Bool; + if (propertyType == designerStringTypeId() || propertyType == QVariant::String) { + if (attribute == QLatin1String(validationModesAttributeC)) + return QVariant::Int; + if (attribute == QLatin1String(fontAttributeC)) + return QVariant::Font; + if (attribute == QLatin1String(themeAttributeC)) + return QVariant::Bool; + } + if (propertyType == QVariant::Palette && attribute == QLatin1String(superPaletteAttributeC)) + return QVariant::Palette; + + return QtVariantPropertyManager::attributeType(propertyType, attribute); +} + +QVariant DesignerPropertyManager::attributeValue(const QtProperty *property, const QString &attribute) const +{ + QtProperty *prop = const_cast(property); + + if (attribute == QLatin1String(resettableAttributeC)) { + const PropertyBoolMap::const_iterator it = m_resetMap.constFind(prop); + if (it != m_resetMap.constEnd()) + return it.value(); + } + + if (attribute == QLatin1String(flagsAttributeC)) { + PropertyFlagDataMap::const_iterator it = m_flagValues.constFind(prop); + if (it != m_flagValues.constEnd()) { + QVariant v; + v.setValue(it.value().flags); + return v; + } + } + if (attribute == QLatin1String(validationModesAttributeC)) { + const PropertyIntMap::const_iterator it = m_stringAttributes.constFind(prop); + if (it != m_stringAttributes.constEnd()) + return it.value(); + } + + if (attribute == QLatin1String(fontAttributeC)) { + const PropertyFontMap::const_iterator it = m_stringFontAttributes.constFind(prop); + if (it != m_stringFontAttributes.constEnd()) + return it.value(); + } + + if (attribute == QLatin1String(themeAttributeC)) { + const PropertyBoolMap::const_iterator it = m_stringThemeAttributes.constFind(prop); + if (it != m_stringThemeAttributes.constEnd()) + return it.value(); + } + + if (attribute == QLatin1String(superPaletteAttributeC)) { + PropertyPaletteDataMap::const_iterator it = m_paletteValues.constFind(prop); + if (it != m_paletteValues.constEnd()) + return it.value().superPalette; + } + + if (attribute == QLatin1String(defaultResourceAttributeC)) { + QMap::const_iterator itPix = m_defaultPixmaps.constFind(prop); + if (itPix != m_defaultPixmaps.constEnd()) + return itPix.value(); + + QMap::const_iterator itIcon = m_defaultIcons.constFind(prop); + if (itIcon != m_defaultIcons.constEnd()) + return itIcon.value(); + } + + return QtVariantPropertyManager::attributeValue(property, attribute); +} + +void DesignerPropertyManager::setAttribute(QtProperty *property, + const QString &attribute, const QVariant &value) +{ + if (attribute == QLatin1String(resettableAttributeC) && m_resetMap.contains(property)) { + if (value.userType() != QVariant::Bool) + return; + const bool val = value.toBool(); + const PropertyBoolMap::iterator it = m_resetMap.find(property); + if (it.value() == val) + return; + it.value() = val; + emit attributeChanged(variantProperty(property), attribute, value); + return; + } else if (attribute == QLatin1String(flagsAttributeC) && m_flagValues.contains(property)) { + if (value.userType() != designerFlagListTypeId()) + return; + + const DesignerFlagList flags = qvariant_cast(value); + PropertyFlagDataMap::iterator fit = m_flagValues.find(property); + FlagData data = fit.value(); + if (data.flags == flags) + return; + + PropertyToPropertyListMap::iterator pfit = m_propertyToFlags.find(property); + QListIterator itProp(pfit.value()); + while (itProp.hasNext()) { + if (QtProperty *prop = itProp.next()) { + delete prop; + m_flagToProperty.remove(prop); + } + } + pfit.value().clear(); + + QList values; + + QListIterator > itFlag(flags); + while (itFlag.hasNext()) { + const QPair pair = itFlag.next(); + const QString flagName = pair.first; + QtProperty *prop = addProperty(QVariant::Bool); + prop->setPropertyName(flagName); + property->addSubProperty(prop); + m_propertyToFlags[property].append(prop); + m_flagToProperty[prop] = property; + values.append(pair.second); + } + + data.val = 0; + data.flags = flags; + data.values = values; + + fit.value() = data; + + QVariant v; + v.setValue(flags); + emit attributeChanged(property, attribute, v); + + emit propertyChanged(property); + emit QtVariantPropertyManager::valueChanged(property, data.val); + } else if (attribute == QLatin1String(validationModesAttributeC) && m_stringAttributes.contains(property)) { + if (value.userType() != QVariant::Int) + return; + + const PropertyIntMap::iterator it = m_stringAttributes.find(property); + const int oldValue = it.value(); + + const int newValue = value.toInt(); + + if (oldValue == newValue) + return; + + it.value() = newValue; + + emit attributeChanged(property, attribute, newValue); + } else if (attribute == QLatin1String(fontAttributeC) && m_stringFontAttributes.contains(property)) { + if (value.userType() != QVariant::Font) + return; + + const PropertyFontMap::iterator it = m_stringFontAttributes.find(property); + const QFont oldValue = it.value(); + + const QFont newValue = qvariant_cast(value); + + if (oldValue == newValue) + return; + + it.value() = newValue; + + emit attributeChanged(property, attribute, newValue); + } else if (attribute == QLatin1String(themeAttributeC) && m_stringThemeAttributes.contains(property)) { + if (value.userType() != QVariant::Bool) + return; + + const PropertyBoolMap::iterator it = m_stringThemeAttributes.find(property); + const bool oldValue = it.value(); + + const bool newValue = value.toBool(); + + if (oldValue == newValue) + return; + + it.value() = newValue; + + emit attributeChanged(property, attribute, newValue); + } else if (attribute == QLatin1String(superPaletteAttributeC) && m_paletteValues.contains(property)) { + if (value.userType() != QVariant::Palette) + return; + + QPalette superPalette = qvariant_cast(value); + + const PropertyPaletteDataMap::iterator it = m_paletteValues.find(property); + PaletteData data = it.value(); + if (data.superPalette == superPalette) + return; + + data.superPalette = superPalette; + // resolve here + const uint mask = data.val.resolve(); + data.val = data.val.resolve(superPalette); + data.val.resolve(mask); + + it.value() = data; + + QVariant v; + v.setValue(superPalette); + emit attributeChanged(property, attribute, v); + + emit propertyChanged(property); + emit QtVariantPropertyManager::valueChanged(property, data.val); // if resolve was done, this is also for consistency + } else if (attribute == QLatin1String(defaultResourceAttributeC) && m_defaultPixmaps.contains(property)) { + if (value.userType() != QVariant::Pixmap) + return; + + QPixmap defaultPixmap = qvariant_cast(value); + + const QMap::iterator it = m_defaultPixmaps.find(property); + QPixmap oldDefaultPixmap = it.value(); + if (defaultPixmap.cacheKey() == oldDefaultPixmap.cacheKey()) + return; + + it.value() = defaultPixmap; + + QVariant v = QVariant::fromValue(defaultPixmap); + emit attributeChanged(property, attribute, v); + + emit propertyChanged(property); + } else if (attribute == QLatin1String(defaultResourceAttributeC) && m_defaultIcons.contains(property)) { + if (value.userType() != QVariant::Icon) + return; + + QIcon defaultIcon = qvariant_cast(value); + + const QMap::iterator it = m_defaultIcons.find(property); + QIcon oldDefaultIcon = it.value(); + if (defaultIcon.cacheKey() == oldDefaultIcon.cacheKey()) + return; + + it.value() = defaultIcon; + + qdesigner_internal::PropertySheetIconValue icon = m_iconValues.value(property); + if (icon.paths().isEmpty()) { + QMap, QtProperty *> subIconProperties = m_propertyToIconSubProperties.value(property); + QMapIterator, QtProperty *> itSub(subIconProperties); + while (itSub.hasNext()) { + QPair pair = itSub.next().key(); + QtProperty *subProp = itSub.value(); + setAttribute(subProp, QLatin1String(defaultResourceAttributeC), + defaultIcon.pixmap(16, 16, pair.first, pair.second)); + } + } + + QVariant v = QVariant::fromValue(defaultIcon); + emit attributeChanged(property, attribute, v); + + emit propertyChanged(property); + } + QtVariantPropertyManager::setAttribute(property, attribute, value); +} + +int DesignerPropertyManager::designerFlagTypeId() +{ + static const int rc = qMetaTypeId(); + return rc; +} + +int DesignerPropertyManager::designerFlagListTypeId() +{ + static const int rc = qMetaTypeId(); + return rc; +} + +int DesignerPropertyManager::designerAlignmentTypeId() +{ + static const int rc = qMetaTypeId(); + return rc; +} + +int DesignerPropertyManager::designerPixmapTypeId() +{ + return qMetaTypeId(); +} + +int DesignerPropertyManager::designerIconTypeId() +{ + return qMetaTypeId(); +} + +int DesignerPropertyManager::designerStringTypeId() +{ + return qMetaTypeId(); +} + +int DesignerPropertyManager::designerKeySequenceTypeId() +{ + return qMetaTypeId(); +} + +bool DesignerPropertyManager::isPropertyTypeSupported(int propertyType) const +{ + switch (propertyType) { + case QVariant::Palette: + case QVariant::UInt: + case QVariant::LongLong: + case QVariant::ULongLong: + case QVariant::Url: + case QVariant::ByteArray: + case QVariant::StringList: + case QVariant::Brush: + return true; + default: + break; + } + + if (propertyType == designerFlagTypeId()) + return true; + if (propertyType == designerAlignmentTypeId()) + return true; + if (propertyType == designerPixmapTypeId()) + return true; + if (propertyType == designerIconTypeId()) + return true; + if (propertyType == designerStringTypeId()) + return true; + if (propertyType == designerKeySequenceTypeId()) + return true; + return QtVariantPropertyManager::isPropertyTypeSupported(propertyType); +} + +QString DesignerPropertyManager::valueText(const QtProperty *property) const +{ + if (m_flagValues.contains(const_cast(property))) { + const FlagData data = m_flagValues.value(const_cast(property)); + const uint v = data.val; + const QChar bar = QLatin1Char('|'); + QString valueStr; + const QList > flags = data.flags; + const QList >::const_iterator fcend = flags.constEnd(); + for (QList >::const_iterator it = flags.constBegin(); it != fcend; ++it) { + const uint val = it->second; + const bool checked = (val == 0) ? (v == 0) : ((val & v) == val); + if (checked) { + if (!valueStr.isEmpty()) + valueStr += bar; + valueStr += it->first; + } + } + return valueStr; + } + if (m_alignValues.contains(const_cast(property))) { + const uint v = m_alignValues.value(const_cast(property)); + return tr("%1, %2").arg(indexHToString(alignToIndexH(v))).arg(indexVToString(alignToIndexV(v))); + } + if (m_paletteValues.contains(const_cast(property))) { + const PaletteData data = m_paletteValues.value(const_cast(property)); + const uint mask = data.val.resolve(); + if (mask) + return tr("Customized (%n roles)", 0, bitCount(mask)); + static const QString inherited = tr("Inherited"); + return inherited; + } + if (m_iconValues.contains(const_cast(property))) { + const PropertySheetIconValue icon = m_iconValues.value(const_cast(property)); + const QString theme = icon.theme(); + if (!theme.isEmpty() && QIcon::hasThemeIcon(theme)) + return tr("[Theme] %1").arg(theme); + const PropertySheetIconValue::ModeStateToPixmapMap paths = icon.paths(); + const PropertySheetIconValue::ModeStateToPixmapMap::const_iterator it = paths.constFind(qMakePair(QIcon::Normal, QIcon::Off)); + if (it == paths.constEnd()) + return QString(); + return QFileInfo(it.value().path()).fileName(); + } + if (m_pixmapValues.contains(const_cast(property))) { + const QString path = m_pixmapValues.value(const_cast(property)).path(); + if (path.isEmpty()) + return QString(); + return QFileInfo(path).fileName(); + } + if (m_uintValues.contains(const_cast(property))) { + return QString::number(m_uintValues.value(const_cast(property))); + } + if (m_longLongValues.contains(const_cast(property))) { + return QString::number(m_longLongValues.value(const_cast(property))); + } + if (m_uLongLongValues.contains(const_cast(property))) { + return QString::number(m_uLongLongValues.value(const_cast(property))); + } + if (m_urlValues.contains(const_cast(property))) { + return m_urlValues.value(const_cast(property)).toString(); + } + if (m_byteArrayValues.contains(const_cast(property))) { + return QString::fromUtf8(m_byteArrayValues.value(const_cast(property))); + } + if (m_stringListValues.contains(const_cast(property))) { + return m_stringListValues.value(const_cast(property)).join(QLatin1String("; ")); + } + if (QtVariantPropertyManager::valueType(property) == QVariant::String || QtVariantPropertyManager::valueType(property) == designerStringTypeId()) { + const QString str = (QtVariantPropertyManager::valueType(property) == QVariant::String) ? value(property).toString() : qvariant_cast(value(property)).value(); + const int validationMode = attributeValue(property, QLatin1String(validationModesAttributeC)).toInt(); + return TextPropertyEditor::stringToEditorString(str, static_cast(validationMode)); + } + if (QtVariantPropertyManager::valueType(property) == designerKeySequenceTypeId()) { + return qvariant_cast(value(property)).value(); + } + if (QtVariantPropertyManager::valueType(property) == QVariant::Bool) { + return QString(); + } + + QString rc; + if (m_brushManager.valueText(property, &rc)) + return rc; + return QtVariantPropertyManager::valueText(property); +} + +void DesignerPropertyManager::reloadResourceProperties() +{ + DesignerIconCache *iconCache = 0; + QMapIterator itIcon(m_iconValues); + while (itIcon.hasNext()) { + QtProperty *property = itIcon.next().key(); + PropertySheetIconValue icon = itIcon.value(); + + QIcon defaultIcon = m_defaultIcons.value(property); + if (!icon.paths().isEmpty()) { + if (!iconCache) { + QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(m_object); + qdesigner_internal::FormWindowBase *fwb = qobject_cast(formWindow); + iconCache = fwb->iconCache(); + } + if (iconCache) + defaultIcon = iconCache->icon(icon); + } + + QMap, PropertySheetPixmapValue> iconPaths = icon.paths(); + + QMap, QtProperty *> subProperties = m_propertyToIconSubProperties.value(property); + QMapIterator, QtProperty *> itSub(subProperties); + while (itSub.hasNext()) { + const QPair pair = itSub.next().key(); + QtVariantProperty *subProperty = variantProperty(itSub.value()); + subProperty->setAttribute(QLatin1String(defaultResourceAttributeC), + defaultIcon.pixmap(16, 16, pair.first, pair.second)); + } + + emit propertyChanged(property); + emit QtVariantPropertyManager::valueChanged(property, QVariant::fromValue(itIcon.value())); + } + QMapIterator itPix(m_pixmapValues); + while (itPix.hasNext()) { + QtProperty *property = itPix.next().key(); + emit propertyChanged(property); + emit QtVariantPropertyManager::valueChanged(property, QVariant::fromValue(itPix.value())); + } +} + +QIcon DesignerPropertyManager::valueIcon(const QtProperty *property) const +{ + if (m_iconValues.contains(const_cast(property))) { + if (!property->isModified()) + return m_defaultIcons.value(const_cast(property)).pixmap(16, 16); + QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(m_object); + qdesigner_internal::FormWindowBase *fwb = qobject_cast(formWindow); + if (fwb) + return fwb->iconCache()->icon(m_iconValues.value(const_cast(property))).pixmap(16, 16); + } else if (m_pixmapValues.contains(const_cast(property))) { + if (!property->isModified()) + return m_defaultPixmaps.value(const_cast(property)); + QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(m_object); + qdesigner_internal::FormWindowBase *fwb = qobject_cast(formWindow); + if (fwb) + return fwb->pixmapCache()->pixmap(m_pixmapValues.value(const_cast(property))); + } else if (m_stringThemeAttributes.value(const_cast(property), false)) { + return QIcon::fromTheme(value(property).toString()); + } else { + QIcon rc; + if (m_brushManager.valueIcon(property, &rc)) + return rc; + } + + return QtVariantPropertyManager::valueIcon(property); +} + +QVariant DesignerPropertyManager::value(const QtProperty *property) const +{ + if (m_flagValues.contains(const_cast(property))) + return m_flagValues.value(const_cast(property)).val; + if (m_alignValues.contains(const_cast(property))) + return m_alignValues.value(const_cast(property)); + if (m_paletteValues.contains(const_cast(property))) + return m_paletteValues.value(const_cast(property)).val; + if (m_iconValues.contains(const_cast(property))) + return QVariant::fromValue(m_iconValues.value(const_cast(property))); + if (m_pixmapValues.contains(const_cast(property))) + return QVariant::fromValue(m_pixmapValues.value(const_cast(property))); + if (m_stringValues.contains(const_cast(property))) + return QVariant::fromValue(m_stringValues.value(const_cast(property))); + if (m_keySequenceValues.contains(const_cast(property))) + return QVariant::fromValue(m_keySequenceValues.value(const_cast(property))); + if (m_uintValues.contains(const_cast(property))) + return m_uintValues.value(const_cast(property)); + if (m_longLongValues.contains(const_cast(property))) + return m_longLongValues.value(const_cast(property)); + if (m_uLongLongValues.contains(const_cast(property))) + return m_uLongLongValues.value(const_cast(property)); + if (m_urlValues.contains(const_cast(property))) + return m_urlValues.value(const_cast(property)); + if (m_byteArrayValues.contains(const_cast(property))) + return m_byteArrayValues.value(const_cast(property)); + if (m_stringListValues.contains(const_cast(property))) + return m_stringListValues.value(const_cast(property)); + + QVariant rc; + if (m_brushManager.value(property, &rc)) + return rc; + return QtVariantPropertyManager::value(property); +} + +int DesignerPropertyManager::valueType(int propertyType) const +{ + switch (propertyType) { + case QVariant::Palette: + case QVariant::UInt: + case QVariant::LongLong: + case QVariant::ULongLong: + case QVariant::Url: + case QVariant::ByteArray: + case QVariant::StringList: + case QVariant::Brush: + return propertyType; + default: + break; + } + if (propertyType == designerFlagTypeId()) + return QVariant::UInt; + if (propertyType == designerAlignmentTypeId()) + return QVariant::UInt; + if (propertyType == designerPixmapTypeId()) + return propertyType; + if (propertyType == designerIconTypeId()) + return propertyType; + if (propertyType == designerStringTypeId()) + return propertyType; + if (propertyType == designerKeySequenceTypeId()) + return propertyType; + return QtVariantPropertyManager::valueType(propertyType); +} + +void DesignerPropertyManager::setValue(QtProperty *property, const QVariant &value) +{ + const PropertyFlagDataMap::iterator fit = m_flagValues.find(property); + + if (fit != m_flagValues.end()) { + if (value.type() != QVariant::UInt && !value.canConvert(QVariant::UInt)) + return; + + const uint v = value.toUInt(); + + FlagData data = fit.value(); + if (data.val == v) + return; + + // set Value + + const QList values = data.values; + const QList subFlags = m_propertyToFlags.value(property); + const int subFlagCount = subFlags.count(); + for (int i = 0; i < subFlagCount; ++i) { + QtVariantProperty *subFlag = variantProperty(subFlags.at(i)); + const uint val = values.at(i); + const bool checked = (val == 0) ? (v == 0) : ((val & v) == val); + subFlag->setValue(checked); + } + + for (int i = 0; i < subFlagCount; ++i) { + QtVariantProperty *subFlag = variantProperty(subFlags.at(i)); + const uint val = values.at(i); + const bool checked = (val == 0) ? (v == 0) : ((val & v) == val); + bool enabled = true; + if (val == 0) { + if (checked) + enabled = false; + } else if (bitCount(val) > 1) { + // Disabled if all flags contained in the mask are checked + uint currentMask = 0; + for (int j = 0; j < subFlagCount; ++j) { + QtVariantProperty *subFlag = variantProperty(subFlags.at(j)); + if (bitCount(values.at(j)) == 1) + currentMask |= subFlag->value().toBool() ? values.at(j) : 0; + } + if ((currentMask & values.at(i)) == values.at(i)) + enabled = false; + } + subFlag->setEnabled(enabled); + } + + data.val = v; + fit.value() = data; + + emit QtVariantPropertyManager::valueChanged(property, data.val); + emit propertyChanged(property); + + return; + } else if (m_alignValues.contains(property)) { + if (value.type() != QVariant::UInt && !value.canConvert(QVariant::UInt)) + return; + + const uint v = value.toUInt(); + + uint val = m_alignValues.value(property); + + if (val == v) + return; + + QtVariantProperty *alignH = variantProperty(m_propertyToAlignH.value(property)); + QtVariantProperty *alignV = variantProperty(m_propertyToAlignV.value(property)); + + if (alignH) + alignH->setValue(alignToIndexH(v)); + if (alignV) + alignV->setValue(alignToIndexV(v)); + + m_alignValues[property] = v; + + emit QtVariantPropertyManager::valueChanged(property, v); + emit propertyChanged(property); + + return; + } else if (m_stringValues.contains(property)) { + if (value.userType() != designerStringTypeId()) + return; + + const PropertySheetStringValue v = qvariant_cast(value); + + const PropertySheetStringValue val = m_stringValues.value(property); + + if (val == v) + return; + + QtVariantProperty *comment = variantProperty(m_stringToComment.value(property)); + QtVariantProperty *translatable = variantProperty(m_stringToTranslatable.value(property)); + QtVariantProperty *disambiguation = variantProperty(m_stringToDisambiguation.value(property)); + + if (comment) + comment->setValue(v.comment()); + if (translatable) + translatable->setValue(v.translatable()); + if (disambiguation) + disambiguation->setValue(v.disambiguation()); + + m_stringValues[property] = v; + + emit QtVariantPropertyManager::valueChanged(property, QVariant::fromValue(v)); + emit propertyChanged(property); + + return; + } else if (m_keySequenceValues.contains(property)) { + if (value.userType() != designerKeySequenceTypeId()) + return; + + const PropertySheetKeySequenceValue v = qvariant_cast(value); + + const PropertySheetKeySequenceValue val = m_keySequenceValues.value(property); + + if (val == v) + return; + + QtVariantProperty *comment = variantProperty(m_keySequenceToComment.value(property)); + QtVariantProperty *translatable = variantProperty(m_keySequenceToTranslatable.value(property)); + QtVariantProperty *disambiguation = variantProperty(m_keySequenceToDisambiguation.value(property)); + + if (comment) + comment->setValue(v.comment()); + if (translatable) + translatable->setValue(v.translatable()); + if (disambiguation) + disambiguation->setValue(v.disambiguation()); + + m_keySequenceValues[property] = v; + + emit QtVariantPropertyManager::valueChanged(property, QVariant::fromValue(v)); + emit propertyChanged(property); + + return; + } else if (m_paletteValues.contains(property)) { + if (value.type() != QVariant::Palette && !value.canConvert(QVariant::Palette)) + return; + + QPalette p = qvariant_cast(value); + + PaletteData data = m_paletteValues.value(property); + + const uint mask = p.resolve(); + p = p.resolve(data.superPalette); + p.resolve(mask); + + if (data.val == p && data.val.resolve() == p.resolve()) + return; + + data.val = p; + m_paletteValues[property] = data; + + emit QtVariantPropertyManager::valueChanged(property, data.val); + emit propertyChanged(property); + + return; + } else if (m_iconValues.contains(property)) { + if (value.userType() != designerIconTypeId()) + return; + + const PropertySheetIconValue icon = qvariant_cast(value); + + const PropertySheetIconValue oldIcon = m_iconValues.value(property); + if (icon == oldIcon) + return; + + m_iconValues[property] = icon; + + QIcon defaultIcon = m_defaultIcons.value(property); + if (!icon.paths().isEmpty()) { + QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(m_object); + qdesigner_internal::FormWindowBase *fwb = qobject_cast(formWindow); + if (fwb) + defaultIcon = fwb->iconCache()->icon(icon); + } + + QMap, PropertySheetPixmapValue> iconPaths = icon.paths(); + + QMap, QtProperty *> subProperties = m_propertyToIconSubProperties.value(property); + QMapIterator, QtProperty *> itSub(subProperties); + while (itSub.hasNext()) { + const QPair pair = itSub.next().key(); + QtVariantProperty *subProperty = variantProperty(itSub.value()); + bool hasPath = iconPaths.contains(pair); + subProperty->setModified(hasPath); + subProperty->setValue(QVariant::fromValue(iconPaths.value(pair))); + subProperty->setAttribute(QLatin1String(defaultResourceAttributeC), + defaultIcon.pixmap(16, 16, pair.first, pair.second)); + } + QtVariantProperty *themeSubProperty = variantProperty(m_propertyToTheme.value(property)); + if (themeSubProperty) { + const QString theme = icon.theme(); + themeSubProperty->setModified(!theme.isEmpty()); + themeSubProperty->setValue(theme); + } + + emit QtVariantPropertyManager::valueChanged(property, QVariant::fromValue(icon)); + emit propertyChanged(property); + + QString toolTip; + const QMap, PropertySheetPixmapValue>::ConstIterator itNormalOff = + iconPaths.constFind(qMakePair(QIcon::Normal, QIcon::Off)); + if (itNormalOff != iconPaths.constEnd()) + toolTip = itNormalOff.value().path(); + property->setToolTip(toolTip); + + return; + } else if (m_pixmapValues.contains(property)) { + if (value.userType() != designerPixmapTypeId()) + return; + + const PropertySheetPixmapValue pixmap = qvariant_cast(value); + + const PropertySheetPixmapValue oldPixmap = m_pixmapValues.value(property); + if (pixmap == oldPixmap) + return; + + m_pixmapValues[property] = pixmap; + + emit QtVariantPropertyManager::valueChanged(property, QVariant::fromValue(pixmap)); + emit propertyChanged(property); + + property->setToolTip(pixmap.path()); + + return; + } else if (m_uintValues.contains(property)) { + if (value.type() != QVariant::UInt && !value.canConvert(QVariant::UInt)) + return; + + const uint v = value.toUInt(0); + + const uint oldValue = m_uintValues.value(property); + if (v == oldValue) + return; + + m_uintValues[property] = v; + + emit QtVariantPropertyManager::valueChanged(property, v); + emit propertyChanged(property); + + return; + } else if (m_longLongValues.contains(property)) { + if (value.type() != QVariant::LongLong && !value.canConvert(QVariant::LongLong)) + return; + + const qlonglong v = value.toLongLong(0); + + const qlonglong oldValue = m_longLongValues.value(property); + if (v == oldValue) + return; + + m_longLongValues[property] = v; + + emit QtVariantPropertyManager::valueChanged(property, v); + emit propertyChanged(property); + + return; + } else if (m_uLongLongValues.contains(property)) { + if (value.type() != QVariant::ULongLong && !value.canConvert(QVariant::ULongLong)) + return; + + qulonglong v = value.toULongLong(0); + + qulonglong oldValue = m_uLongLongValues.value(property); + if (v == oldValue) + return; + + m_uLongLongValues[property] = v; + + emit QtVariantPropertyManager::valueChanged(property, v); + emit propertyChanged(property); + + return; + } else if (m_urlValues.contains(property)) { + if (value.type() != QVariant::Url && !value.canConvert(QVariant::Url)) + return; + + const QUrl v = value.toUrl(); + + const QUrl oldValue = m_urlValues.value(property); + if (v == oldValue) + return; + + m_urlValues[property] = v; + + emit QtVariantPropertyManager::valueChanged(property, v); + emit propertyChanged(property); + + return; + } else if (m_byteArrayValues.contains(property)) { + if (value.type() != QVariant::ByteArray && !value.canConvert(QVariant::ByteArray)) + return; + + const QByteArray v = value.toByteArray(); + + const QByteArray oldValue = m_byteArrayValues.value(property); + if (v == oldValue) + return; + + m_byteArrayValues[property] = v; + + emit QtVariantPropertyManager::valueChanged(property, v); + emit propertyChanged(property); + + return; + } else if (m_stringListValues.contains(property)) { + if (value.type() != QVariant::StringList && !value.canConvert(QVariant::StringList)) + return; + + const QStringList v = value.toStringList(); + + const QStringList oldValue = m_stringListValues.value(property); + if (v == oldValue) + return; + + m_stringListValues[property] = v; + + emit QtVariantPropertyManager::valueChanged(property, v); + emit propertyChanged(property); + + return; + } + switch (m_brushManager.setValue(this, property, value)) { + case BrushPropertyManager::Unchanged: + return; + case BrushPropertyManager::Changed: + emit QtVariantPropertyManager::valueChanged(property, value); + emit propertyChanged(property); + return; + default: + break; + } + m_fontManager.setValue(this, property, value); + QtVariantPropertyManager::setValue(property, value); + if (QtVariantPropertyManager::valueType(property) == QVariant::String) + property->setToolTip(DesignerPropertyManager::value(property).toString()); + else if (QtVariantPropertyManager::valueType(property) == designerStringTypeId()) + property->setToolTip(qvariant_cast(DesignerPropertyManager::value(property)).value()); + else if (QtVariantPropertyManager::valueType(property) == designerKeySequenceTypeId()) + property->setToolTip(qvariant_cast(DesignerPropertyManager::value(property)).value()); + else if (QtVariantPropertyManager::valueType(property) == QVariant::Bool) + property->setToolTip(QtVariantPropertyManager::valueText(property)); +} + +void DesignerPropertyManager::initializeProperty(QtProperty *property) +{ + m_resetMap[property] = false; + + const int type = propertyType(property); + m_fontManager.preInitializeProperty(property, type, m_resetMap); + switch (type) { + case QVariant::Palette: + m_paletteValues[property] = PaletteData(); + break; + case QVariant::String: + m_stringAttributes[property] = ValidationSingleLine; + m_stringFontAttributes[property] = QApplication::font(); + m_stringThemeAttributes[property] = false; + break; + case QVariant::UInt: + m_uintValues[property] = 0; + break; + case QVariant::LongLong: + m_longLongValues[property] = 0; + break; + case QVariant::ULongLong: + m_uLongLongValues[property] = 0; + break; + case QVariant::Url: + m_urlValues[property] = QUrl(); + break; + case QVariant::ByteArray: + m_byteArrayValues[property] = 0; + break; + case QVariant::StringList: + m_stringListValues[property] = QStringList(); + break; + case QVariant::Brush: + m_brushManager.initializeProperty(this, property, enumTypeId()); + break; + default: + if (type == designerFlagTypeId()) { + m_flagValues[property] = FlagData(); + m_propertyToFlags[property] = QList(); + } else if (type == designerAlignmentTypeId()) { + const uint align = Qt::AlignLeft | Qt::AlignVCenter; + m_alignValues[property] = align; + + QtVariantProperty *alignH = addProperty(enumTypeId(), tr("Horizontal")); + QStringList namesH; + namesH << indexHToString(0) << indexHToString(1) << indexHToString(2) << indexHToString(3); + alignH->setAttribute(QLatin1String("enumNames"), namesH); + alignH->setValue(alignToIndexH(align)); + m_propertyToAlignH[property] = alignH; + m_alignHToProperty[alignH] = property; + property->addSubProperty(alignH); + + QtVariantProperty *alignV = addProperty(enumTypeId(), tr("Vertical")); + QStringList namesV; + namesV << indexVToString(0) << indexVToString(1) << indexVToString(2); + alignV->setAttribute(QLatin1String("enumNames"), namesV); + alignV->setValue(alignToIndexV(align)); + m_propertyToAlignV[property] = alignV; + m_alignVToProperty[alignV] = property; + property->addSubProperty(alignV); + } else if (type == designerPixmapTypeId()) { + m_pixmapValues[property] = PropertySheetPixmapValue(); + m_defaultPixmaps[property] = QPixmap(); + } else if (type == designerIconTypeId()) { + m_iconValues[property] = PropertySheetIconValue(); + m_defaultIcons[property] = QIcon(); + + QtVariantProperty *themeProp = addProperty(QVariant::String, tr("Theme")); + themeProp->setAttribute(QLatin1String(themeAttributeC), true); + m_iconSubPropertyToProperty[themeProp] = property; + m_propertyToTheme[property] = themeProp; + m_resetMap[themeProp] = true; + property->addSubProperty(themeProp); + + createIconSubProperty(property, QIcon::Normal, QIcon::Off, tr("Normal Off")); + createIconSubProperty(property, QIcon::Normal, QIcon::On, tr("Normal On")); + createIconSubProperty(property, QIcon::Disabled, QIcon::Off, tr("Disabled Off")); + createIconSubProperty(property, QIcon::Disabled, QIcon::On, tr("Disabled On")); + createIconSubProperty(property, QIcon::Active, QIcon::Off, tr("Active Off")); + createIconSubProperty(property, QIcon::Active, QIcon::On, tr("Active On")); + createIconSubProperty(property, QIcon::Selected, QIcon::Off, tr("Selected Off")); + createIconSubProperty(property, QIcon::Selected, QIcon::On, tr("Selected On")); + } else if (type == designerStringTypeId()) { + PropertySheetStringValue val; + m_stringValues[property] = val; + m_stringAttributes[property] = ValidationMultiLine; + m_stringFontAttributes[property] = QApplication::font(); + m_stringThemeAttributes[property] = false; + + QtVariantProperty *translatable = addProperty(QVariant::Bool, tr("translatable")); + translatable->setValue(val.translatable()); + m_stringToTranslatable[property] = translatable; + m_translatableToString[translatable] = property; + property->addSubProperty(translatable); + + QtVariantProperty *disambiguation = addProperty(QVariant::String, tr("disambiguation")); + disambiguation->setValue(val.disambiguation()); + m_stringToDisambiguation[property] = disambiguation; + m_disambiguationToString[disambiguation] = property; + property->addSubProperty(disambiguation); + + QtVariantProperty *comment = addProperty(QVariant::String, tr("comment")); + comment->setValue(val.comment()); + m_stringToComment[property] = comment; + m_commentToString[comment] = property; + property->addSubProperty(comment); + } else if (type == designerKeySequenceTypeId()) { + PropertySheetKeySequenceValue val; + m_keySequenceValues[property] = val; + + QtVariantProperty *translatable = addProperty(QVariant::Bool, tr("translatable")); + translatable->setValue(val.translatable()); + m_keySequenceToTranslatable[property] = translatable; + m_translatableToKeySequence[translatable] = property; + property->addSubProperty(translatable); + + QtVariantProperty *disambiguation = addProperty(QVariant::String, tr("disambiguation")); + disambiguation->setValue(val.disambiguation()); + m_keySequenceToDisambiguation[property] = disambiguation; + m_disambiguationToKeySequence[disambiguation] = property; + property->addSubProperty(disambiguation); + + QtVariantProperty *comment = addProperty(QVariant::String, tr("comment")); + comment->setValue(val.comment()); + m_keySequenceToComment[property] = comment; + m_commentToKeySequence[comment] = property; + property->addSubProperty(comment); + } + } + + QtVariantPropertyManager::initializeProperty(property); + m_fontManager.postInitializeProperty(this, property, type, DesignerPropertyManager::enumTypeId()); + if (type == QVariant::Double) + setAttribute(property, QLatin1String("decimals"), 6); +} + +void DesignerPropertyManager::createIconSubProperty(QtProperty *iconProperty, QIcon::Mode mode, QIcon::State state, const QString &subName) +{ + QPair pair = qMakePair(mode, state); + QtVariantProperty *subProp = addProperty(DesignerPropertyManager::designerPixmapTypeId(), subName); + m_propertyToIconSubProperties[iconProperty][pair] = subProp; + m_iconSubPropertyToState[subProp] = pair; + m_iconSubPropertyToProperty[subProp] = iconProperty; + m_resetMap[subProp] = true; + iconProperty->addSubProperty(subProp); +} + +void DesignerPropertyManager::uninitializeProperty(QtProperty *property) +{ + m_resetMap.remove(property); + + QListIterator itProp(m_propertyToFlags[property]); + while (itProp.hasNext()) { + QtProperty *prop = itProp.next(); + if (prop) { + delete prop; + m_flagToProperty.remove(prop); + } + } + m_propertyToFlags.remove(property); + m_flagValues.remove(property); + + QtProperty *alignH = m_propertyToAlignH.value(property); + if (alignH) { + delete alignH; + m_alignHToProperty.remove(alignH); + } + QtProperty *alignV = m_propertyToAlignV.value(property); + if (alignV) { + delete alignV; + m_alignVToProperty.remove(alignV); + } + + QtProperty *stringComment = m_stringToComment.value(property); + if (stringComment) { + delete stringComment; + m_commentToString.remove(stringComment); + } + + QtProperty *stringTranslatable = m_stringToTranslatable.value(property); + if (stringTranslatable) { + delete stringTranslatable; + m_translatableToString.remove(stringTranslatable); + } + + QtProperty *stringDisambiguation = m_stringToDisambiguation.value(property); + if (stringDisambiguation) { + delete stringDisambiguation; + m_disambiguationToString.remove(stringDisambiguation); + } + + QtProperty *keySequenceComment = m_keySequenceToComment.value(property); + if (keySequenceComment) { + delete keySequenceComment; + m_commentToKeySequence.remove(keySequenceComment); + } + + QtProperty *keySequenceTranslatable = m_keySequenceToTranslatable.value(property); + if (keySequenceTranslatable) { + delete keySequenceTranslatable; + m_translatableToKeySequence.remove(keySequenceTranslatable); + } + + QtProperty *keySequenceDisambiguation = m_keySequenceToDisambiguation.value(property); + if (keySequenceDisambiguation) { + delete keySequenceDisambiguation; + m_disambiguationToKeySequence.remove(keySequenceDisambiguation); + } + + QtProperty *iconTheme = m_propertyToTheme.value(property); + if (iconTheme) { + delete iconTheme; + m_iconSubPropertyToProperty.remove(iconTheme); + } + + m_propertyToAlignH.remove(property); + m_propertyToAlignV.remove(property); + + m_stringToComment.remove(property); + m_stringToTranslatable.remove(property); + m_stringToDisambiguation.remove(property); + m_stringValues.remove(property); + m_stringAttributes.remove(property); + m_stringFontAttributes.remove(property); + + m_keySequenceToComment.remove(property); + m_keySequenceToTranslatable.remove(property); + m_keySequenceToDisambiguation.remove(property); + m_keySequenceValues.remove(property); + + m_paletteValues.remove(property); + + m_iconValues.remove(property); + m_defaultIcons.remove(property); + + m_pixmapValues.remove(property); + m_defaultPixmaps.remove(property); + + QMap, QtProperty *> iconSubProperties = m_propertyToIconSubProperties.value(property); + QMapIterator, QtProperty *> itIcon(iconSubProperties); + while (itIcon.hasNext()) { + QtProperty *subIcon = itIcon.next().value(); + delete subIcon; + m_iconSubPropertyToState.remove(subIcon); + m_iconSubPropertyToProperty.remove(subIcon); + } + m_propertyToIconSubProperties.remove(property); + m_iconSubPropertyToState.remove(property); + m_iconSubPropertyToProperty.remove(property); + + m_uintValues.remove(property); + m_longLongValues.remove(property); + m_uLongLongValues.remove(property); + m_urlValues.remove(property); + m_byteArrayValues.remove(property); + m_stringListValues.remove(property); + + m_fontManager.uninitializeProperty(property); + m_brushManager.uninitializeProperty(property); + + QtVariantPropertyManager::uninitializeProperty(property); +} + + +bool DesignerPropertyManager::resetFontSubProperty(QtProperty *property) +{ + return m_fontManager.resetFontSubProperty(this, property); +} + +bool DesignerPropertyManager::resetIconSubProperty(QtProperty *property) +{ + QtProperty *iconProperty = m_iconSubPropertyToProperty.value(property); + if (!iconProperty) + return false; + + if (m_pixmapValues.contains(property)) { + QtVariantProperty *pixmapProperty = variantProperty(property); + pixmapProperty->setValue(QVariant::fromValue(PropertySheetPixmapValue())); + return true; + } else if (m_propertyToTheme.contains(iconProperty)) { + QtVariantProperty *themeProperty = variantProperty(property); + themeProperty->setValue(QString()); + return true; + } + return false; +} + +// -------- DesignerEditorFactory +DesignerEditorFactory::DesignerEditorFactory(QDesignerFormEditorInterface *core, QObject *parent) : + QtVariantEditorFactory(parent), + m_resetDecorator(new ResetDecorator(this)), + m_changingPropertyValue(false), + m_core(core), + m_spacing(-1) +{ + connect(m_resetDecorator, SIGNAL(resetProperty(QtProperty*)), this, SIGNAL(resetProperty(QtProperty*))); +} + +DesignerEditorFactory::~DesignerEditorFactory() +{ +} + +void DesignerEditorFactory::setSpacing(int spacing) +{ + m_spacing = spacing; + m_resetDecorator->setSpacing(spacing); +} + +void DesignerEditorFactory::setFormWindowBase(qdesigner_internal::FormWindowBase *fwb) +{ + m_fwb = fwb; + DesignerPixmapCache *cache = 0; + if (fwb) + cache = fwb->pixmapCache(); + QMapIterator itPixmapEditor(m_editorToPixmapProperty); + while (itPixmapEditor.hasNext()) { + PixmapEditor *pe = itPixmapEditor.next().key(); + pe->setPixmapCache(cache); + } + QMapIterator itIconEditor(m_editorToIconProperty); + while (itIconEditor.hasNext()) { + PixmapEditor *pe = itIconEditor.next().key(); + pe->setPixmapCache(cache); + } +} + +void DesignerEditorFactory::connectPropertyManager(QtVariantPropertyManager *manager) +{ + m_resetDecorator->connectPropertyManager(manager); + connect(manager, SIGNAL(attributeChanged(QtProperty*,QString,QVariant)), + this, SLOT(slotAttributeChanged(QtProperty*,QString,QVariant))); + connect(manager, SIGNAL(valueChanged(QtProperty*,QVariant)), + this, SLOT(slotValueChanged(QtProperty*,QVariant))); + connect(manager, SIGNAL(propertyChanged(QtProperty*)), + this, SLOT(slotPropertyChanged(QtProperty*))); + QtVariantEditorFactory::connectPropertyManager(manager); +} + +void DesignerEditorFactory::disconnectPropertyManager(QtVariantPropertyManager *manager) +{ + m_resetDecorator->disconnectPropertyManager(manager); + disconnect(manager, SIGNAL(attributeChanged(QtProperty*,QString,QVariant)), + this, SLOT(slotAttributeChanged(QtProperty*,QString,QVariant))); + disconnect(manager, SIGNAL(valueChanged(QtProperty*,QVariant)), + this, SLOT(slotValueChanged(QtProperty*,QVariant))); + disconnect(manager, SIGNAL(propertyChanged(QtProperty*)), + this, SLOT(slotPropertyChanged(QtProperty*))); + QtVariantEditorFactory::disconnectPropertyManager(manager); +} + +// A helper that calls a setter with a value on a pointer list of editor objects. +// Could use QList instead of EditorContainer/Editor, but that crashes VS 6. +template +static inline void applyToEditors(const EditorContainer &list, void (Editor::*setter)(SetterParameter), const Value &value) +{ + typedef Q_TYPENAME EditorContainer::const_iterator ListIterator; + if (list.empty()) { + return; + } + const ListIterator end = list.constEnd(); + for (ListIterator it = list.constBegin(); it != end; ++it) { + Editor &editor = *(*it); + (editor.*setter)(value); + } +} + +void DesignerEditorFactory::slotAttributeChanged(QtProperty *property, const QString &attribute, const QVariant &value) +{ + QtVariantPropertyManager *manager = propertyManager(property); + const int type = manager->propertyType(property); + if (type == DesignerPropertyManager::designerPixmapTypeId() && attribute == QLatin1String(defaultResourceAttributeC)) { + const QPixmap pixmap = qvariant_cast(value); + applyToEditors(m_pixmapPropertyToEditors.value(property), &PixmapEditor::setDefaultPixmap, pixmap); + } else if (type == DesignerPropertyManager::designerStringTypeId() || type == QVariant::String) { + if (attribute == QLatin1String(validationModesAttributeC)) { + const TextPropertyValidationMode validationMode = static_cast(value.toInt()); + applyToEditors(m_stringPropertyToEditors.value(property), &TextEditor::setTextPropertyValidationMode, validationMode); + } + if (attribute == QLatin1String(fontAttributeC)) { + const QFont font = qvariant_cast(value); + applyToEditors(m_stringPropertyToEditors.value(property), &TextEditor::setRichTextDefaultFont, font); + } + if (attribute == QLatin1String(themeAttributeC)) { + const bool themeEnabled = value.toBool(); + applyToEditors(m_stringPropertyToEditors.value(property), &TextEditor::setIconThemeModeEnabled, themeEnabled); + } + } else if (type == QVariant::Palette && attribute == QLatin1String(superPaletteAttributeC)) { + const QPalette palette = qvariant_cast(value); + applyToEditors(m_palettePropertyToEditors.value(property), &PaletteEditorButton::setSuperPalette, palette); + } +} + +void DesignerEditorFactory::slotPropertyChanged(QtProperty *property) +{ + QtVariantPropertyManager *manager = propertyManager(property); + const int type = manager->propertyType(property); + if (type == DesignerPropertyManager::designerIconTypeId()) { + QPixmap defaultPixmap; + if (!property->isModified()) + defaultPixmap = qvariant_cast(manager->attributeValue(property, QLatin1String(defaultResourceAttributeC))).pixmap(16, 16); + else if (m_fwb) + defaultPixmap = m_fwb->iconCache()->icon(qvariant_cast(manager->value(property))).pixmap(16, 16); + QList editors = m_iconPropertyToEditors.value(property); + QListIterator it(editors); + while (it.hasNext()) { + PixmapEditor *editor = it.next(); + editor->setDefaultPixmap(defaultPixmap); + } + } +} + +void DesignerEditorFactory::slotValueChanged(QtProperty *property, const QVariant &value) +{ + if (m_changingPropertyValue) + return; + + QtVariantPropertyManager *manager = propertyManager(property); + const int type = manager->propertyType(property); + switch (type) { + case QVariant::String: + applyToEditors(m_stringPropertyToEditors.value(property), &TextEditor::setText, value.toString()); + break; + case QVariant::Palette: + applyToEditors(m_palettePropertyToEditors.value(property), &PaletteEditorButton::setPalette, qvariant_cast(value)); + break; + case QVariant::UInt: + applyToEditors(m_uintPropertyToEditors.value(property), &QLineEdit::setText, QString::number(value.toUInt())); + break; + case QVariant::LongLong: + applyToEditors(m_longLongPropertyToEditors.value(property), &QLineEdit::setText, QString::number(value.toLongLong())); + break; + case QVariant::ULongLong: + applyToEditors(m_uLongLongPropertyToEditors.value(property), &QLineEdit::setText, QString::number(value.toULongLong())); + break; + case QVariant::Url: + applyToEditors(m_urlPropertyToEditors.value(property), &TextEditor::setText, value.toUrl().toString()); + break; + case QVariant::ByteArray: + applyToEditors(m_byteArrayPropertyToEditors.value(property), &TextEditor::setText, QString::fromUtf8(value.toByteArray())); + break; + case QVariant::StringList: + applyToEditors(m_stringListPropertyToEditors.value(property), &StringListEditorButton::setStringList, value.toStringList()); + break; + default: + if (type == DesignerPropertyManager::designerIconTypeId()) { + PropertySheetIconValue iconValue = qvariant_cast(value); + const QString theme = iconValue.theme(); + applyToEditors(m_iconPropertyToEditors.value(property), &PixmapEditor::setTheme, iconValue.theme()); + applyToEditors(m_iconPropertyToEditors.value(property), &PixmapEditor::setPath, iconValue.pixmap(QIcon::Normal, QIcon::Off).path()); + } else if (type == DesignerPropertyManager::designerPixmapTypeId()) { + applyToEditors(m_pixmapPropertyToEditors.value(property), &PixmapEditor::setPath, qvariant_cast(value).path()); + } else if (type == DesignerPropertyManager::designerStringTypeId()) { + applyToEditors(m_stringPropertyToEditors.value(property), &TextEditor::setText, qvariant_cast(value).value()); + } else if (type == DesignerPropertyManager::designerKeySequenceTypeId()) { + applyToEditors(m_keySequencePropertyToEditors.value(property), &QtKeySequenceEdit::setKeySequence, qvariant_cast(value).value()); + } + break; + } +} + +TextEditor *DesignerEditorFactory::createTextEditor(QWidget *parent, TextPropertyValidationMode vm, const QString &value) +{ + TextEditor *rc = new TextEditor(m_core, parent); + rc->setText(value); + rc->setSpacing(m_spacing); + rc->setTextPropertyValidationMode(vm); + connect(rc, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + return rc; +} + +QWidget *DesignerEditorFactory::createEditor(QtVariantPropertyManager *manager, QtProperty *property, + QWidget *parent) +{ + QWidget *editor = 0; + const int type = manager->propertyType(property); + switch (type) { + case QVariant::Bool: { + editor = QtVariantEditorFactory::createEditor(manager, property, parent); + QtBoolEdit *boolEdit = qobject_cast(editor); + if (boolEdit) + boolEdit->setTextVisible(false); + } + break; + case QVariant::String: { + const TextPropertyValidationMode tvm = static_cast(manager->attributeValue(property, QLatin1String(validationModesAttributeC)).toInt()); + TextEditor *ed = createTextEditor(parent, tvm, manager->value(property).toString()); + const QVariant richTextDefaultFont = manager->attributeValue(property, QLatin1String(fontAttributeC)); + if (richTextDefaultFont.type() == QVariant::Font) + ed->setRichTextDefaultFont(qvariant_cast(richTextDefaultFont)); + const bool themeEnabled = manager->attributeValue(property, QLatin1String(themeAttributeC)).toBool(); + ed->setIconThemeModeEnabled(themeEnabled); + m_stringPropertyToEditors[property].append(ed); + m_editorToStringProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + connect(ed, SIGNAL(textChanged(QString)), this, SLOT(slotStringTextChanged(QString))); + editor = ed; + } + break; + case QVariant::Palette: { + PaletteEditorButton *ed = new PaletteEditorButton(m_core, qvariant_cast(manager->value(property)), parent); + ed->setSuperPalette(qvariant_cast(manager->attributeValue(property, QLatin1String(superPaletteAttributeC)))); + m_palettePropertyToEditors[property].append(ed); + m_editorToPaletteProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + connect(ed, SIGNAL(paletteChanged(QPalette)), this, SLOT(slotPaletteChanged(QPalette))); + editor = ed; + } + break; + case QVariant::UInt: { + QLineEdit *ed = new QLineEdit(parent); + ed->setValidator(new QULongLongValidator(0, UINT_MAX, ed)); + ed->setText(QString::number(manager->value(property).toUInt())); + m_uintPropertyToEditors[property].append(ed); + m_editorToUintProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + connect(ed, SIGNAL(textChanged(QString)), this, SLOT(slotUintChanged(QString))); + editor = ed; + } + break; + case QVariant::LongLong: { + QLineEdit *ed = new QLineEdit(parent); + ed->setValidator(new QLongLongValidator(ed)); + ed->setText(QString::number(manager->value(property).toLongLong())); + m_longLongPropertyToEditors[property].append(ed); + m_editorToLongLongProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + connect(ed, SIGNAL(textChanged(QString)), this, SLOT(slotLongLongChanged(QString))); + editor = ed; + } + break; + case QVariant::ULongLong: { + QLineEdit *ed = new QLineEdit(parent); + ed->setValidator(new QULongLongValidator(ed)); + ed->setText(QString::number(manager->value(property).toULongLong())); + m_uLongLongPropertyToEditors[property].append(ed); + m_editorToULongLongProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + connect(ed, SIGNAL(textChanged(QString)), this, SLOT(slotULongLongChanged(QString))); + editor = ed; + } + break; + case QVariant::Url: { + TextEditor *ed = createTextEditor(parent, ValidationURL, manager->value(property).toUrl().toString()); + ed->setUpdateMode(TextPropertyEditor::UpdateOnFinished); + m_urlPropertyToEditors[property].append(ed); + m_editorToUrlProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + connect(ed, SIGNAL(textChanged(QString)), this, SLOT(slotUrlChanged(QString))); + editor = ed; + } + break; + case QVariant::ByteArray: { + TextEditor *ed = createTextEditor(parent, ValidationMultiLine, QString::fromUtf8(manager->value(property).toByteArray())); + m_byteArrayPropertyToEditors[property].append(ed); + m_editorToByteArrayProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + connect(ed, SIGNAL(textChanged(QString)), this, SLOT(slotByteArrayChanged(QString))); + editor = ed; + } + break; + case QVariant::StringList: { + StringListEditorButton *ed = new StringListEditorButton(manager->value(property).toStringList(), parent); + m_stringListPropertyToEditors[property].append(ed); + m_editorToStringListProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + connect(ed, SIGNAL(stringListChanged(QStringList)), this, SLOT(slotStringListChanged(QStringList))); + editor = ed; + } + break; + default: + if (type == DesignerPropertyManager::designerPixmapTypeId()) { + PixmapEditor *ed = new PixmapEditor(m_core, parent); + ed->setPixmapCache(m_fwb->pixmapCache()); + ed->setPath(qvariant_cast(manager->value(property)).path()); + ed->setDefaultPixmap(qvariant_cast(manager->attributeValue(property, QLatin1String(defaultResourceAttributeC)))); + ed->setSpacing(m_spacing); + m_pixmapPropertyToEditors[property].append(ed); + m_editorToPixmapProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + connect(ed, SIGNAL(pathChanged(QString)), this, SLOT(slotPixmapChanged(QString))); + editor = ed; + } else if (type == DesignerPropertyManager::designerIconTypeId()) { + PixmapEditor *ed = new PixmapEditor(m_core, parent); + ed->setPixmapCache(m_fwb->pixmapCache()); + ed->setIconThemeModeEnabled(true); + PropertySheetIconValue value = qvariant_cast(manager->value(property)); + ed->setTheme(value.theme()); + ed->setPath(value.pixmap(QIcon::Normal, QIcon::Off).path()); + QPixmap defaultPixmap; + if (!property->isModified()) + defaultPixmap = qvariant_cast(manager->attributeValue(property, QLatin1String(defaultResourceAttributeC))).pixmap(16, 16); + else if (m_fwb) + defaultPixmap = m_fwb->iconCache()->icon(value).pixmap(16, 16); + ed->setDefaultPixmap(defaultPixmap); + ed->setSpacing(m_spacing); + m_iconPropertyToEditors[property].append(ed); + m_editorToIconProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + connect(ed, SIGNAL(pathChanged(QString)), this, SLOT(slotIconChanged(QString))); + connect(ed, SIGNAL(themeChanged(QString)), this, SLOT(slotIconThemeChanged(QString))); + editor = ed; + } else if (type == DesignerPropertyManager::designerStringTypeId()) { + const TextPropertyValidationMode tvm = static_cast(manager->attributeValue(property, QLatin1String(validationModesAttributeC)).toInt()); + TextEditor *ed = createTextEditor(parent, tvm, qvariant_cast(manager->value(property)).value()); + const QVariant richTextDefaultFont = manager->attributeValue(property, QLatin1String(fontAttributeC)); + if (richTextDefaultFont.type() == QVariant::Font) + ed->setRichTextDefaultFont(qvariant_cast(richTextDefaultFont)); + m_stringPropertyToEditors[property].append(ed); + m_editorToStringProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + connect(ed, SIGNAL(textChanged(QString)), this, SLOT(slotStringTextChanged(QString))); + editor = ed; + } else if (type == DesignerPropertyManager::designerKeySequenceTypeId()) { + QtKeySequenceEdit *ed = new QtKeySequenceEdit(parent); + ed->setKeySequence(qvariant_cast(manager->value(property)).value()); + m_keySequencePropertyToEditors[property].append(ed); + m_editorToKeySequenceProperty[ed] = property; + connect(ed, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + connect(ed, SIGNAL(keySequenceChanged(QKeySequence)), this, SLOT(slotKeySequenceChanged(QKeySequence))); + editor = ed; + } else { + editor = QtVariantEditorFactory::createEditor(manager, property, parent); + } + break; + } + return m_resetDecorator->editor(editor, + manager->variantProperty(property)->attributeValue(QLatin1String(resettableAttributeC)).toBool(), + manager, property, parent); +} + +template +bool removeEditor(QObject *object, + QMap > *propertyToEditors, + QMap *editorToProperty) +{ + if (!propertyToEditors) + return false; + if (!editorToProperty) + return false; + QMapIterator it(*editorToProperty); + while (it.hasNext()) { + Editor editor = it.next().key(); + if (editor == object) { + QtProperty *prop = it.value(); + (*propertyToEditors)[prop].removeAll(editor); + if ((*propertyToEditors)[prop].count() == 0) + propertyToEditors->remove(prop); + editorToProperty->remove(editor); + return true; + } + } + return false; +} + +void DesignerEditorFactory::slotEditorDestroyed(QObject *object) +{ + if (removeEditor(object, &m_stringPropertyToEditors, &m_editorToStringProperty)) + return; + if (removeEditor(object, &m_keySequencePropertyToEditors, &m_editorToKeySequenceProperty)) + return; + if (removeEditor(object, &m_palettePropertyToEditors, &m_editorToPaletteProperty)) + return; + if (removeEditor(object, &m_pixmapPropertyToEditors, &m_editorToPixmapProperty)) + return; + if (removeEditor(object, &m_iconPropertyToEditors, &m_editorToIconProperty)) + return; + if (removeEditor(object, &m_uintPropertyToEditors, &m_editorToUintProperty)) + return; + if (removeEditor(object, &m_longLongPropertyToEditors, &m_editorToLongLongProperty)) + return; + if (removeEditor(object, &m_uLongLongPropertyToEditors, &m_editorToULongLongProperty)) + return; + if (removeEditor(object, &m_urlPropertyToEditors, &m_editorToUrlProperty)) + return; + if (removeEditor(object, &m_byteArrayPropertyToEditors, &m_editorToByteArrayProperty)) + return; + if (removeEditor(object, &m_stringListPropertyToEditors, &m_editorToStringListProperty)) + return; +} + +template +bool updateManager(QtVariantEditorFactory *factory, bool *changingPropertyValue, + const QMap &editorToProperty, QWidget *editor, const QVariant &value) +{ + if (!editor) + return false; + QMapIterator it(editorToProperty); + while (it.hasNext()) { + if (it.next().key() == editor) { + QtProperty *prop = it.value(); + QtVariantPropertyManager *manager = factory->propertyManager(prop); + *changingPropertyValue = true; + manager->variantProperty(prop)->setValue(value); + *changingPropertyValue = false; + return true; + } + } + return false; +} + +void DesignerEditorFactory::slotUintChanged(const QString &value) +{ + updateManager(this, &m_changingPropertyValue, m_editorToUintProperty, qobject_cast(sender()), value.toUInt()); +} + +void DesignerEditorFactory::slotLongLongChanged(const QString &value) +{ + updateManager(this, &m_changingPropertyValue, m_editorToLongLongProperty, qobject_cast(sender()), value.toLongLong()); +} + +void DesignerEditorFactory::slotULongLongChanged(const QString &value) +{ + updateManager(this, &m_changingPropertyValue, m_editorToULongLongProperty, qobject_cast(sender()), value.toULongLong()); +} + +void DesignerEditorFactory::slotUrlChanged(const QString &value) +{ + updateManager(this, &m_changingPropertyValue, m_editorToUrlProperty, qobject_cast(sender()), QUrl(value)); +} + +void DesignerEditorFactory::slotByteArrayChanged(const QString &value) +{ + updateManager(this, &m_changingPropertyValue, m_editorToByteArrayProperty, qobject_cast(sender()), value.toUtf8()); +} + +void DesignerEditorFactory::slotStringTextChanged(const QString &value) +{ + QMapIterator it(m_editorToStringProperty); + while (it.hasNext()) { + if (it.next().key() == sender()) { + QtProperty *prop = it.value(); + QtVariantPropertyManager *manager = propertyManager(prop); + QtVariantProperty *varProp = manager->variantProperty(prop); + QVariant val = varProp->value(); + if (val.userType() == DesignerPropertyManager::designerStringTypeId()) { + PropertySheetStringValue strVal = qvariant_cast(val); + strVal.setValue(value); + // Disable translation if no translation subproperties exist. + if (varProp->subProperties().empty()) + strVal.setTranslatable(false); + val = QVariant::fromValue(strVal); + } else { + val = QVariant(value); + } + m_changingPropertyValue = true; + manager->variantProperty(prop)->setValue(val); + m_changingPropertyValue = false; + } + } +} + +void DesignerEditorFactory::slotKeySequenceChanged(const QKeySequence &value) +{ + QMapIterator it(m_editorToKeySequenceProperty); + while (it.hasNext()) { + if (it.next().key() == sender()) { + QtProperty *prop = it.value(); + QtVariantPropertyManager *manager = propertyManager(prop); + QtVariantProperty *varProp = manager->variantProperty(prop); + QVariant val = varProp->value(); + if (val.userType() == DesignerPropertyManager::designerKeySequenceTypeId()) { + PropertySheetKeySequenceValue keyVal = qvariant_cast(val); + keyVal.setValue(value); + val = QVariant::fromValue(keyVal); + } else { + val = QVariant::fromValue(value); + } + m_changingPropertyValue = true; + manager->variantProperty(prop)->setValue(val); + m_changingPropertyValue = false; + } + } +} + +void DesignerEditorFactory::slotPaletteChanged(const QPalette &value) +{ + updateManager(this, &m_changingPropertyValue, m_editorToPaletteProperty, qobject_cast(sender()), QVariant::fromValue(value)); +} + +void DesignerEditorFactory::slotPixmapChanged(const QString &value) +{ + updateManager(this, &m_changingPropertyValue, m_editorToPixmapProperty, qobject_cast(sender()), + QVariant::fromValue(PropertySheetPixmapValue(value))); +} + +void DesignerEditorFactory::slotIconChanged(const QString &value) +{ + updateManager(this, &m_changingPropertyValue, m_editorToIconProperty, qobject_cast(sender()), + QVariant::fromValue(PropertySheetIconValue(PropertySheetPixmapValue(value)))); +} + +void DesignerEditorFactory::slotIconThemeChanged(const QString &value) +{ + PropertySheetIconValue icon; + icon.setTheme(value); + updateManager(this, &m_changingPropertyValue, m_editorToIconProperty, qobject_cast(sender()), + QVariant::fromValue(icon)); +} + +void DesignerEditorFactory::slotStringListChanged(const QStringList &value) +{ + updateManager(this, &m_changingPropertyValue, m_editorToStringListProperty, qobject_cast(sender()), QVariant::fromValue(value)); +} + +ResetDecorator::~ResetDecorator() +{ + QList editors = m_resetWidgetToProperty.keys(); + QListIterator it(editors); + while (it.hasNext()) + delete it.next(); +} + +void ResetDecorator::connectPropertyManager(QtAbstractPropertyManager *manager) +{ + connect(manager, SIGNAL(propertyChanged(QtProperty*)), + this, SLOT(slotPropertyChanged(QtProperty*))); +} + +void ResetDecorator::disconnectPropertyManager(QtAbstractPropertyManager *manager) +{ + disconnect(manager, SIGNAL(propertyChanged(QtProperty*)), + this, SLOT(slotPropertyChanged(QtProperty*))); +} + +void ResetDecorator::setSpacing(int spacing) +{ + m_spacing = spacing; +} + +QWidget *ResetDecorator::editor(QWidget *subEditor, bool resettable, QtAbstractPropertyManager *manager, QtProperty *property, + QWidget *parent) +{ + Q_UNUSED(manager) + + ResetWidget *resetWidget = 0; + if (resettable) { + resetWidget = new ResetWidget(property, parent); + resetWidget->setSpacing(m_spacing); + resetWidget->setResetEnabled(property->isModified()); + resetWidget->setValueText(property->valueText()); + resetWidget->setValueIcon(property->valueIcon()); + resetWidget->setAutoFillBackground(true); + connect(resetWidget, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*))); + connect(resetWidget, SIGNAL(resetProperty(QtProperty*)), this, SIGNAL(resetProperty(QtProperty*))); + m_createdResetWidgets[property].append(resetWidget); + m_resetWidgetToProperty[resetWidget] = property; + } + if (subEditor) { + if (resetWidget) { + subEditor->setParent(resetWidget); + resetWidget->setWidget(subEditor); + } + } + if (resetWidget) + return resetWidget; + return subEditor; +} + +void ResetDecorator::slotPropertyChanged(QtProperty *property) +{ + QMap >::ConstIterator prIt = m_createdResetWidgets.constFind(property); + if (prIt == m_createdResetWidgets.constEnd()) + return; + + const QList editors = prIt.value(); + const QList::ConstIterator cend = editors.constEnd(); + for (QList::ConstIterator itEditor = editors.constBegin(); itEditor != cend; ++itEditor) { + ResetWidget *widget = *itEditor; + widget->setResetEnabled(property->isModified()); + widget->setValueText(property->valueText()); + widget->setValueIcon(property->valueIcon()); + } +} + +void ResetDecorator::slotEditorDestroyed(QObject *object) +{ + const QMap::ConstIterator rcend = m_resetWidgetToProperty.constEnd(); + for (QMap::ConstIterator itEditor = m_resetWidgetToProperty.constBegin(); itEditor != rcend; ++itEditor) { + if (itEditor.key() == object) { + ResetWidget *editor = itEditor.key(); + QtProperty *property = itEditor.value(); + m_resetWidgetToProperty.remove(editor); + m_createdResetWidgets[property].removeAll(editor); + if (m_createdResetWidgets[property].isEmpty()) + m_createdResetWidgets.remove(property); + return; + } + } +} + +} + +QT_END_NAMESPACE + +#include "designerpropertymanager.moc" diff --git a/src/designer/src/components/propertyeditor/designerpropertymanager.h b/src/designer/src/components/propertyeditor/designerpropertymanager.h new file mode 100644 index 000000000..4f4bb3c17 --- /dev/null +++ b/src/designer/src/components/propertyeditor/designerpropertymanager.h @@ -0,0 +1,315 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DESIGNERPROPERTYMANAGER_H +#define DESIGNERPROPERTYMANAGER_H + +#include "qtvariantproperty.h" +#include "brushpropertymanager.h" +#include "fontpropertymanager.h" + +#include +#include + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +typedef QPair DesignerIntPair; +typedef QList DesignerFlagList; + +class QDesignerFormEditorInterface; +class QLineEdit; +class QUrl; +class QtKeySequenceEdit; + +namespace qdesigner_internal +{ + +class ResetWidget; + +class TextEditor; +class PaletteEditorButton; +class PixmapEditor; +class StringListEditorButton; +class FormWindowBase; + +class ResetDecorator : public QObject +{ + Q_OBJECT +public: + ResetDecorator(QObject *parent = 0) : QObject(parent), m_spacing(-1) {} + ~ResetDecorator(); + + void connectPropertyManager(QtAbstractPropertyManager *manager); + QWidget *editor(QWidget *subEditor, bool resettable, QtAbstractPropertyManager *manager, QtProperty *property, + QWidget *parent); + void disconnectPropertyManager(QtAbstractPropertyManager *manager); + void setSpacing(int spacing); +signals: + void resetProperty(QtProperty *property); +private slots: + void slotPropertyChanged(QtProperty *property); + void slotEditorDestroyed(QObject *object); +private: + QMap > m_createdResetWidgets; + QMap m_resetWidgetToProperty; + int m_spacing; +}; + +class DesignerPropertyManager : public QtVariantPropertyManager +{ + Q_OBJECT +public: + explicit DesignerPropertyManager(QDesignerFormEditorInterface *core, QObject *parent = 0); + ~DesignerPropertyManager(); + + virtual QStringList attributes(int propertyType) const; + virtual int attributeType(int propertyType, const QString &attribute) const; + + virtual QVariant attributeValue(const QtProperty *property, const QString &attribute) const; + virtual bool isPropertyTypeSupported(int propertyType) const; + virtual QVariant value(const QtProperty *property) const; + virtual int valueType(int propertyType) const; + virtual QString valueText(const QtProperty *property) const; + virtual QIcon valueIcon(const QtProperty *property) const; + + bool resetFontSubProperty(QtProperty *property); + bool resetIconSubProperty(QtProperty *subProperty); + + void reloadResourceProperties(); + + static int designerFlagTypeId(); + static int designerFlagListTypeId(); + static int designerAlignmentTypeId(); + static int designerPixmapTypeId(); + static int designerIconTypeId(); + static int designerStringTypeId(); + static int designerKeySequenceTypeId(); + + void setObject(QObject *object) { m_object = object; } + +public Q_SLOTS: + virtual void setAttribute(QtProperty *property, + const QString &attribute, const QVariant &value); + virtual void setValue(QtProperty *property, const QVariant &value); +Q_SIGNALS: + // sourceOfChange - a subproperty (or just property) which caused a change + //void valueChanged(QtProperty *property, const QVariant &value, QtProperty *sourceOfChange); + void valueChanged(QtProperty *property, const QVariant &value, bool enableSubPropertyHandling); +protected: + virtual void initializeProperty(QtProperty *property); + virtual void uninitializeProperty(QtProperty *property); +private Q_SLOTS: + void slotValueChanged(QtProperty *property, const QVariant &value); + void slotPropertyDestroyed(QtProperty *property); +private: + void createIconSubProperty(QtProperty *iconProperty, QIcon::Mode mode, QIcon::State state, const QString &subName); + + typedef QMap PropertyBoolMap; + PropertyBoolMap m_resetMap; + + int bitCount(int mask) const; + struct FlagData + { + FlagData() : val(0) {} + uint val; + DesignerFlagList flags; + QList values; + }; + typedef QMap PropertyFlagDataMap; + PropertyFlagDataMap m_flagValues; + typedef QMap > PropertyToPropertyListMap; + PropertyToPropertyListMap m_propertyToFlags; + QMap m_flagToProperty; + + int alignToIndexH(uint align) const; + int alignToIndexV(uint align) const; + uint indexHToAlign(int idx) const; + uint indexVToAlign(int idx) const; + QString indexHToString(int idx) const; + QString indexVToString(int idx) const; + QMap m_alignValues; + typedef QMap PropertyToPropertyMap; + PropertyToPropertyMap m_propertyToAlignH; + PropertyToPropertyMap m_propertyToAlignV; + PropertyToPropertyMap m_alignHToProperty; + PropertyToPropertyMap m_alignVToProperty; + + QMap, QtProperty *> > m_propertyToIconSubProperties; + QMap > m_iconSubPropertyToState; + PropertyToPropertyMap m_iconSubPropertyToProperty; + PropertyToPropertyMap m_propertyToTheme; + + QMap m_stringValues; + QMap m_stringToComment; + QMap m_stringToTranslatable; + QMap m_stringToDisambiguation; + + QMap m_commentToString; + QMap m_translatableToString; + QMap m_disambiguationToString; + + QMap m_keySequenceValues; + QMap m_keySequenceToComment; + QMap m_keySequenceToTranslatable; + QMap m_keySequenceToDisambiguation; + + QMap m_commentToKeySequence; + QMap m_translatableToKeySequence; + QMap m_disambiguationToKeySequence; + + struct PaletteData + { + QPalette val; + QPalette superPalette; + }; + typedef QMap PropertyPaletteDataMap; + PropertyPaletteDataMap m_paletteValues; + + QMap m_pixmapValues; + QMap m_iconValues; + + QMap m_uintValues; + QMap m_longLongValues; + QMap m_uLongLongValues; + QMap m_urlValues; + QMap m_byteArrayValues; + QMap m_stringListValues; + + typedef QMap PropertyIntMap; + PropertyIntMap m_stringAttributes; + typedef QMap PropertyFontMap; + PropertyFontMap m_stringFontAttributes; + PropertyBoolMap m_stringThemeAttributes; + + BrushPropertyManager m_brushManager; + FontPropertyManager m_fontManager; + + QMap m_defaultPixmaps; + QMap m_defaultIcons; + + bool m_changingSubValue; + QDesignerFormEditorInterface *m_core; + + QObject *m_object; + + QtProperty *m_sourceOfChange; +}; + +class DesignerEditorFactory : public QtVariantEditorFactory +{ + Q_OBJECT +public: + explicit DesignerEditorFactory(QDesignerFormEditorInterface *core, QObject *parent = 0); + ~DesignerEditorFactory(); + void setSpacing(int spacing); + void setFormWindowBase(FormWindowBase *fwb); +signals: + void resetProperty(QtProperty *property); +protected: + void connectPropertyManager(QtVariantPropertyManager *manager); + QWidget *createEditor(QtVariantPropertyManager *manager, QtProperty *property, + QWidget *parent); + void disconnectPropertyManager(QtVariantPropertyManager *manager); +private slots: + void slotEditorDestroyed(QObject *object); + void slotAttributeChanged(QtProperty *property, const QString &attribute, const QVariant &value); + void slotPropertyChanged(QtProperty *property); + void slotValueChanged(QtProperty *property, const QVariant &value); + void slotStringTextChanged(const QString &value); + void slotKeySequenceChanged(const QKeySequence &value); + void slotPaletteChanged(const QPalette &value); + void slotPixmapChanged(const QString &value); + void slotIconChanged(const QString &value); + void slotIconThemeChanged(const QString &value); + void slotUintChanged(const QString &value); + void slotLongLongChanged(const QString &value); + void slotULongLongChanged(const QString &value); + void slotUrlChanged(const QString &value); + void slotByteArrayChanged(const QString &value); + void slotStringListChanged(const QStringList &value); +private: + TextEditor *createTextEditor(QWidget *parent, TextPropertyValidationMode vm, const QString &value); + + ResetDecorator *m_resetDecorator; + bool m_changingPropertyValue; + QDesignerFormEditorInterface *m_core; + FormWindowBase *m_fwb; + + int m_spacing; + + QMap > m_stringPropertyToEditors; + QMap m_editorToStringProperty; + QMap > m_keySequencePropertyToEditors; + QMap m_editorToKeySequenceProperty; + QMap > m_palettePropertyToEditors; + QMap m_editorToPaletteProperty; + QMap > m_pixmapPropertyToEditors; + QMap m_editorToPixmapProperty; + QMap > m_iconPropertyToEditors; + QMap m_editorToIconProperty; + QMap > m_uintPropertyToEditors; + QMap m_editorToUintProperty; + QMap > m_longLongPropertyToEditors; + QMap m_editorToLongLongProperty; + QMap > m_uLongLongPropertyToEditors; + QMap m_editorToULongLongProperty; + QMap > m_urlPropertyToEditors; + QMap m_editorToUrlProperty; + QMap > m_byteArrayPropertyToEditors; + QMap m_editorToByteArrayProperty; + QMap > m_stringListPropertyToEditors; + QMap m_editorToStringListProperty; +}; + +} + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(DesignerIntPair) +Q_DECLARE_METATYPE(DesignerFlagList) + +#endif + diff --git a/src/designer/src/components/propertyeditor/fontmapping.xml b/src/designer/src/components/propertyeditor/fontmapping.xml new file mode 100644 index 000000000..cbd68b8db --- /dev/null +++ b/src/designer/src/components/propertyeditor/fontmapping.xml @@ -0,0 +1,73 @@ + + + + + + +]> + + +DejaVu SansDejaVu Sans [&qe;] +DejaVu SansDejaVu Sans [&qe;] +DejaVu SansDejaVu Sans [&qe;] +DejaVu SansDejaVu Sans [&qe;] +DejaVu Sans MonoDejaVu Sans Mono [&qe;] +DejaVu Sans MonoDejaVu Sans Mono [&qe;] +DejaVu Sans MonoDejaVu Sans Mono [&qe;] +DejaVu Sans MonoDejaVu Sans Mono [&qe;] +DejaVu SerifDejaVu Serif [&qe;] +DejaVu SerifDejaVu Serif [&qe;] +DejaVu SerifDejaVu Serif [&qe;] +DejaVu SerifDejaVu Serif [&qe;] +Bitstream Vera SansBitstream Vera Sans [&qe;] +Bitstream Vera SansBitstream Vera Sans [&qe;] +Bitstream Vera SansBitstream Vera Sans [&qe;] +Bitstream Vera SansBitstream Vera Sans [&qe;] +Bitstream Vera Sans MonoBitstream Vera Sans Mono [&qe;] +Bitstream Vera Sans MonoBitstream Vera Sans Mono [&qe;] +Bitstream Vera Sans MonoBitstream Vera Sans Mono [&qe;] +Bitstream Vera Sans MonoBitstream Vera Sans Mono [&qe;] +Bitstream Vera SerifBitstream Vera Serif [&qe;] +Bitstream Vera SerifBitstream Vera Serif [&qe;] + diff --git a/src/designer/src/components/propertyeditor/fontpropertymanager.cpp b/src/designer/src/components/propertyeditor/fontpropertymanager.cpp new file mode 100644 index 000000000..d04bfe6e2 --- /dev/null +++ b/src/designer/src/components/propertyeditor/fontpropertymanager.cpp @@ -0,0 +1,377 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "fontpropertymanager.h" +#include "qtpropertymanager.h" +#include "qtvariantproperty.h" +#include "qtpropertybrowserutils_p.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + + static const char *aliasingC[] = { + QT_TRANSLATE_NOOP("FontPropertyManager", "PreferDefault"), + QT_TRANSLATE_NOOP("FontPropertyManager", "NoAntialias"), + QT_TRANSLATE_NOOP("FontPropertyManager", "PreferAntialias") + }; + + FontPropertyManager::FontPropertyManager() : + m_createdFontProperty(0) + { + const int nameCount = sizeof(aliasingC)/sizeof(const char *); + for (int i = 0; i < nameCount; i++) + m_aliasingEnumNames.push_back(QCoreApplication::translate("FontPropertyManager", aliasingC[i])); + + QString errorMessage; + if (!readFamilyMapping(&m_familyMappings, &errorMessage)) { + designerWarning(errorMessage); + } + + } + + void FontPropertyManager::preInitializeProperty(QtProperty *property, + int type, + ResetMap &resetMap) + { + if (m_createdFontProperty) { + PropertyToSubPropertiesMap::iterator it = m_propertyToFontSubProperties.find(m_createdFontProperty); + if (it == m_propertyToFontSubProperties.end()) + it = m_propertyToFontSubProperties.insert(m_createdFontProperty, PropertyList()); + const int index = it.value().size(); + m_fontSubPropertyToFlag.insert(property, index); + it.value().push_back(property); + m_fontSubPropertyToProperty[property] = m_createdFontProperty; + resetMap[property] = true; + } + + if (type == QVariant::Font) + m_createdFontProperty = property; + } + + // Map the font family names to display names retrieved from the XML configuration + static QStringList designerFamilyNames(QStringList families, const FontPropertyManager::NameMap &nm) + { + if (nm.empty()) + return families; + + const FontPropertyManager::NameMap::const_iterator ncend = nm.constEnd(); + const QStringList::iterator end = families.end(); + for (QStringList::iterator it = families.begin(); it != end; ++it) { + const FontPropertyManager::NameMap::const_iterator nit = nm.constFind(*it); + if (nit != ncend) + *it = nit.value(); + } + return families; + } + + void FontPropertyManager::postInitializeProperty(QtVariantPropertyManager *vm, + QtProperty *property, + int type, + int enumTypeId) + { + if (type != QVariant::Font) + return; + + // This will cause a recursion + QtVariantProperty *antialiasing = vm->addProperty(enumTypeId, QCoreApplication::translate("FontPropertyManager", "Antialiasing")); + const QFont font = qvariant_cast(vm->variantProperty(property)->value()); + + antialiasing->setAttribute(QLatin1String("enumNames"), m_aliasingEnumNames); + antialiasing->setValue(antialiasingToIndex(font.styleStrategy())); + property->addSubProperty(antialiasing); + + m_propertyToAntialiasing[property] = antialiasing; + m_antialiasingToProperty[antialiasing] = property; + // Fiddle family names + if (!m_familyMappings.empty()) { + const PropertyToSubPropertiesMap::iterator it = m_propertyToFontSubProperties.find(m_createdFontProperty); + QtVariantProperty *familyProperty = vm->variantProperty(it.value().front()); + const QString enumNamesAttribute = QLatin1String("enumNames"); + QStringList plainFamilyNames = familyProperty->attributeValue(enumNamesAttribute).toStringList(); + // Did someone load fonts or something? + if (m_designerFamilyNames.size() != plainFamilyNames.size()) + m_designerFamilyNames = designerFamilyNames(plainFamilyNames, m_familyMappings); + familyProperty->setAttribute(enumNamesAttribute, m_designerFamilyNames); + } + // Next + m_createdFontProperty = 0; + } + + bool FontPropertyManager::uninitializeProperty(QtProperty *property) + { + const PropertyToPropertyMap::iterator ait = m_propertyToAntialiasing.find(property); + if (ait != m_propertyToAntialiasing.end()) { + QtProperty *antialiasing = ait.value(); + m_antialiasingToProperty.remove(antialiasing); + m_propertyToAntialiasing.erase(ait); + delete antialiasing; + } + + PropertyToSubPropertiesMap::iterator sit = m_propertyToFontSubProperties.find(property); + if (sit == m_propertyToFontSubProperties.end()) + return false; + + m_propertyToFontSubProperties.erase(sit); + m_fontSubPropertyToFlag.remove(property); + m_fontSubPropertyToProperty.remove(property); + + return true; + } + + void FontPropertyManager::slotPropertyDestroyed(QtProperty *property) + { + removeAntialiasingProperty(property); + } + + void FontPropertyManager::removeAntialiasingProperty(QtProperty *property) + { + const PropertyToPropertyMap::iterator ait = m_antialiasingToProperty.find(property); + if (ait == m_antialiasingToProperty.end()) + return; + m_propertyToAntialiasing[ait.value()] = 0; + m_antialiasingToProperty.erase(ait); + } + + bool FontPropertyManager::resetFontSubProperty(QtVariantPropertyManager *vm, QtProperty *property) + { + const PropertyToPropertyMap::iterator it = m_fontSubPropertyToProperty.find(property); + if (it == m_fontSubPropertyToProperty.end()) + return false; + + QtVariantProperty *fontProperty = vm->variantProperty(it.value()); + + QVariant v = fontProperty->value(); + QFont font = qvariant_cast(v); + unsigned mask = font.resolve(); + const unsigned flag = fontFlag(m_fontSubPropertyToFlag.value(property)); + + mask &= ~flag; + font.resolve(mask); + v.setValue(font); + fontProperty->setValue(v); + return true; + } + + int FontPropertyManager::antialiasingToIndex(QFont::StyleStrategy antialias) + { + switch (antialias) { + case QFont::PreferDefault: return 0; + case QFont::NoAntialias: return 1; + case QFont::PreferAntialias: return 2; + default: break; + } + return 0; + } + + QFont::StyleStrategy FontPropertyManager::indexToAntialiasing(int idx) + { + switch (idx) { + case 0: return QFont::PreferDefault; + case 1: return QFont::NoAntialias; + case 2: return QFont::PreferAntialias; + } + return QFont::PreferDefault; + } + + unsigned FontPropertyManager::fontFlag(int idx) + { + switch (idx) { + case 0: return QFont::FamilyResolved; + case 1: return QFont::SizeResolved; + case 2: return QFont::WeightResolved; + case 3: return QFont::StyleResolved; + case 4: return QFont::UnderlineResolved; + case 5: return QFont::StrikeOutResolved; + case 6: return QFont::KerningResolved; + case 7: return QFont::StyleStrategyResolved; + } + return 0; + } + + FontPropertyManager::ValueChangedResult FontPropertyManager::valueChanged(QtVariantPropertyManager *vm, QtProperty *property, const QVariant &value) + { + QtProperty *antialiasingProperty = m_antialiasingToProperty.value(property, 0); + if (!antialiasingProperty) { + if (m_propertyToFontSubProperties.contains(property)) { + updateModifiedState(property, value); + } + return NoMatch; + } + + QtVariantProperty *fontProperty = vm->variantProperty(antialiasingProperty); + const QFont::StyleStrategy newValue = indexToAntialiasing(value.toInt()); + + QFont font = qvariant_cast(fontProperty->value()); + const QFont::StyleStrategy oldValue = font.styleStrategy(); + if (newValue == oldValue) + return Unchanged; + + font.setStyleStrategy(newValue); + fontProperty->setValue(QVariant::fromValue(font)); + return Changed; + } + + void FontPropertyManager::updateModifiedState(QtProperty *property, const QVariant &value) + { + const PropertyToSubPropertiesMap::iterator it = m_propertyToFontSubProperties.find(property); + if (it == m_propertyToFontSubProperties.end()) + return; + + const PropertyList &subProperties = it.value(); + + QFont font = qvariant_cast(value); + const unsigned mask = font.resolve(); + + const int count = subProperties.size(); + for (int index = 0; index < count; index++) { + const unsigned flag = fontFlag(index); + subProperties.at(index)->setModified(mask & flag); + } + } + + void FontPropertyManager::setValue(QtVariantPropertyManager *vm, QtProperty *property, const QVariant &value) + { + updateModifiedState(property, value); + + if (QtProperty *antialiasingProperty = m_propertyToAntialiasing.value(property, 0)) { + QtVariantProperty *antialiasing = vm->variantProperty(antialiasingProperty); + if (antialiasing) { + QFont font = qvariant_cast(value); + antialiasing->setValue(antialiasingToIndex(font.styleStrategy())); + } + } + } + + /* Parse a mappings file of the form: + * + * DejaVu SansDejaVu Sans [CE] + * ... which is used to display on which platforms fonts are available.*/ + + static const char *rootTagC = "fontmappings"; + static const char *mappingTagC = "mapping"; + static const char *familyTagC = "family"; + static const char *displayTagC = "display"; + + static QString msgXmlError(const QXmlStreamReader &r, const QString& fileName) + { + return QString::fromUtf8("An error has been encountered at line %1 of %2: %3:").arg(r.lineNumber()).arg(fileName, r.errorString()); + } + + /* Switch stages when encountering a start element (state table) */ + enum ParseStage { ParseBeginning, ParseWithinRoot, ParseWithinMapping, ParseWithinFamily, + ParseWithinDisplay, ParseError }; + + static ParseStage nextStage(ParseStage currentStage, const QStringRef &startElement) + { + switch (currentStage) { + case ParseBeginning: + return startElement == QLatin1String(rootTagC) ? ParseWithinRoot : ParseError; + case ParseWithinRoot: + case ParseWithinDisplay: // Next mapping, was in + return startElement == QLatin1String(mappingTagC) ? ParseWithinMapping : ParseError; + case ParseWithinMapping: + return startElement == QLatin1String(familyTagC) ? ParseWithinFamily : ParseError; + case ParseWithinFamily: + return startElement == QLatin1String(displayTagC) ? ParseWithinDisplay : ParseError; + case ParseError: + break; + } + return ParseError; + } + + bool FontPropertyManager::readFamilyMapping(NameMap *rc, QString *errorMessage) + { + rc->clear(); + const QString fileName = QLatin1String(":/trolltech/propertyeditor/fontmapping.xml"); + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly)) { + *errorMessage = QString::fromUtf8("Unable to open %1: %2").arg(fileName, file.errorString()); + return false; + } + + QXmlStreamReader reader(&file); + QXmlStreamReader::TokenType token; + + QString family; + ParseStage stage = ParseBeginning; + do { + token = reader.readNext(); + switch (token) { + case QXmlStreamReader::Invalid: + *errorMessage = msgXmlError(reader, fileName); + return false; + case QXmlStreamReader::StartElement: + stage = nextStage(stage, reader.name()); + switch (stage) { + case ParseError: + reader.raiseError(QString::fromUtf8("Unexpected element <%1>.").arg(reader.name().toString())); + *errorMessage = msgXmlError(reader, fileName); + return false; + case ParseWithinFamily: + family = reader.readElementText(); + break; + case ParseWithinDisplay: + rc->insert(family, reader.readElementText()); + break; + default: + break; + } + default: + break; + } + } while (token != QXmlStreamReader::EndDocument); + return true; + } + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/propertyeditor/fontpropertymanager.h b/src/designer/src/components/propertyeditor/fontpropertymanager.h new file mode 100644 index 000000000..2154186b7 --- /dev/null +++ b/src/designer/src/components/propertyeditor/fontpropertymanager.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FONTPROPERTYMANAGER_H +#define FONTPROPERTYMANAGER_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QtProperty; +class QtVariantPropertyManager; + +class QString; +class QVariant; + +namespace qdesigner_internal { + +/* FontPropertyManager: A mixin for DesignerPropertyManager that manages font + * properties. Adds an antialiasing subproperty and reset flags/mask handling + * for the other subproperties. It also modifies the font family + * enumeration names, which it reads from an XML mapping file that + * contains annotations indicating the platform the font is available on. */ + +class FontPropertyManager { + Q_DISABLE_COPY(FontPropertyManager) + +public: + FontPropertyManager(); + + typedef QMap ResetMap; + typedef QMap NameMap; + + // Call before QtVariantPropertyManager::initializeProperty. + void preInitializeProperty(QtProperty *property, int type, ResetMap &resetMap); + // Call after QtVariantPropertyManager::initializeProperty. This will trigger + // a recursion for the sub properties + void postInitializeProperty(QtVariantPropertyManager *vm, QtProperty *property, int type, int enumTypeId); + + bool uninitializeProperty(QtProperty *property); + + // Call from QtPropertyManager's propertyDestroyed signal + void slotPropertyDestroyed(QtProperty *property); + + bool resetFontSubProperty(QtVariantPropertyManager *vm, QtProperty *subProperty); + + // Call from slotValueChanged(). + enum ValueChangedResult { NoMatch, Unchanged, Changed }; + ValueChangedResult valueChanged(QtVariantPropertyManager *vm, QtProperty *property, const QVariant &value); + + // Call from setValue() before calling setValue() on QtVariantPropertyManager. + void setValue(QtVariantPropertyManager *vm, QtProperty *property, const QVariant &value); + + static bool readFamilyMapping(NameMap *rc, QString *errorMessage); + +private: + typedef QMap PropertyToPropertyMap; + typedef QList PropertyList; + typedef QMap PropertyToSubPropertiesMap; + + void removeAntialiasingProperty(QtProperty *); + void updateModifiedState(QtProperty *property, const QVariant &value); + static int antialiasingToIndex(QFont::StyleStrategy antialias); + static QFont::StyleStrategy indexToAntialiasing(int idx); + static unsigned fontFlag(int idx); + + PropertyToPropertyMap m_propertyToAntialiasing; + PropertyToPropertyMap m_antialiasingToProperty; + + PropertyToSubPropertiesMap m_propertyToFontSubProperties; + QMap m_fontSubPropertyToFlag; + PropertyToPropertyMap m_fontSubPropertyToProperty; + QtProperty *m_createdFontProperty; + QStringList m_aliasingEnumNames; + // Font families with Designer annotations + QStringList m_designerFamilyNames; + NameMap m_familyMappings; +}; + +} + +QT_END_NAMESPACE + +#endif // FONTPROPERTYMANAGER_H diff --git a/src/designer/src/components/propertyeditor/newdynamicpropertydialog.cpp b/src/designer/src/components/propertyeditor/newdynamicpropertydialog.cpp new file mode 100644 index 000000000..32277a0ba --- /dev/null +++ b/src/designer/src/components/propertyeditor/newdynamicpropertydialog.cpp @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "newdynamicpropertydialog.h" +#include "ui_newdynamicpropertydialog.h" +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +NewDynamicPropertyDialog::NewDynamicPropertyDialog(QDesignerDialogGuiInterface *dialogGui, + QWidget *parent) : + QDialog(parent), + m_dialogGui(dialogGui), + m_ui(new Ui::NewDynamicPropertyDialog) +{ + m_ui->setupUi(this); + connect(m_ui->m_lineEdit, SIGNAL(textChanged(QString)), this, SLOT(nameChanged(QString))); + + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + m_ui->m_comboBox->addItem(QLatin1String("String"), QVariant(QVariant::String)); + m_ui->m_comboBox->addItem(QLatin1String("StringList"), QVariant(QVariant::StringList)); + m_ui->m_comboBox->addItem(QLatin1String("Char"), QVariant(QVariant::Char)); + m_ui->m_comboBox->addItem(QLatin1String("ByteArray"), QVariant(QVariant::ByteArray)); + m_ui->m_comboBox->addItem(QLatin1String("Url"), QVariant(QVariant::Url)); + m_ui->m_comboBox->addItem(QLatin1String("Bool"), QVariant(QVariant::Bool)); + m_ui->m_comboBox->addItem(QLatin1String("Int"), QVariant(QVariant::Int)); + m_ui->m_comboBox->addItem(QLatin1String("UInt"), QVariant(QVariant::UInt)); + m_ui->m_comboBox->addItem(QLatin1String("LongLong"), QVariant(QVariant::LongLong)); + m_ui->m_comboBox->addItem(QLatin1String("ULongLong"), QVariant(QVariant::ULongLong)); + m_ui->m_comboBox->addItem(QLatin1String("Double"), QVariant(QVariant::Double)); + m_ui->m_comboBox->addItem(QLatin1String("Size"), QVariant(QVariant::Size)); + m_ui->m_comboBox->addItem(QLatin1String("SizeF"), QVariant(QVariant::SizeF)); + m_ui->m_comboBox->addItem(QLatin1String("Point"), QVariant(QVariant::Point)); + m_ui->m_comboBox->addItem(QLatin1String("PointF"), QVariant(QVariant::PointF)); + m_ui->m_comboBox->addItem(QLatin1String("Rect"), QVariant(QVariant::Rect)); + m_ui->m_comboBox->addItem(QLatin1String("RectF"), QVariant(QVariant::RectF)); + m_ui->m_comboBox->addItem(QLatin1String("Date"), QVariant(QVariant::Date)); + m_ui->m_comboBox->addItem(QLatin1String("Time"), QVariant(QVariant::Time)); + m_ui->m_comboBox->addItem(QLatin1String("DateTime"), QVariant(QVariant::DateTime)); + m_ui->m_comboBox->addItem(QLatin1String("Font"), QVariant(QVariant::Font)); + m_ui->m_comboBox->addItem(QLatin1String("Palette"), QVariant(QVariant::Palette)); + m_ui->m_comboBox->addItem(QLatin1String("Color"), QVariant(QVariant::Color)); + m_ui->m_comboBox->addItem(QLatin1String("Pixmap"), QVariant(QVariant::Pixmap)); + m_ui->m_comboBox->addItem(QLatin1String("Icon"), QVariant(QVariant::Icon)); + m_ui->m_comboBox->addItem(QLatin1String("Cursor"), QVariant(QVariant::Cursor)); + m_ui->m_comboBox->addItem(QLatin1String("SizePolicy"), QVariant(QVariant::SizePolicy)); + m_ui->m_comboBox->addItem(QLatin1String("KeySequence"), QVariant(QVariant::KeySequence)); + + m_ui->m_comboBox->setCurrentIndex(0); // String + setOkButtonEnabled(false); +} + +void NewDynamicPropertyDialog::setOkButtonEnabled(bool e) +{ + m_ui->m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(e); +} + +NewDynamicPropertyDialog::~NewDynamicPropertyDialog() +{ + delete m_ui; +} + +void NewDynamicPropertyDialog::setReservedNames(const QStringList &names) +{ + m_reservedNames = names; +} + +void NewDynamicPropertyDialog::setPropertyType(QVariant::Type t) +{ + const int index = m_ui->m_comboBox->findData(QVariant(t)); + if (index != -1) + m_ui->m_comboBox->setCurrentIndex(index); +} + +QString NewDynamicPropertyDialog::propertyName() const +{ + return m_ui->m_lineEdit->text(); +} + +QVariant NewDynamicPropertyDialog::propertyValue() const +{ + const int index = m_ui->m_comboBox->currentIndex(); + if (index == -1) + return QVariant(); + return m_ui->m_comboBox->itemData(index); +} + +void NewDynamicPropertyDialog::information(const QString &message) +{ + m_dialogGui->message(this, QDesignerDialogGuiInterface::PropertyEditorMessage, QMessageBox::Information, tr("Set Property Name"), message); +} + +void NewDynamicPropertyDialog::nameChanged(const QString &s) +{ + setOkButtonEnabled(!s.isEmpty()); +} + +bool NewDynamicPropertyDialog::validatePropertyName(const QString& name) +{ + if (m_reservedNames.contains(name)) { + information(tr("The current object already has a property named '%1'.\nPlease select another, unique one.").arg(name)); + return false; + } + if (!QDesignerPropertySheet::internalDynamicPropertiesEnabled() && name.startsWith(QLatin1String("_q_"))) { + information(tr("The '_q_' prefix is reserved for the Qt library.\nPlease select another name.")); + return false; + } + return true; +} + +void NewDynamicPropertyDialog::on_m_buttonBox_clicked(QAbstractButton *btn) +{ + const int role = m_ui->m_buttonBox->buttonRole(btn); + switch (role) { + case QDialogButtonBox::RejectRole: + reject(); + break; + case QDialogButtonBox::AcceptRole: + if (validatePropertyName(propertyName())) + accept(); + break; + } +} +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/propertyeditor/newdynamicpropertydialog.h b/src/designer/src/components/propertyeditor/newdynamicpropertydialog.h new file mode 100644 index 000000000..7c3966a43 --- /dev/null +++ b/src/designer/src/components/propertyeditor/newdynamicpropertydialog.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef NEWDYNAMICPROPERTYDIALOG_P_H +#define NEWDYNAMICPROPERTYDIALOG_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "propertyeditor_global.h" +#include +#include + +QT_BEGIN_NAMESPACE + +class QAbstractButton; +class QDesignerDialogGuiInterface; + +namespace qdesigner_internal { + +namespace Ui +{ + class NewDynamicPropertyDialog; +} + +class QT_PROPERTYEDITOR_EXPORT NewDynamicPropertyDialog: public QDialog +{ + Q_OBJECT +public: + explicit NewDynamicPropertyDialog(QDesignerDialogGuiInterface *dialogGui, QWidget *parent = 0); + ~NewDynamicPropertyDialog(); + + void setReservedNames(const QStringList &names); + void setPropertyType(QVariant::Type t); + + QString propertyName() const; + QVariant propertyValue() const; + +private slots: + + void on_m_buttonBox_clicked(QAbstractButton *btn); + void nameChanged(const QString &); + +private: + bool validatePropertyName(const QString& name); + void setOkButtonEnabled(bool e); + void information(const QString &message); + + QDesignerDialogGuiInterface *m_dialogGui; + Ui::NewDynamicPropertyDialog *m_ui; + QStringList m_reservedNames; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // NEWDYNAMICPROPERTYDIALOG_P_H diff --git a/src/designer/src/components/propertyeditor/newdynamicpropertydialog.ui b/src/designer/src/components/propertyeditor/newdynamicpropertydialog.ui new file mode 100644 index 000000000..2aa91f3e9 --- /dev/null +++ b/src/designer/src/components/propertyeditor/newdynamicpropertydialog.ui @@ -0,0 +1,106 @@ + + qdesigner_internal::NewDynamicPropertyDialog + + + + 0 + 0 + 340 + 118 + + + + Create Dynamic Property + + + + + + + + + 220 + 0 + + + + + + + + + 0 + 0 + + + + Property Name + + + + + + + + + + + + horizontalSpacer + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + 0 + + + + Property Type + + + + + + + + + + + + Qt::Vertical + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + false + + + + + + + + diff --git a/src/designer/src/components/propertyeditor/paletteeditor.cpp b/src/designer/src/components/propertyeditor/paletteeditor.cpp new file mode 100644 index 000000000..55a6da5cb --- /dev/null +++ b/src/designer/src/components/propertyeditor/paletteeditor.cpp @@ -0,0 +1,616 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "paletteeditor.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +enum { BrushRole = 33 }; + +PaletteEditor::PaletteEditor(QDesignerFormEditorInterface *core, QWidget *parent) : + QDialog(parent), + m_currentColorGroup(QPalette::Active), + m_paletteModel(new PaletteModel(this)), + m_modelUpdated(false), + m_paletteUpdated(false), + m_compute(true), + m_core(core) +{ + ui.setupUi(this); + ui.paletteView->setModel(m_paletteModel); + updatePreviewPalette(); + updateStyledButton(); + ui.paletteView->setModel(m_paletteModel); + ColorDelegate *delegate = new ColorDelegate(core, this); + ui.paletteView->setItemDelegate(delegate); + ui.paletteView->setEditTriggers(QAbstractItemView::AllEditTriggers); + connect(m_paletteModel, SIGNAL(paletteChanged(QPalette)), + this, SLOT(paletteChanged(QPalette))); + ui.paletteView->setSelectionBehavior(QAbstractItemView::SelectRows); + ui.paletteView->setDragEnabled(true); + ui.paletteView->setDropIndicatorShown(true); + ui.paletteView->setRootIsDecorated(false); + ui.paletteView->setColumnHidden(2, true); + ui.paletteView->setColumnHidden(3, true); +} + +PaletteEditor::~PaletteEditor() +{ +} + +QPalette PaletteEditor::palette() const +{ + return m_editPalette; +} + +void PaletteEditor::setPalette(const QPalette &palette) +{ + m_editPalette = palette; + const uint mask = palette.resolve(); + for (int i = 0; i < (int)QPalette::NColorRoles; i++) { + if (!(mask & (1 << i))) { + m_editPalette.setBrush(QPalette::Active, static_cast(i), + m_parentPalette.brush(QPalette::Active, static_cast(i))); + m_editPalette.setBrush(QPalette::Inactive, static_cast(i), + m_parentPalette.brush(QPalette::Inactive, static_cast(i))); + m_editPalette.setBrush(QPalette::Disabled, static_cast(i), + m_parentPalette.brush(QPalette::Disabled, static_cast(i))); + } + } + m_editPalette.resolve(mask); + updatePreviewPalette(); + updateStyledButton(); + m_paletteUpdated = true; + if (!m_modelUpdated) + m_paletteModel->setPalette(m_editPalette, m_parentPalette); + m_paletteUpdated = false; +} + +void PaletteEditor::setPalette(const QPalette &palette, const QPalette &parentPalette) +{ + m_parentPalette = parentPalette; + setPalette(palette); +} + +void PaletteEditor::on_buildButton_colorChanged(const QColor &) +{ + buildPalette(); +} + +void PaletteEditor::on_activeRadio_clicked() +{ + m_currentColorGroup = QPalette::Active; + updatePreviewPalette(); +} + +void PaletteEditor::on_inactiveRadio_clicked() +{ + m_currentColorGroup = QPalette::Inactive; + updatePreviewPalette(); +} + +void PaletteEditor::on_disabledRadio_clicked() +{ + m_currentColorGroup = QPalette::Disabled; + updatePreviewPalette(); +} + +void PaletteEditor::on_computeRadio_clicked() +{ + if (m_compute) + return; + ui.paletteView->setColumnHidden(2, true); + ui.paletteView->setColumnHidden(3, true); + m_compute = true; + m_paletteModel->setCompute(true); +} + +void PaletteEditor::on_detailsRadio_clicked() +{ + if (!m_compute) + return; + const int w = ui.paletteView->columnWidth(1); + ui.paletteView->setColumnHidden(2, false); + ui.paletteView->setColumnHidden(3, false); + QHeaderView *header = ui.paletteView->header(); + header->resizeSection(1, w / 3); + header->resizeSection(2, w / 3); + header->resizeSection(3, w / 3); + m_compute = false; + m_paletteModel->setCompute(false); +} + +void PaletteEditor::paletteChanged(const QPalette &palette) +{ + m_modelUpdated = true; + if (!m_paletteUpdated) + setPalette(palette); + m_modelUpdated = false; +} + +void PaletteEditor::buildPalette() +{ + const QColor btn = ui.buildButton->color(); + const QPalette temp = QPalette(btn); + setPalette(temp); +} + +void PaletteEditor::updatePreviewPalette() +{ + const QPalette::ColorGroup g = currentColorGroup(); + // build the preview palette + const QPalette currentPalette = palette(); + QPalette previewPalette; + for (int i = QPalette::WindowText; i < QPalette::NColorRoles; i++) { + const QPalette::ColorRole r = static_cast(i); + const QBrush br = currentPalette.brush(g, r); + previewPalette.setBrush(QPalette::Active, r, br); + previewPalette.setBrush(QPalette::Inactive, r, br); + previewPalette.setBrush(QPalette::Disabled, r, br); + } + ui.previewFrame->setPreviewPalette(previewPalette); + + const bool enabled = g != QPalette::Disabled; + ui.previewFrame->setEnabled(enabled); + ui.previewFrame->setSubWindowActive(g != QPalette::Inactive); +} + +void PaletteEditor::updateStyledButton() +{ + ui.buildButton->setColor(palette().color(QPalette::Active, QPalette::Button)); +} + +QPalette PaletteEditor::getPalette(QDesignerFormEditorInterface *core, QWidget* parent, const QPalette &init, + const QPalette &parentPal, int *ok) +{ + PaletteEditor dlg(core, parent); + QPalette parentPalette(parentPal); + uint mask = init.resolve(); + for (int i = 0; i < (int)QPalette::NColorRoles; i++) { + if (!(mask & (1 << i))) { + parentPalette.setBrush(QPalette::Active, static_cast(i), + init.brush(QPalette::Active, static_cast(i))); + parentPalette.setBrush(QPalette::Inactive, static_cast(i), + init.brush(QPalette::Inactive, static_cast(i))); + parentPalette.setBrush(QPalette::Disabled, static_cast(i), + init.brush(QPalette::Disabled, static_cast(i))); + } + } + dlg.setPalette(init, parentPalette); + + const int result = dlg.exec(); + if (ok) *ok = result; + + return result == QDialog::Accepted ? dlg.palette() : init; +} + +////////////////////// + +PaletteModel::PaletteModel(QObject *parent) : + QAbstractTableModel(parent), + m_compute(true) +{ + const QMetaObject *meta = metaObject(); + const int index = meta->indexOfProperty("colorRole"); + const QMetaProperty p = meta->property(index); + const QMetaEnum e = p.enumerator(); + for (int r = QPalette::WindowText; r < QPalette::NColorRoles; r++) { + m_roleNames[static_cast(r)] = QLatin1String(e.key(r)); + } +} + +int PaletteModel::rowCount(const QModelIndex &) const +{ + return m_roleNames.count(); +} + +int PaletteModel::columnCount(const QModelIndex &) const +{ + return 4; +} + +QVariant PaletteModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + if (index.row() < 0 || index.row() >= QPalette::NColorRoles) + return QVariant(); + if (index.column() < 0 || index.column() >= 4) + return QVariant(); + + if (index.column() == 0) { + if (role == Qt::DisplayRole) + return m_roleNames[static_cast(index.row())]; + if (role == Qt::EditRole) { + const uint mask = m_palette.resolve(); + if (mask & (1 << index.row())) + return true; + return false; + } + return QVariant(); + } + if (role == BrushRole) + return m_palette.brush(columnToGroup(index.column()), + static_cast(index.row())); + return QVariant(); +} + +bool PaletteModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (!index.isValid()) + return false; + + if (index.column() != 0 && role == BrushRole) { + const QBrush br = qvariant_cast(value); + const QPalette::ColorRole r = static_cast(index.row()); + const QPalette::ColorGroup g = columnToGroup(index.column()); + m_palette.setBrush(g, r, br); + + QModelIndex idxBegin = PaletteModel::index(r, 0); + QModelIndex idxEnd = PaletteModel::index(r, 3); + if (m_compute) { + m_palette.setBrush(QPalette::Inactive, r, br); + switch (r) { + case QPalette::WindowText: + case QPalette::Text: + case QPalette::ButtonText: + case QPalette::Base: + break; + case QPalette::Dark: + m_palette.setBrush(QPalette::Disabled, QPalette::WindowText, br); + m_palette.setBrush(QPalette::Disabled, QPalette::Dark, br); + m_palette.setBrush(QPalette::Disabled, QPalette::Text, br); + m_palette.setBrush(QPalette::Disabled, QPalette::ButtonText, br); + idxBegin = PaletteModel::index(0, 0); + idxEnd = PaletteModel::index(m_roleNames.count() - 1, 3); + break; + case QPalette::Window: + m_palette.setBrush(QPalette::Disabled, QPalette::Base, br); + m_palette.setBrush(QPalette::Disabled, QPalette::Window, br); + idxBegin = PaletteModel::index(QPalette::Base, 0); + break; + case QPalette::Highlight: + //m_palette.setBrush(QPalette::Disabled, QPalette::Highlight, c.dark(120)); + break; + default: + m_palette.setBrush(QPalette::Disabled, r, br); + break; + } + } + emit paletteChanged(m_palette); + emit dataChanged(idxBegin, idxEnd); + return true; + } + if (index.column() == 0 && role == Qt::EditRole) { + uint mask = m_palette.resolve(); + const bool isMask = qvariant_cast(value); + const int r = index.row(); + if (isMask) + mask |= (1 << r); + else { + m_palette.setBrush(QPalette::Active, static_cast(r), + m_parentPalette.brush(QPalette::Active, static_cast(r))); + m_palette.setBrush(QPalette::Inactive, static_cast(r), + m_parentPalette.brush(QPalette::Inactive, static_cast(r))); + m_palette.setBrush(QPalette::Disabled, static_cast(r), + m_parentPalette.brush(QPalette::Disabled, static_cast(r))); + + mask &= ~(1 << index.row()); + } + m_palette.resolve(mask); + emit paletteChanged(m_palette); + const QModelIndex idxEnd = PaletteModel::index(r, 3); + emit dataChanged(index, idxEnd); + return true; + } + return false; +} + +Qt::ItemFlags PaletteModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return Qt::ItemIsEnabled; + return Qt::ItemIsEditable | Qt::ItemIsEnabled; +} + +QVariant PaletteModel::headerData(int section, Qt::Orientation orientation, + int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { + if (section == 0) + return tr("Color Role"); + if (section == groupToColumn(QPalette::Active)) + return tr("Active"); + if (section == groupToColumn(QPalette::Inactive)) + return tr("Inactive"); + if (section == groupToColumn(QPalette::Disabled)) + return tr("Disabled"); + } + return QVariant(); +} + +QPalette PaletteModel::getPalette() const +{ + return m_palette; +} + +void PaletteModel::setPalette(const QPalette &palette, const QPalette &parentPalette) +{ + m_parentPalette = parentPalette; + m_palette = palette; + const QModelIndex idxBegin = index(0, 0); + const QModelIndex idxEnd = index(m_roleNames.count() - 1, 3); + emit dataChanged(idxBegin, idxEnd); +} + +QPalette::ColorGroup PaletteModel::columnToGroup(int index) const +{ + if (index == 1) + return QPalette::Active; + if (index == 2) + return QPalette::Inactive; + return QPalette::Disabled; +} + +int PaletteModel::groupToColumn(QPalette::ColorGroup group) const +{ + if (group == QPalette::Active) + return 1; + if (group == QPalette::Inactive) + return 2; + return 3; +} + +////////////////////////// + +BrushEditor::BrushEditor(QDesignerFormEditorInterface *core, QWidget *parent) : + QWidget(parent), + m_button(new QtColorButton(this)), + m_changed(false), + m_core(core) +{ + QLayout *layout = new QHBoxLayout(this); + layout->setMargin(0); + layout->addWidget(m_button); + connect(m_button, SIGNAL(colorChanged(QColor)), this, SLOT(brushChanged())); + setFocusProxy(m_button); +} + +void BrushEditor::setBrush(const QBrush &brush) +{ + m_button->setColor(brush.color()); + m_changed = false; +} + +QBrush BrushEditor::brush() const +{ + return QBrush(m_button->color()); +} + +void BrushEditor::brushChanged() +{ + m_changed = true; + emit changed(this); +} + +bool BrushEditor::changed() const +{ + return m_changed; +} + +////////////////////////// + +RoleEditor::RoleEditor(QWidget *parent) : + QWidget(parent), + m_label(new QLabel(this)), + m_edited(false) +{ + QHBoxLayout *layout = new QHBoxLayout(this); + layout->setMargin(0); + layout->setSpacing(0); + + layout->addWidget(m_label); + m_label->setAutoFillBackground(true); + m_label->setIndent(3); // ### hardcode it should have the same value of textMargin in QItemDelegate + setFocusProxy(m_label); + + QToolButton *button = new QToolButton(this); + button->setToolButtonStyle(Qt::ToolButtonIconOnly); + button->setIcon(createIconSet(QLatin1String("resetproperty.png"))); + button->setIconSize(QSize(8,8)); + button->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding)); + layout->addWidget(button); + connect(button, SIGNAL(clicked()), this, SLOT(emitResetProperty())); +} + +void RoleEditor::setLabel(const QString &label) +{ + m_label->setText(label); +} + +void RoleEditor::setEdited(bool on) +{ + QFont font; + if (on == true) { + font.setBold(on); + } + m_label->setFont(font); + m_edited = on; +} + +bool RoleEditor::edited() const +{ + return m_edited; +} + +void RoleEditor::emitResetProperty() +{ + setEdited(false); + emit changed(this); +} + +////////////////////////// +ColorDelegate::ColorDelegate(QDesignerFormEditorInterface *core, QObject *parent) : + QItemDelegate(parent), + m_core(core) +{ +} + +QWidget *ColorDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, + const QModelIndex &index) const +{ + QWidget *ed = 0; + if (index.column() == 0) { + RoleEditor *editor = new RoleEditor(parent); + connect(editor, SIGNAL(changed(QWidget*)), this, SIGNAL(commitData(QWidget*))); + //editor->setFocusPolicy(Qt::NoFocus); + //editor->installEventFilter(const_cast(this)); + ed = editor; + } else { + BrushEditor *editor = new BrushEditor(m_core, parent); + connect(editor, SIGNAL(changed(QWidget*)), this, SIGNAL(commitData(QWidget*))); + editor->setFocusPolicy(Qt::NoFocus); + editor->installEventFilter(const_cast(this)); + ed = editor; + } + return ed; +} + +void ColorDelegate::setEditorData(QWidget *ed, const QModelIndex &index) const +{ + if (index.column() == 0) { + const bool mask = qvariant_cast(index.model()->data(index, Qt::EditRole)); + RoleEditor *editor = static_cast(ed); + editor->setEdited(mask); + const QString colorName = qvariant_cast(index.model()->data(index, Qt::DisplayRole)); + editor->setLabel(colorName); + } else { + const QBrush br = qvariant_cast(index.model()->data(index, BrushRole)); + BrushEditor *editor = static_cast(ed); + editor->setBrush(br); + } +} + +void ColorDelegate::setModelData(QWidget *ed, QAbstractItemModel *model, + const QModelIndex &index) const +{ + if (index.column() == 0) { + RoleEditor *editor = static_cast(ed); + const bool mask = editor->edited(); + model->setData(index, mask, Qt::EditRole); + } else { + BrushEditor *editor = static_cast(ed); + if (editor->changed()) { + QBrush br = editor->brush(); + model->setData(index, br, BrushRole); + } + } +} + +void ColorDelegate::updateEditorGeometry(QWidget *ed, + const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + QItemDelegate::updateEditorGeometry(ed, option, index); + ed->setGeometry(ed->geometry().adjusted(0, 0, -1, -1)); +} + +void ColorDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opt, + const QModelIndex &index) const +{ + QStyleOptionViewItem option = opt; + const bool mask = qvariant_cast(index.model()->data(index, Qt::EditRole)); + if (index.column() == 0 && mask) { + option.font.setBold(true); + } + QBrush br = qvariant_cast(index.model()->data(index, BrushRole)); + if (br.style() == Qt::LinearGradientPattern || + br.style() == Qt::RadialGradientPattern || + br.style() == Qt::ConicalGradientPattern) { + painter->save(); + painter->translate(option.rect.x(), option.rect.y()); + painter->scale(option.rect.width(), option.rect.height()); + QGradient gr = *(br.gradient()); + gr.setCoordinateMode(QGradient::LogicalMode); + br = QBrush(gr); + painter->fillRect(0, 0, 1, 1, br); + painter->restore(); + } else { + painter->save(); + painter->setBrushOrigin(option.rect.x(), option.rect.y()); + painter->fillRect(option.rect, br); + painter->restore(); + } + QItemDelegate::paint(painter, option, index); + + + const QColor color = static_cast(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &option)); + const QPen oldPen = painter->pen(); + painter->setPen(QPen(color)); + + painter->drawLine(option.rect.right(), option.rect.y(), + option.rect.right(), option.rect.bottom()); + painter->drawLine(option.rect.x(), option.rect.bottom(), + option.rect.right(), option.rect.bottom()); + painter->setPen(oldPen); +} + +QSize ColorDelegate::sizeHint(const QStyleOptionViewItem &opt, const QModelIndex &index) const +{ + return QItemDelegate::sizeHint(opt, index) + QSize(4, 4); +} +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/propertyeditor/paletteeditor.h b/src/designer/src/components/propertyeditor/paletteeditor.h new file mode 100644 index 000000000..9caed1965 --- /dev/null +++ b/src/designer/src/components/propertyeditor/paletteeditor.h @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PALETTEEDITOR_H +#define PALETTEEDITOR_H + +#include "ui_paletteeditor.h" +#include + +QT_BEGIN_NAMESPACE + +class QListView; +class QLabel; +class QtColorButton; +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +class PaletteEditor: public QDialog +{ + Q_OBJECT +public: + virtual ~PaletteEditor(); + + static QPalette getPalette(QDesignerFormEditorInterface *core, + QWidget* parent, const QPalette &init = QPalette(), + const QPalette &parentPal = QPalette(), int *result = 0); + + QPalette palette() const; + void setPalette(const QPalette &palette); + void setPalette(const QPalette &palette, const QPalette &parentPalette); + +private slots: + + void on_buildButton_colorChanged(const QColor &); + void on_activeRadio_clicked(); + void on_inactiveRadio_clicked(); + void on_disabledRadio_clicked(); + void on_computeRadio_clicked(); + void on_detailsRadio_clicked(); + + void paletteChanged(const QPalette &palette); + +protected: + +private: + PaletteEditor(QDesignerFormEditorInterface *core, QWidget *parent); + void buildPalette(); + + void updatePreviewPalette(); + void updateStyledButton(); + + QPalette::ColorGroup currentColorGroup() const + { return m_currentColorGroup; } + + Ui::PaletteEditor ui; + QPalette m_editPalette; + QPalette m_parentPalette; + QPalette::ColorGroup m_currentColorGroup; + class PaletteModel *m_paletteModel; + bool m_modelUpdated; + bool m_paletteUpdated; + bool m_compute; + QDesignerFormEditorInterface *m_core; +}; + + +class PaletteModel : public QAbstractTableModel +{ + Q_OBJECT + Q_PROPERTY(QPalette::ColorRole colorRole READ colorRole) +public: + explicit PaletteModel(QObject *parent = 0); + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + QVariant data(const QModelIndex &index, int role) const; + bool setData(const QModelIndex &index, const QVariant &value, int role); + Qt::ItemFlags flags(const QModelIndex &index) const; + QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + + QPalette getPalette() const; + void setPalette(const QPalette &palette, const QPalette &parentPalette); + + QPalette::ColorRole colorRole() const { return QPalette::NoRole; } + void setCompute(bool on) { m_compute = on; } +signals: + void paletteChanged(const QPalette &palette); +private: + + QPalette::ColorGroup columnToGroup(int index) const; + int groupToColumn(QPalette::ColorGroup group) const; + + QPalette m_palette; + QPalette m_parentPalette; + QMap m_roleNames; + bool m_compute; +}; + +class BrushEditor : public QWidget +{ + Q_OBJECT +public: + explicit BrushEditor(QDesignerFormEditorInterface *core, QWidget *parent = 0); + + void setBrush(const QBrush &brush); + QBrush brush() const; + bool changed() const; +signals: + void changed(QWidget *widget); +private slots: + void brushChanged(); +private: + QtColorButton *m_button; + bool m_changed; + QDesignerFormEditorInterface *m_core; +}; + +class RoleEditor : public QWidget +{ + Q_OBJECT +public: + explicit RoleEditor(QWidget *parent = 0); + + void setLabel(const QString &label); + void setEdited(bool on); + bool edited() const; +signals: + void changed(QWidget *widget); +private slots: + void emitResetProperty(); +private: + QLabel *m_label; + bool m_edited; +}; + +class ColorDelegate : public QItemDelegate +{ + Q_OBJECT + +public: + explicit ColorDelegate(QDesignerFormEditorInterface *core, QObject *parent = 0); + + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, + const QModelIndex &index) const; + + void setEditorData(QWidget *ed, const QModelIndex &index) const; + void setModelData(QWidget *ed, QAbstractItemModel *model, + const QModelIndex &index) const; + + void updateEditorGeometry(QWidget *ed, + const QStyleOptionViewItem &option, const QModelIndex &index) const; + + virtual void paint(QPainter *painter, const QStyleOptionViewItem &opt, + const QModelIndex &index) const; + virtual QSize sizeHint(const QStyleOptionViewItem &opt, const QModelIndex &index) const; +private: + QDesignerFormEditorInterface *m_core; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // PALETTEEDITOR_H diff --git a/src/designer/src/components/propertyeditor/paletteeditor.ui b/src/designer/src/components/propertyeditor/paletteeditor.ui new file mode 100644 index 000000000..12d27127b --- /dev/null +++ b/src/designer/src/components/propertyeditor/paletteeditor.ui @@ -0,0 +1,264 @@ + + ********************************************************************* +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +********************************************************************* + qdesigner_internal::PaletteEditor + + + + 0 + 0 + 365 + 409 + + + + + 7 + 7 + 0 + 0 + + + + Edit Palette + + + + 9 + + + 6 + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Tune Palette + + + + 9 + + + 6 + + + + + + 7 + 13 + 0 + 0 + + + + + + + + + + + + 0 + 200 + + + + + + + + Show Details + + + + + + + Compute Details + + + true + + + + + + + Quick + + + + + + + + + + + 5 + 7 + 0 + 0 + + + + Preview + + + + 8 + + + 6 + + + + + Disabled + + + + + + + Inactive + + + + + + + Active + + + true + + + + + + + + 7 + 7 + 0 + 0 + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok + + + + + + + + QtColorButton + QToolButton +
qtcolorbutton.h
+
+ + qdesigner_internal::PreviewFrame + QWidget +
previewframe.h
+
+
+ + + + buttonBox + accepted() + qdesigner_internal::PaletteEditor + accept() + + + 180 + 331 + + + 134 + 341 + + + + + buttonBox + rejected() + qdesigner_internal::PaletteEditor + reject() + + + 287 + 329 + + + 302 + 342 + + + + +
diff --git a/src/designer/src/components/propertyeditor/paletteeditorbutton.cpp b/src/designer/src/components/propertyeditor/paletteeditorbutton.cpp new file mode 100644 index 000000000..b716de1e1 --- /dev/null +++ b/src/designer/src/components/propertyeditor/paletteeditorbutton.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "paletteeditorbutton.h" +#include "paletteeditor.h" + +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +PaletteEditorButton::PaletteEditorButton(QDesignerFormEditorInterface *core, const QPalette &palette, QWidget *parent) + : QToolButton(parent), + m_palette(palette) +{ + m_core = core; + setFocusPolicy(Qt::NoFocus); + setText(tr("Change Palette")); + setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); + + connect(this, SIGNAL(clicked()), this, SLOT(showPaletteEditor())); +} + +PaletteEditorButton::~PaletteEditorButton() +{ +} + +void PaletteEditorButton::setPalette(const QPalette &palette) +{ + m_palette = palette; +} + +void PaletteEditorButton::setSuperPalette(const QPalette &palette) +{ + m_superPalette = palette; +} + +void PaletteEditorButton::showPaletteEditor() +{ + int result; + QPalette p = QPalette(); + QPalette pal = PaletteEditor::getPalette(m_core, 0, m_palette, m_superPalette, &result); + if (result == QDialog::Accepted) { + m_palette = pal; + emit paletteChanged(m_palette); + } +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/propertyeditor/paletteeditorbutton.h b/src/designer/src/components/propertyeditor/paletteeditorbutton.h new file mode 100644 index 000000000..567605a19 --- /dev/null +++ b/src/designer/src/components/propertyeditor/paletteeditorbutton.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PALETTEEDITORBUTTON_H +#define PALETTEEDITORBUTTON_H + +#include "propertyeditor_global.h" + +#include +#include + +#include "abstractformeditor.h" + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QT_PROPERTYEDITOR_EXPORT PaletteEditorButton: public QToolButton +{ + Q_OBJECT +public: + PaletteEditorButton(QDesignerFormEditorInterface *core, const QPalette &palette, QWidget *parent = 0); + virtual ~PaletteEditorButton(); + + void setSuperPalette(const QPalette &palette); + inline QPalette palette() const + { return m_palette; } + +signals: + void paletteChanged(const QPalette &palette); + +public slots: + void setPalette(const QPalette &palette); + +private slots: + void showPaletteEditor(); + +private: + QPalette m_palette; + QPalette m_superPalette; + QDesignerFormEditorInterface *m_core; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // PALETTEEDITORBUTTON_H diff --git a/src/designer/src/components/propertyeditor/previewframe.cpp b/src/designer/src/components/propertyeditor/previewframe.cpp new file mode 100644 index 000000000..5e426c9c7 --- /dev/null +++ b/src/designer/src/components/propertyeditor/previewframe.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "previewframe.h" +#include "previewwidget.h" + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + + class PreviewMdiArea: public QMdiArea { + public: + PreviewMdiArea(QWidget *parent = 0) : QMdiArea(parent) {} + protected: + bool viewportEvent ( QEvent * event ); + }; + + bool PreviewMdiArea::viewportEvent (QEvent * event) { + if (event->type() != QEvent::Paint) + return QMdiArea::viewportEvent (event); + QWidget *paintWidget = viewport(); + QPainter p(paintWidget); + p.fillRect(rect(), paintWidget->palette().color(backgroundRole()).dark()); + p.setPen(QPen(Qt::white)); + //: Palette editor background + p.drawText(0, height() / 2, width(), height(), Qt::AlignHCenter, + QCoreApplication::translate("qdesigner_internal::PreviewMdiArea", "The moose in the noose\nate the goose who was loose.")); + return true; + } + +PreviewFrame::PreviewFrame(QWidget *parent) : + QFrame(parent), + m_mdiArea(new PreviewMdiArea(this)) +{ + m_mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + m_mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); + setLineWidth(1); + + QVBoxLayout *vbox = new QVBoxLayout(this); + vbox->setMargin(0); + vbox->addWidget(m_mdiArea); + + setMinimumSize(ensureMdiSubWindow()->minimumSizeHint()); +} + +void PreviewFrame::setPreviewPalette(const QPalette &pal) +{ + ensureMdiSubWindow()->widget()->setPalette(pal); +} + +void PreviewFrame::setSubWindowActive(bool active) +{ + m_mdiArea->setActiveSubWindow (active ? ensureMdiSubWindow() : static_cast(0)); +} + +QMdiSubWindow *PreviewFrame::ensureMdiSubWindow() +{ + if (!m_mdiSubWindow) { + PreviewWidget *previewWidget = new PreviewWidget(m_mdiArea); + m_mdiSubWindow = m_mdiArea->addSubWindow(previewWidget, Qt::WindowTitleHint | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint); + m_mdiSubWindow->move(10,10); + m_mdiSubWindow->showMaximized(); + } + + const Qt::WindowStates state = m_mdiSubWindow->windowState(); + if (state & Qt::WindowMinimized) + m_mdiSubWindow->setWindowState(state & ~Qt::WindowMinimized); + + return m_mdiSubWindow; +} +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/propertyeditor/previewframe.h b/src/designer/src/components/propertyeditor/previewframe.h new file mode 100644 index 000000000..567fd7f7a --- /dev/null +++ b/src/designer/src/components/propertyeditor/previewframe.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PREVIEWFRAME_H +#define PREVIEWFRAME_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class QMdiArea; +class QMdiSubWindow; + +namespace qdesigner_internal { + +class PreviewFrame: public QFrame +{ + Q_OBJECT +public: + explicit PreviewFrame(QWidget *parent); + + void setPreviewPalette(const QPalette &palette); + void setSubWindowActive(bool active); + +private: + // The user can on some platforms close the mdi child by invoking the system menu. + // Ensure a child is present. + QMdiSubWindow *ensureMdiSubWindow(); + QMdiArea *m_mdiArea; + QPointer m_mdiSubWindow; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif diff --git a/src/designer/src/components/propertyeditor/previewwidget.cpp b/src/designer/src/components/propertyeditor/previewwidget.cpp new file mode 100644 index 000000000..8dec3ffff --- /dev/null +++ b/src/designer/src/components/propertyeditor/previewwidget.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "previewwidget.h" + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +PreviewWidget::PreviewWidget(QWidget *parent) + : QWidget(parent) +{ + ui.setupUi(this); +} + +PreviewWidget::~PreviewWidget() +{ +} + + +QT_END_NAMESPACE diff --git a/src/designer/src/components/propertyeditor/previewwidget.h b/src/designer/src/components/propertyeditor/previewwidget.h new file mode 100644 index 000000000..4b014db8a --- /dev/null +++ b/src/designer/src/components/propertyeditor/previewwidget.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PREVIEWWIDGET_H +#define PREVIEWWIDGET_H + +#include "ui_previewwidget.h" + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class PreviewWidget: public QWidget +{ + Q_OBJECT +public: + explicit PreviewWidget(QWidget *parent); + virtual ~PreviewWidget(); + +private: + Ui::PreviewWidget ui; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // PREVIEWWIDGET_H diff --git a/src/designer/src/components/propertyeditor/previewwidget.ui b/src/designer/src/components/propertyeditor/previewwidget.ui new file mode 100644 index 000000000..a5f2a1eee --- /dev/null +++ b/src/designer/src/components/propertyeditor/previewwidget.ui @@ -0,0 +1,238 @@ + + ********************************************************************* +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +********************************************************************* + qdesigner_internal::PreviewWidget + + + + 0 + 0 + 471 + 251 + + + + + 1 + 1 + 0 + 0 + + + + Preview Window + + + + 9 + + + 6 + + + + + 0 + + + 6 + + + + + LineEdit + + + + + + + + ComboBox + + + + + + + + 0 + + + 6 + + + + + + + + PushButton + + + + + + + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + + + + + + 32767 + 50 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + Qt::Horizontal + + + + + + + ButtonGroup2 + + + + 9 + + + 6 + + + + + CheckBox1 + + + true + + + + + + + CheckBox2 + + + + + + + + + + ButtonGroup + + + + 9 + + + 6 + + + + + RadioButton1 + + + true + + + + + + + RadioButton2 + + + + + + + RadioButton3 + + + + + + + + + + + diff --git a/src/designer/src/components/propertyeditor/propertyeditor.cpp b/src/designer/src/components/propertyeditor/propertyeditor.cpp new file mode 100644 index 000000000..9f298d0a4 --- /dev/null +++ b/src/designer/src/components/propertyeditor/propertyeditor.cpp @@ -0,0 +1,1294 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "propertyeditor.h" + +#include "qttreepropertybrowser.h" +#include "qtbuttonpropertybrowser.h" +#include "qtvariantproperty.h" +#include "designerpropertymanager.h" +#include "qdesigner_propertysheet_p.h" +#include "formwindowbase_p.h" +#include "filterwidget_p.h" // For FilterWidget + +#include "newdynamicpropertydialog.h" +#include "dynamicpropertysheet.h" +#include "shared_enums_p.h" + +// sdk +#include +#include +#include +#include +#include +#include +// shared +#include +#include +#include +#include +#ifdef Q_OS_WIN +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static const char *SettingsGroupC = "PropertyEditor"; +#if QT_VERSION >= 0x040500 +static const char *ViewKeyC = "View"; +#endif +static const char *ColorKeyC = "Colored"; +static const char *SortedKeyC = "Sorted"; +static const char *ExpansionKeyC = "ExpandedItems"; +static const char *SplitterPositionKeyC = "SplitterPosition"; + +enum SettingsView { TreeView, ButtonView }; + +QT_BEGIN_NAMESPACE + +// --------------------------------------------------------------------------------- + +namespace qdesigner_internal { + +// ----------- ElidingLabel +// QLabel does not support text eliding so we need a helper class + +class ElidingLabel : public QWidget +{ +public: + ElidingLabel(const QString &text = QString(), QWidget *parent = 0) + : QWidget(parent), + m_text(text), + m_mode(Qt::ElideRight) { + setContentsMargins(3, 2, 3, 2); + } + QSize sizeHint() const; + void paintEvent(QPaintEvent *e); + void setText(const QString &text) { + m_text = text; + updateGeometry(); + } + void setElidemode(Qt::TextElideMode mode) { + m_mode = mode; + updateGeometry(); + } +private: + QString m_text; + Qt::TextElideMode m_mode; +}; + +QSize ElidingLabel::sizeHint() const +{ + QSize size = fontMetrics().boundingRect(m_text).size(); + size += QSize(contentsMargins().left() + contentsMargins().right(), + contentsMargins().top() + contentsMargins().bottom()); + return size; +} + +void ElidingLabel::paintEvent(QPaintEvent *) { + QPainter painter(this); + painter.setPen(QColor(0, 0, 0, 60)); + painter.setBrush(QColor(255, 255, 255, 40)); + painter.drawRect(rect().adjusted(0, 0, -1, -1)); + painter.setPen(palette().windowText().color()); + painter.drawText(contentsRect(), Qt::AlignLeft, + fontMetrics().elidedText(m_text, Qt::ElideRight, width(), 0)); +} + + +// ----------- PropertyEditor::Strings + +PropertyEditor::Strings::Strings() : + m_fontProperty(QLatin1String("font")), + m_qLayoutWidget(QLatin1String("QLayoutWidget")), + m_designerPrefix(QLatin1String("QDesigner")), + m_layout(QLatin1String("Layout")), + m_validationModeAttribute(QLatin1String("validationMode")), + m_fontAttribute(QLatin1String("font")), + m_superPaletteAttribute(QLatin1String("superPalette")), + m_enumNamesAttribute(QLatin1String("enumNames")), + m_resettableAttribute(QLatin1String("resettable")), + m_flagsAttribute(QLatin1String("flags")) +{ + m_alignmentProperties.insert(QLatin1String("alignment")); + m_alignmentProperties.insert(QLatin1String("layoutLabelAlignment")); // QFormLayout + m_alignmentProperties.insert(QLatin1String("layoutFormAlignment")); +} + +// ----------- PropertyEditor + +QDesignerMetaDataBaseItemInterface* PropertyEditor::metaDataBaseItem() const +{ + QObject *o = object(); + if (!o) + return 0; + QDesignerMetaDataBaseInterface *db = core()->metaDataBase(); + if (!db) + return 0; + return db->item(o); +} + +void PropertyEditor::setupStringProperty(QtVariantProperty *property, bool isMainContainer) +{ + const StringPropertyParameters params = textPropertyValidationMode(core(), m_object, property->propertyName(), isMainContainer); + // Does a meta DB entry exist - add comment + const bool hasComment = params.second; + property->setAttribute(m_strings.m_validationModeAttribute, params.first); + // assuming comment cannot appear or disappear for the same property in different object instance + if (!hasComment) + qDeleteAll(property->subProperties()); +} + +void PropertyEditor::setupPaletteProperty(QtVariantProperty *property) +{ + QPalette value = qvariant_cast(property->value()); + QPalette superPalette = QPalette(); + QWidget *currentWidget = qobject_cast(m_object); + if (currentWidget) { + if (currentWidget->isWindow()) + superPalette = QApplication::palette(currentWidget); + else { + if (currentWidget->parentWidget()) + superPalette = currentWidget->parentWidget()->palette(); + } + } + m_updatingBrowser = true; + property->setAttribute(m_strings.m_superPaletteAttribute, superPalette); + m_updatingBrowser = false; +} + +static inline QToolButton *createDropDownButton(QAction *defaultAction, QWidget *parent = 0) +{ + QToolButton *rc = new QToolButton(parent); + rc->setDefaultAction(defaultAction); + rc->setPopupMode(QToolButton::InstantPopup); + return rc; +} + +PropertyEditor::PropertyEditor(QDesignerFormEditorInterface *core, QWidget *parent, Qt::WindowFlags flags) : + QDesignerPropertyEditor(parent, flags), + m_core(core), + m_propertySheet(0), + m_currentBrowser(0), + m_treeBrowser(0), + m_propertyManager(new DesignerPropertyManager(m_core, this)), + m_dynamicGroup(0), + m_updatingBrowser(false), + m_stackedWidget(new QStackedWidget), + m_filterWidget(new FilterWidget(0, FilterWidget::LayoutAlignNone)), + m_buttonIndex(-1), + m_treeIndex(-1), + m_addDynamicAction(new QAction(createIconSet(QLatin1String("plus.png")), tr("Add Dynamic Property..."), this)), + m_removeDynamicAction(new QAction(createIconSet(QLatin1String("minus.png")), tr("Remove Dynamic Property"), this)), + m_sortingAction(new QAction(createIconSet(QLatin1String("sort.png")), tr("Sorting"), this)), + m_coloringAction(new QAction(createIconSet(QLatin1String("color.png")), tr("Color Groups"), this)), + m_treeAction(new QAction(tr("Tree View"), this)), + m_buttonAction(new QAction(tr("Drop Down Button View"), this)), + m_classLabel(new ElidingLabel), + m_sorting(false), + m_coloring(false), + m_brightness(false) +{ + QVector colors; + colors.reserve(6); + colors.push_back(QColor(255, 230, 191)); + colors.push_back(QColor(255, 255, 191)); + colors.push_back(QColor(191, 255, 191)); + colors.push_back(QColor(199, 255, 255)); + colors.push_back(QColor(234, 191, 255)); + colors.push_back(QColor(255, 191, 239)); + m_colors.reserve(colors.count()); + const int darknessFactor = 250; + for (int i = 0; i < colors.count(); i++) { + QColor c = colors.at(i); + m_colors.push_back(qMakePair(c, c.darker(darknessFactor))); + } + QColor dynamicColor(191, 207, 255); + QColor layoutColor(255, 191, 191); + m_dynamicColor = qMakePair(dynamicColor, dynamicColor.darker(darknessFactor)); + m_layoutColor = qMakePair(layoutColor, layoutColor.darker(darknessFactor)); + + updateForegroundBrightness(); + + QActionGroup *actionGroup = new QActionGroup(this); + + m_treeAction->setCheckable(true); + m_treeAction->setIcon(createIconSet(QLatin1String("widgets/listview.png"))); + m_buttonAction->setCheckable(true); + m_buttonAction->setIcon(createIconSet(QLatin1String("dropdownbutton.png"))); + + actionGroup->addAction(m_treeAction); + actionGroup->addAction(m_buttonAction); + connect(actionGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotViewTriggered(QAction*))); + + // Add actions + QActionGroup *addDynamicActionGroup = new QActionGroup(this); + connect(addDynamicActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotAddDynamicProperty(QAction*))); + + QMenu *addDynamicActionMenu = new QMenu(this); + m_addDynamicAction->setMenu(addDynamicActionMenu); + m_addDynamicAction->setEnabled(false); + QAction *addDynamicAction = addDynamicActionGroup->addAction(tr("String...")); + addDynamicAction->setData(static_cast(QVariant::String)); + addDynamicActionMenu->addAction(addDynamicAction); + addDynamicAction = addDynamicActionGroup->addAction(tr("Bool...")); + addDynamicAction->setData(static_cast(QVariant::Bool)); + addDynamicActionMenu->addAction(addDynamicAction); + addDynamicActionMenu->addSeparator(); + addDynamicAction = addDynamicActionGroup->addAction(tr("Other...")); + addDynamicAction->setData(static_cast(QVariant::Invalid)); + addDynamicActionMenu->addAction(addDynamicAction); + // remove + m_removeDynamicAction->setEnabled(false); + connect(m_removeDynamicAction, SIGNAL(triggered()), this, SLOT(slotRemoveDynamicProperty())); + // Configure + QAction *configureAction = new QAction(tr("Configure Property Editor"), this); + configureAction->setIcon(createIconSet(QLatin1String("configure.png"))); + QMenu *configureMenu = new QMenu(this); + configureAction->setMenu(configureMenu); + + m_sortingAction->setCheckable(true); + connect(m_sortingAction, SIGNAL(toggled(bool)), this, SLOT(slotSorting(bool))); + + m_coloringAction->setCheckable(true); + connect(m_coloringAction, SIGNAL(toggled(bool)), this, SLOT(slotColoring(bool))); + + configureMenu->addAction(m_sortingAction); + configureMenu->addAction(m_coloringAction); +#if QT_VERSION >= 0x04FF00 + configureMenu->addSeparator(); + configureMenu->addAction(m_treeAction); + configureMenu->addAction(m_buttonAction); +#endif + // Assemble toolbar + QToolBar *toolBar = new QToolBar; + toolBar->addWidget(m_filterWidget); + toolBar->addWidget(createDropDownButton(m_addDynamicAction)); + toolBar->addAction(m_removeDynamicAction); + toolBar->addWidget(createDropDownButton(configureAction)); + // Views + QScrollArea *buttonScroll = new QScrollArea(m_stackedWidget); + m_buttonBrowser = new QtButtonPropertyBrowser(buttonScroll); + buttonScroll->setWidgetResizable(true); + buttonScroll->setWidget(m_buttonBrowser); + m_buttonIndex = m_stackedWidget->addWidget(buttonScroll); + connect(m_buttonBrowser, SIGNAL(currentItemChanged(QtBrowserItem*)), this, SLOT(slotCurrentItemChanged(QtBrowserItem*))); + + m_treeBrowser = new QtTreePropertyBrowser(m_stackedWidget); + m_treeBrowser->setRootIsDecorated(false); + m_treeBrowser->setPropertiesWithoutValueMarked(true); + m_treeBrowser->setResizeMode(QtTreePropertyBrowser::Interactive); + m_treeIndex = m_stackedWidget->addWidget(m_treeBrowser); + connect(m_treeBrowser, SIGNAL(currentItemChanged(QtBrowserItem*)), this, SLOT(slotCurrentItemChanged(QtBrowserItem*))); + connect(m_filterWidget, SIGNAL(filterChanged(QString)), this, SLOT(setFilter(QString))); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->addWidget(toolBar); + layout->addWidget(m_classLabel); + layout->addSpacerItem(new QSpacerItem(0,1)); + layout->addWidget(m_stackedWidget); + layout->setMargin(0); + layout->setSpacing(0); + + m_treeFactory = new DesignerEditorFactory(m_core, this); + m_treeFactory->setSpacing(0); + m_groupFactory = new DesignerEditorFactory(m_core, this); + QtVariantPropertyManager *variantManager = m_propertyManager; + m_buttonBrowser->setFactoryForManager(variantManager, m_groupFactory); + m_treeBrowser->setFactoryForManager(variantManager, m_treeFactory); + + m_stackedWidget->setCurrentIndex(m_treeIndex); + m_currentBrowser = m_treeBrowser; + m_treeAction->setChecked(true); + + connect(m_groupFactory, SIGNAL(resetProperty(QtProperty*)), this, SLOT(slotResetProperty(QtProperty*))); + connect(m_treeFactory, SIGNAL(resetProperty(QtProperty*)), this, SLOT(slotResetProperty(QtProperty*))); + connect(variantManager, SIGNAL(valueChanged(QtProperty*,QVariant,bool)), this, SLOT(slotValueChanged(QtProperty*,QVariant,bool))); + + // retrieve initial settings + QDesignerSettingsInterface *settings = m_core->settingsManager(); + settings->beginGroup(QLatin1String(SettingsGroupC)); +#if QT_VERSION >= 0x040500 + const SettingsView view = settings->value(QLatin1String(ViewKeyC), TreeView).toInt() == TreeView ? TreeView : ButtonView; +#endif + // Coloring not available unless treeview and not sorted + m_sorting = settings->value(QLatin1String(SortedKeyC), false).toBool(); + m_coloring = settings->value(QLatin1String(ColorKeyC), true).toBool(); + const QVariantMap expansionState = settings->value(QLatin1String(ExpansionKeyC), QVariantMap()).toMap(); + const int splitterPosition = settings->value(QLatin1String(SplitterPositionKeyC), 150).toInt(); + settings->endGroup(); + // Apply settings + m_sortingAction->setChecked(m_sorting); + m_coloringAction->setChecked(m_coloring); + m_treeBrowser->setSplitterPosition(splitterPosition); +#if QT_VERSION >= 0x040500 + switch (view) { + case TreeView: + m_currentBrowser = m_treeBrowser; + m_stackedWidget->setCurrentIndex(m_treeIndex); + m_treeAction->setChecked(true); + break; + case ButtonView: + m_currentBrowser = m_buttonBrowser; + m_stackedWidget->setCurrentIndex(m_buttonIndex); + m_buttonAction->setChecked(true); + break; + } +#endif + // Restore expansionState from QVariant map + if (!expansionState.empty()) { + const QVariantMap::const_iterator cend = expansionState.constEnd(); + for (QVariantMap::const_iterator it = expansionState.constBegin(); it != cend; ++it) + m_expansionState.insert(it.key(), it.value().toBool()); + } + updateActionsState(); +} + +PropertyEditor::~PropertyEditor() +{ + storeExpansionState(); + saveSettings(); +} + +void PropertyEditor::saveSettings() const +{ + QDesignerSettingsInterface *settings = m_core->settingsManager(); + settings->beginGroup(QLatin1String(SettingsGroupC)); +#if QT_VERSION >= 0x040500 + settings->setValue(QLatin1String(ViewKeyC), QVariant(m_treeAction->isChecked() ? TreeView : ButtonView)); +#endif + settings->setValue(QLatin1String(ColorKeyC), QVariant(m_coloring)); + settings->setValue(QLatin1String(SortedKeyC), QVariant(m_sorting)); + // Save last expansionState as QVariant map + QVariantMap expansionState; + if (!m_expansionState.empty()) { + const QMap::const_iterator cend = m_expansionState.constEnd(); + for (QMap::const_iterator it = m_expansionState.constBegin(); it != cend; ++it) + expansionState.insert(it.key(), QVariant(it.value())); + } + settings->setValue(QLatin1String(ExpansionKeyC), expansionState); + settings->setValue(QLatin1String(SplitterPositionKeyC), m_treeBrowser->splitterPosition()); + settings->endGroup(); +} + +void PropertyEditor::setExpanded(QtBrowserItem *item, bool expanded) +{ + if (m_buttonBrowser == m_currentBrowser) + m_buttonBrowser->setExpanded(item, expanded); + else if (m_treeBrowser == m_currentBrowser) + m_treeBrowser->setExpanded(item, expanded); +} + +bool PropertyEditor::isExpanded(QtBrowserItem *item) const +{ + if (m_buttonBrowser == m_currentBrowser) + return m_buttonBrowser->isExpanded(item); + else if (m_treeBrowser == m_currentBrowser) + return m_treeBrowser->isExpanded(item); + return false; +} + +void PropertyEditor::setItemVisible(QtBrowserItem *item, bool visible) +{ + if (m_currentBrowser == m_treeBrowser) { + m_treeBrowser->setItemVisible(item, visible); + } else { + qWarning("** WARNING %s is not implemented for this browser.", Q_FUNC_INFO); + } +} + +bool PropertyEditor::isItemVisible(QtBrowserItem *item) const +{ + return m_currentBrowser == m_treeBrowser ? m_treeBrowser->isItemVisible(item) : true; +} + +/* Default handling of items not found in the map: + * - Top-level items (classes) are assumed to be expanded + * - Anything below (properties) is assumed to be collapsed + * That is, the map is required, the state cannot be stored in a set */ + +void PropertyEditor::storePropertiesExpansionState(const QList &items) +{ + const QChar bar = QLatin1Char('|'); + QListIterator itProperty(items); + while (itProperty.hasNext()) { + QtBrowserItem *propertyItem = itProperty.next(); + if (!propertyItem->children().empty()) { + QtProperty *property = propertyItem->property(); + const QString propertyName = property->propertyName(); + const QMap::const_iterator itGroup = m_propertyToGroup.constFind(property); + if (itGroup != m_propertyToGroup.constEnd()) { + QString key = itGroup.value(); + key += bar; + key += propertyName; + m_expansionState[key] = isExpanded(propertyItem); + } + } + } +} + +void PropertyEditor::storeExpansionState() +{ + const QList items = m_currentBrowser->topLevelItems(); + if (m_sorting) { + storePropertiesExpansionState(items); + } else { + QListIterator itGroup(items); + while (itGroup.hasNext()) { + QtBrowserItem *item = itGroup.next(); + const QString groupName = item->property()->propertyName(); + QList propertyItems = item->children(); + if (!propertyItems.empty()) + m_expansionState[groupName] = isExpanded(item); + + // properties stuff here + storePropertiesExpansionState(propertyItems); + } + } +} + +void PropertyEditor::collapseAll() +{ + QList items = m_currentBrowser->topLevelItems(); + QListIterator itGroup(items); + while (itGroup.hasNext()) + setExpanded(itGroup.next(), false); +} + +void PropertyEditor::applyPropertiesExpansionState(const QList &items) +{ + const QChar bar = QLatin1Char('|'); + QListIterator itProperty(items); + while (itProperty.hasNext()) { + const QMap::const_iterator excend = m_expansionState.constEnd(); + QtBrowserItem *propertyItem = itProperty.next(); + QtProperty *property = propertyItem->property(); + const QString propertyName = property->propertyName(); + const QMap::const_iterator itGroup = m_propertyToGroup.constFind(property); + if (itGroup != m_propertyToGroup.constEnd()) { + QString key = itGroup.value(); + key += bar; + key += propertyName; + const QMap::const_iterator pit = m_expansionState.constFind(key); + if (pit != excend) + setExpanded(propertyItem, pit.value()); + else + setExpanded(propertyItem, false); + } + } +} + +void PropertyEditor::applyExpansionState() +{ + const QList items = m_currentBrowser->topLevelItems(); + if (m_sorting) { + applyPropertiesExpansionState(items); + } else { + QListIterator itTopLevel(items); + const QMap::const_iterator excend = m_expansionState.constEnd(); + while (itTopLevel.hasNext()) { + QtBrowserItem *item = itTopLevel.next(); + const QString groupName = item->property()->propertyName(); + const QMap::const_iterator git = m_expansionState.constFind(groupName); + if (git != excend) + setExpanded(item, git.value()); + else + setExpanded(item, true); + // properties stuff here + applyPropertiesExpansionState(item->children()); + } + } +} + +int PropertyEditor::applyPropertiesFilter(const QList &items) +{ + int showCount = 0; + const bool matchAll = m_filterPattern.isEmpty(); + QListIterator itProperty(items); + while (itProperty.hasNext()) { + QtBrowserItem *propertyItem = itProperty.next(); + QtProperty *property = propertyItem->property(); + const QString propertyName = property->propertyName(); + const bool showProperty = matchAll || propertyName.contains(m_filterPattern, Qt::CaseInsensitive); + setItemVisible(propertyItem, showProperty); + if (showProperty) + showCount++; + } + return showCount; +} + +void PropertyEditor::applyFilter() +{ + const QList items = m_currentBrowser->topLevelItems(); + if (m_sorting) { + applyPropertiesFilter(items); + } else { + QListIterator itTopLevel(items); + while (itTopLevel.hasNext()) { + QtBrowserItem *item = itTopLevel.next(); + setItemVisible(item, applyPropertiesFilter(item->children())); + } + } +} + +void PropertyEditor::clearView() +{ + m_currentBrowser->clear(); +} + +bool PropertyEditor::event(QEvent *event) +{ + if (event->type() == QEvent::PaletteChange) + updateForegroundBrightness(); + + return QDesignerPropertyEditor::event(event); +} + +void PropertyEditor::updateForegroundBrightness() +{ + QColor c = palette().color(QPalette::Text); + bool newBrightness = qRound(0.3 * c.redF() + 0.59 * c.greenF() + 0.11 * c.blueF()); + + if (m_brightness == newBrightness) + return; + + m_brightness = newBrightness; + + updateColors(); +} + +QColor PropertyEditor::propertyColor(QtProperty *property) const +{ + if (!m_coloring) + return QColor(); + + QtProperty *groupProperty = property; + + QMap::ConstIterator itProp = m_propertyToGroup.constFind(property); + if (itProp != m_propertyToGroup.constEnd()) + groupProperty = m_nameToGroup.value(itProp.value()); + + const int groupIdx = m_groups.indexOf(groupProperty); + QPair pair; + if (groupIdx != -1) { + if (groupProperty == m_dynamicGroup) + pair = m_dynamicColor; + else if (isLayoutGroup(groupProperty)) + pair = m_layoutColor; + else + pair = m_colors[groupIdx % m_colors.count()]; + } + if (!m_brightness) + return pair.first; + return pair.second; +} + +void PropertyEditor::fillView() +{ + if (m_sorting) { + QMapIterator itProperty(m_nameToProperty); + while (itProperty.hasNext()) { + QtVariantProperty *property = itProperty.next().value(); + m_currentBrowser->addProperty(property); + } + } else { + QListIterator itGroup(m_groups); + while (itGroup.hasNext()) { + QtProperty *group = itGroup.next(); + QtBrowserItem *item = m_currentBrowser->addProperty(group); + if (m_currentBrowser == m_treeBrowser) + m_treeBrowser->setBackgroundColor(item, propertyColor(group)); + group->setModified(m_currentBrowser == m_treeBrowser); + } + } +} + +bool PropertyEditor::isLayoutGroup(QtProperty *group) const +{ + return group->propertyName() == m_strings.m_layout; +} + +void PropertyEditor::updateActionsState() +{ + m_coloringAction->setEnabled(m_treeAction->isChecked() && !m_sortingAction->isChecked()); +} + +void PropertyEditor::slotViewTriggered(QAction *action) +{ + storeExpansionState(); + collapseAll(); + { + UpdateBlocker ub(this); + clearView(); + int idx = 0; + if (action == m_treeAction) { + m_currentBrowser = m_treeBrowser; + idx = m_treeIndex; + } else if (action == m_buttonAction) { + m_currentBrowser = m_buttonBrowser; + idx = m_buttonIndex; + } + fillView(); + m_stackedWidget->setCurrentIndex(idx); + applyExpansionState(); + applyFilter(); + } + updateActionsState(); +} + +void PropertyEditor::slotSorting(bool sort) +{ + if (sort == m_sorting) + return; + + storeExpansionState(); + m_sorting = sort; + collapseAll(); + { + UpdateBlocker ub(this); + clearView(); + m_treeBrowser->setRootIsDecorated(sort); + fillView(); + applyExpansionState(); + applyFilter(); + } + updateActionsState(); +} + +void PropertyEditor::updateColors() +{ + if (m_treeBrowser && m_currentBrowser == m_treeBrowser) { + QList items = m_treeBrowser->topLevelItems(); + QListIterator itItem(items); + while (itItem.hasNext()) { + QtBrowserItem *item = itItem.next(); + m_treeBrowser->setBackgroundColor(item, propertyColor(item->property())); + } + } +} + +void PropertyEditor::slotColoring(bool coloring) +{ + if (coloring == m_coloring) + return; + + m_coloring = coloring; + + updateColors(); +} + +void PropertyEditor::slotAddDynamicProperty(QAction *action) +{ + if (!m_propertySheet) + return; + + const QDesignerDynamicPropertySheetExtension *dynamicSheet = + qt_extension(m_core->extensionManager(), m_object); + + if (!dynamicSheet) + return; + + QString newName; + QVariant newValue; + { // Make sure the dialog is closed before the signal is emitted. + const QVariant::Type type = static_cast(action->data().toInt()); + NewDynamicPropertyDialog dlg(core()->dialogGui(), m_currentBrowser); + if (type != QVariant::Invalid) + dlg.setPropertyType(type); + + QStringList reservedNames; + const int propertyCount = m_propertySheet->count(); + for (int i = 0; i < propertyCount; i++) { + if (!dynamicSheet->isDynamicProperty(i) || m_propertySheet->isVisible(i)) + reservedNames.append(m_propertySheet->propertyName(i)); + } + dlg.setReservedNames(reservedNames); + if (dlg.exec() == QDialog::Rejected) + return; + newName = dlg.propertyName(); + newValue = dlg.propertyValue(); + } + m_recentlyAddedDynamicProperty = newName; + emit addDynamicProperty(newName, newValue); +} + +QDesignerFormEditorInterface *PropertyEditor::core() const +{ + return m_core; +} + +bool PropertyEditor::isReadOnly() const +{ + return false; +} + +void PropertyEditor::setReadOnly(bool /*readOnly*/) +{ + qDebug() << "PropertyEditor::setReadOnly() request"; +} + +void PropertyEditor::setPropertyValue(const QString &name, const QVariant &value, bool changed) +{ + const QMap::const_iterator it = m_nameToProperty.constFind(name); + if (it == m_nameToProperty.constEnd()) + return; + QtVariantProperty *property = it.value(); + updateBrowserValue(property, value); + property->setModified(changed); +} + +/* Quick update that assumes the actual count of properties has not changed + * N/A when for example executing a layout command and margin properties appear. */ +void PropertyEditor::updatePropertySheet() +{ + if (!m_propertySheet) + return; + + updateToolBarLabel(); + + const int propertyCount = m_propertySheet->count(); + const QMap::const_iterator npcend = m_nameToProperty.constEnd(); + for (int i = 0; i < propertyCount; ++i) { + const QString propertyName = m_propertySheet->propertyName(i); + QMap::const_iterator it = m_nameToProperty.constFind(propertyName); + if (it != npcend) + updateBrowserValue(it.value(), m_propertySheet->property(i)); + } +} + +static inline QLayout *layoutOfQLayoutWidget(QObject *o) +{ + if (o->isWidgetType() && !qstrcmp(o->metaObject()->className(), "QLayoutWidget")) + return static_cast(o)->layout(); + return 0; +} + +void PropertyEditor::updateToolBarLabel() +{ + QString objectName; + QString className; + if (m_object) { + if (QLayout *l = layoutOfQLayoutWidget(m_object)) + objectName = l->objectName(); + else + objectName = m_object->objectName(); + className = realClassName(m_object); + } + + m_classLabel->setVisible(!objectName.isEmpty() || !className.isEmpty()); + m_classLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + + QString classLabelText; + if (!objectName.isEmpty()) + classLabelText += objectName + QLatin1String(" : "); + classLabelText += className; + + m_classLabel->setText(classLabelText); + m_classLabel->setToolTip(tr("Object: %1\nClass: %2").arg(objectName).arg(className)); +} + +void PropertyEditor::updateBrowserValue(QtVariantProperty *property, const QVariant &value) +{ + QVariant v = value; + const int type = property->propertyType(); + if (type == QtVariantPropertyManager::enumTypeId()) { + const PropertySheetEnumValue e = qvariant_cast(v); + v = e.metaEnum.keys().indexOf(e.metaEnum.valueToKey(e.value)); + } else if (type == DesignerPropertyManager::designerFlagTypeId()) { + const PropertySheetFlagValue f = qvariant_cast(v); + v = QVariant(f.value); + } else if (type == DesignerPropertyManager::designerAlignmentTypeId()) { + const PropertySheetFlagValue f = qvariant_cast(v); + v = QVariant(f.value); + } + QDesignerPropertySheet *sheet = qobject_cast(m_core->extensionManager()->extension(m_object, Q_TYPEID(QDesignerPropertySheetExtension))); + int index = -1; + if (sheet) + index = sheet->indexOf(property->propertyName()); + if (sheet && m_propertyToGroup.contains(property)) { // don't do it for comments since property sheet doesn't keep them + property->setEnabled(sheet->isEnabled(index)); + } + + // Rich text string property with comment: Store/Update the font the rich text editor dialog starts out with + if (type == QVariant::String && !property->subProperties().empty()) { + const int fontIndex = m_propertySheet->indexOf(m_strings.m_fontProperty); + if (fontIndex != -1) + property->setAttribute(m_strings.m_fontAttribute, m_propertySheet->property(fontIndex)); + } + + m_updatingBrowser = true; + property->setValue(v); + if (sheet && sheet->isResourceProperty(index)) + property->setAttribute(QLatin1String("defaultResource"), sheet->defaultResourceProperty(index)); + m_updatingBrowser = false; +} + +int PropertyEditor::toBrowserType(const QVariant &value, const QString &propertyName) const +{ + if (value.canConvert()) { + if (m_strings.m_alignmentProperties.contains(propertyName)) + return DesignerPropertyManager::designerAlignmentTypeId(); + return DesignerPropertyManager::designerFlagTypeId(); + } + if (value.canConvert()) + return DesignerPropertyManager::enumTypeId(); + + return value.userType(); +} + +QString PropertyEditor::realClassName(QObject *object) const +{ + if (!object) + return QString(); + + QString className = QLatin1String(object->metaObject()->className()); + const QDesignerWidgetDataBaseInterface *db = core()->widgetDataBase(); + if (QDesignerWidgetDataBaseItemInterface *widgetItem = db->item(db->indexOfObject(object, true))) { + className = widgetItem->name(); + + if (object->isWidgetType() && className == m_strings.m_qLayoutWidget + && static_cast(object)->layout()) { + className = QLatin1String(static_cast(object)->layout()->metaObject()->className()); + } + } + + if (className.startsWith(m_strings.m_designerPrefix)) + className.remove(1, m_strings.m_designerPrefix.size() - 1); + + return className; +} + +static QString msgUnsupportedType(const QString &propertyName, unsigned type) +{ + QString rc; + QTextStream str(&rc); + str << "The property \"" << propertyName << "\" of type " << type; + if (type == QVariant::Invalid) { + str << " (invalid) "; + } else { + if (type < QVariant::UserType) { + if (const char *typeName = QVariant::typeToName(static_cast(type))) + str << " (" << typeName << ") "; + } else { + str << " (user type) "; + } + } + str << " is not supported yet!"; + return rc; +} + +void PropertyEditor::setObject(QObject *object) +{ + QDesignerFormWindowInterface *oldFormWindow = QDesignerFormWindowInterface::findFormWindow(m_object); + // In the first setObject() call following the addition of a dynamic property, focus and edit it. + const bool editNewDynamicProperty = object != 0 && m_object == object && !m_recentlyAddedDynamicProperty.isEmpty(); + m_object = object; + m_propertyManager->setObject(object); + QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(m_object); + FormWindowBase *fwb = qobject_cast(formWindow); + m_treeFactory->setFormWindowBase(fwb); + m_groupFactory->setFormWindowBase(fwb); + + storeExpansionState(); + + UpdateBlocker ub(this); + + updateToolBarLabel(); + + QMap toRemove = m_nameToProperty; + + const QDesignerDynamicPropertySheetExtension *dynamicSheet = + qt_extension(m_core->extensionManager(), m_object); + const QDesignerPropertySheet *sheet = qobject_cast(m_core->extensionManager()->extension(m_object, Q_TYPEID(QDesignerPropertySheetExtension))); + + // Optimizization: Instead of rebuilding the complete list every time, compile a list of properties to remove, + // remove them, traverse the sheet, in case property exists just set a value, otherwise - create it. + QExtensionManager *m = m_core->extensionManager(); + + m_propertySheet = qobject_cast(m->extension(object, Q_TYPEID(QDesignerPropertySheetExtension))); + if (m_propertySheet) { + const int propertyCount = m_propertySheet->count(); + for (int i = 0; i < propertyCount; ++i) { + if (!m_propertySheet->isVisible(i)) + continue; + + const QString propertyName = m_propertySheet->propertyName(i); + if (m_propertySheet->indexOf(propertyName) != i) + continue; + const QString groupName = m_propertySheet->propertyGroup(i); + const QMap::const_iterator rit = toRemove.constFind(propertyName); + if (rit != toRemove.constEnd()) { + QtVariantProperty *property = rit.value(); + if (m_propertyToGroup.value(property) == groupName && toBrowserType(m_propertySheet->property(i), propertyName) == property->propertyType()) + toRemove.remove(propertyName); + } + } + } + + QMapIterator itRemove(toRemove); + while (itRemove.hasNext()) { + itRemove.next(); + + QtVariantProperty *property = itRemove.value(); + m_nameToProperty.remove(itRemove.key()); + m_propertyToGroup.remove(property); + delete property; + } + + if (oldFormWindow != formWindow) + reloadResourceProperties(); + + bool isMainContainer = false; + if (QWidget *widget = qobject_cast(object)) { + if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(widget)) { + isMainContainer = (fw->mainContainer() == widget); + } + } + m_groups.clear(); + + if (m_propertySheet) { + QtProperty *lastProperty = 0; + QtProperty *lastGroup = 0; + const int propertyCount = m_propertySheet->count(); + for (int i = 0; i < propertyCount; ++i) { + if (!m_propertySheet->isVisible(i)) + continue; + + const QString propertyName = m_propertySheet->propertyName(i); + if (m_propertySheet->indexOf(propertyName) != i) + continue; + const QVariant value = m_propertySheet->property(i); + + const int type = toBrowserType(value, propertyName); + + QtVariantProperty *property = m_nameToProperty.value(propertyName, 0); + bool newProperty = property == 0; + if (newProperty) { + property = m_propertyManager->addProperty(type, propertyName); + if (property) { + newProperty = true; + if (type == DesignerPropertyManager::enumTypeId()) { + const PropertySheetEnumValue e = qvariant_cast(value); + QStringList names; + QStringListIterator it(e.metaEnum.keys()); + while (it.hasNext()) + names.append(it.next()); + m_updatingBrowser = true; + property->setAttribute(m_strings.m_enumNamesAttribute, names); + m_updatingBrowser = false; + } else if (type == DesignerPropertyManager::designerFlagTypeId()) { + const PropertySheetFlagValue f = qvariant_cast(value); + QList > flags; + QStringListIterator it(f.metaFlags.keys()); + while (it.hasNext()) { + const QString name = it.next(); + const uint val = f.metaFlags.keyToValue(name); + flags.append(qMakePair(name, val)); + } + m_updatingBrowser = true; + QVariant v; + v.setValue(flags); + property->setAttribute(m_strings.m_flagsAttribute, v); + m_updatingBrowser = false; + } + } + } + + if (property != 0) { + const bool dynamicProperty = (dynamicSheet && dynamicSheet->isDynamicProperty(i)) + || (sheet && sheet->isDefaultDynamicProperty(i)); + switch (type) { + case QVariant::Palette: + setupPaletteProperty(property); + break; + case QVariant::KeySequence: + //addCommentProperty(property, propertyName); + break; + default: + break; + } + if (type == QVariant::String || type == qMetaTypeId()) + setupStringProperty(property, isMainContainer); + property->setAttribute(m_strings.m_resettableAttribute, m_propertySheet->hasReset(i)); + + const QString groupName = m_propertySheet->propertyGroup(i); + QtVariantProperty *groupProperty = 0; + + if (newProperty) { + QMap::const_iterator itPrev = m_nameToProperty.insert(propertyName, property); + m_propertyToGroup[property] = groupName; + if (m_sorting) { + QtProperty *previous = 0; + if (itPrev != m_nameToProperty.constBegin()) + previous = (--itPrev).value(); + m_currentBrowser->insertProperty(property, previous); + } + } + const QMap::const_iterator gnit = m_nameToGroup.constFind(groupName); + if (gnit != m_nameToGroup.constEnd()) { + groupProperty = gnit.value(); + } else { + groupProperty = m_propertyManager->addProperty(QtVariantPropertyManager::groupTypeId(), groupName); + QtBrowserItem *item = 0; + if (!m_sorting) + item = m_currentBrowser->insertProperty(groupProperty, lastGroup); + m_nameToGroup[groupName] = groupProperty; + m_groups.append(groupProperty); + if (dynamicProperty) + m_dynamicGroup = groupProperty; + if (m_currentBrowser == m_treeBrowser && item) { + m_treeBrowser->setBackgroundColor(item, propertyColor(groupProperty)); + groupProperty->setModified(true); + } + } + /* Group changed or new group. Append to last subproperty of + * that group. Note that there are cases in which a derived + * property sheet appends fake properties for the class + * which will appear after the layout group properties + * (QWizardPage). To make them appear at the end of the + * actual class group, goto last element. */ + if (lastGroup != groupProperty) { + lastGroup = groupProperty; + lastProperty = 0; // Append at end + const QList subProperties = lastGroup->subProperties(); + if (!subProperties.empty()) + lastProperty = subProperties.back(); + lastGroup = groupProperty; + } + if (!m_groups.contains(groupProperty)) + m_groups.append(groupProperty); + if (newProperty) + groupProperty->insertSubProperty(property, lastProperty); + + lastProperty = property; + + updateBrowserValue(property, value); + + property->setModified(m_propertySheet->isChanged(i)); + if (propertyName == QLatin1String("geometry") && type == QVariant::Rect) { + QList subProperties = property->subProperties(); + foreach (QtProperty *subProperty, subProperties) { + const QString subPropertyName = subProperty->propertyName(); + if (subPropertyName == QLatin1String("X") || subPropertyName == QLatin1String("Y")) + subProperty->setEnabled(!isMainContainer); + } + } + } else { + qWarning("%s", qPrintable(msgUnsupportedType(propertyName, type))); + } + } + } + QMap groups = m_nameToGroup; + QMapIterator itGroup(groups); + while (itGroup.hasNext()) { + QtVariantProperty *groupProperty = itGroup.next().value(); + if (groupProperty->subProperties().empty()) { + if (groupProperty == m_dynamicGroup) + m_dynamicGroup = 0; + delete groupProperty; + m_nameToGroup.remove(itGroup.key()); + } + } + const bool addEnabled = dynamicSheet ? dynamicSheet->dynamicPropertiesAllowed() : false; + m_addDynamicAction->setEnabled(addEnabled); + m_removeDynamicAction->setEnabled(false); + applyExpansionState(); + applyFilter(); + // In the first setObject() call following the addition of a dynamic property, focus and edit it. + if (editNewDynamicProperty) { + // Have QApplication process the events related to completely closing the modal 'add' dialog, + // otherwise, we cannot focus the property editor in docked mode. + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + editProperty(m_recentlyAddedDynamicProperty); + } + m_recentlyAddedDynamicProperty.clear(); + m_filterWidget->setEnabled(object); +} + +void PropertyEditor::reloadResourceProperties() +{ + m_updatingBrowser = true; + m_propertyManager->reloadResourceProperties(); + m_updatingBrowser = false; +} + +QtBrowserItem *PropertyEditor::nonFakePropertyBrowserItem(QtBrowserItem *item) const +{ + // Top-level properties are QObject/QWidget groups, etc. Find first item property below + // which should be nonfake + const QList topLevelItems = m_currentBrowser->topLevelItems(); + do { + if (topLevelItems.contains(item->parent())) + return item; + item = item->parent(); + } while (item); + return 0; +} + +QString PropertyEditor::currentPropertyName() const +{ + if (QtBrowserItem *browserItem = m_currentBrowser->currentItem()) + if (QtBrowserItem *topLevelItem = nonFakePropertyBrowserItem(browserItem)) { + return topLevelItem->property()->propertyName(); + } + return QString(); +} + +void PropertyEditor::slotResetProperty(QtProperty *property) +{ + QDesignerFormWindowInterface *form = m_core->formWindowManager()->activeFormWindow(); + if (!form) + return; + + if (m_propertyManager->resetFontSubProperty(property)) + return; + + if (m_propertyManager->resetIconSubProperty(property)) + return; + + if (!m_propertyToGroup.contains(property)) + return; + + emit resetProperty(property->propertyName()); +} + +void PropertyEditor::slotValueChanged(QtProperty *property, const QVariant &value, bool enableSubPropertyHandling) +{ + if (m_updatingBrowser) + return; + + if (!m_propertySheet) + return; + + QtVariantProperty *varProp = m_propertyManager->variantProperty(property); + + if (!varProp) + return; + + if (!m_propertyToGroup.contains(property)) + return; + + if (varProp->propertyType() == QtVariantPropertyManager::enumTypeId()) { + PropertySheetEnumValue e = qvariant_cast(m_propertySheet->property(m_propertySheet->indexOf(property->propertyName()))); + const int val = value.toInt(); + const QString valName = varProp->attributeValue(m_strings.m_enumNamesAttribute).toStringList().at(val); + bool ok = false; + e.value = e.metaEnum.parseEnum(valName, &ok); + Q_ASSERT(ok); + QVariant v; + v.setValue(e); + emitPropertyValueChanged(property->propertyName(), v, true); + return; + } + + emitPropertyValueChanged(property->propertyName(), value, enableSubPropertyHandling); +} + +bool PropertyEditor::isDynamicProperty(const QtBrowserItem* item) const +{ + if (!item) + return false; + + const QDesignerDynamicPropertySheetExtension *dynamicSheet = + qt_extension(m_core->extensionManager(), m_object); + + if (!dynamicSheet) + return false; + + if (m_propertyToGroup.contains(item->property()) + && dynamicSheet->isDynamicProperty(m_propertySheet->indexOf(item->property()->propertyName()))) + return true; + return false; +} + +void PropertyEditor::editProperty(const QString &name) +{ + // find the browser item belonging to the property, make it current and edit it + QtBrowserItem *browserItem = 0; + if (QtVariantProperty *property = m_nameToProperty.value(name, 0)) { + const QList items = m_currentBrowser->items(property); + if (items.size() == 1) + browserItem = items.front(); + } + if (browserItem == 0) + return; + m_currentBrowser->setFocus(Qt::OtherFocusReason); + if (m_currentBrowser == m_treeBrowser) { // edit is currently only supported in tree view + m_treeBrowser->editItem(browserItem); + } else { + m_currentBrowser->setCurrentItem(browserItem); + } +} + +void PropertyEditor::slotCurrentItemChanged(QtBrowserItem *item) +{ + m_removeDynamicAction->setEnabled(isDynamicProperty(item)); + +} + +void PropertyEditor::slotRemoveDynamicProperty() +{ + if (QtBrowserItem* item = m_currentBrowser->currentItem()) + if (isDynamicProperty(item)) + emit removeDynamicProperty(item->property()->propertyName()); +} + +void PropertyEditor::setFilter(const QString &pattern) +{ + m_filterPattern = pattern; + applyFilter(); +} +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/propertyeditor/propertyeditor.h b/src/designer/src/components/propertyeditor/propertyeditor.h new file mode 100644 index 000000000..7278a3de9 --- /dev/null +++ b/src/designer/src/components/propertyeditor/propertyeditor.h @@ -0,0 +1,207 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PROPERTYEDITOR_H +#define PROPERTYEDITOR_H + +#include "propertyeditor_global.h" +#include + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class DomProperty; +class QDesignerMetaDataBaseItemInterface; +class QDesignerPropertySheetExtension; + +class QtAbstractPropertyBrowser; +class QtButtonPropertyBrowser; +class QtTreePropertyBrowser; +class QtProperty; +class QtVariantProperty; +class QtBrowserItem; +class QStackedWidget; + +namespace qdesigner_internal { + +class StringProperty; +class DesignerPropertyManager; +class DesignerEditorFactory; +class FilterWidget; +class ElidingLabel; + +class QT_PROPERTYEDITOR_EXPORT PropertyEditor: public QDesignerPropertyEditor +{ + Q_OBJECT +public: + explicit PropertyEditor(QDesignerFormEditorInterface *core, QWidget *parent = 0, Qt::WindowFlags flags = 0); + virtual ~PropertyEditor(); + + virtual QDesignerFormEditorInterface *core() const; + + virtual bool isReadOnly() const; + virtual void setReadOnly(bool readOnly); + virtual void setPropertyValue(const QString &name, const QVariant &value, bool changed = true); + virtual void updatePropertySheet(); + + virtual void setObject(QObject *object); + + void reloadResourceProperties(); + + virtual QObject *object() const + { return m_object; } + + virtual QString currentPropertyName() const; + +protected: + + bool event(QEvent *event); + +private slots: + void slotResetProperty(QtProperty *property); + void slotValueChanged(QtProperty *property, const QVariant &value, bool enableSubPropertyHandling); + void slotViewTriggered(QAction *action); + void slotAddDynamicProperty(QAction *action); + void slotRemoveDynamicProperty(); + void slotSorting(bool sort); + void slotColoring(bool color); + void slotCurrentItemChanged(QtBrowserItem*); + void setFilter(const QString &pattern); + +private: + void updateBrowserValue(QtVariantProperty *property, const QVariant &value); + void updateToolBarLabel(); + int toBrowserType(const QVariant &value, const QString &propertyName) const; + QString removeScope(const QString &value) const; + QDesignerMetaDataBaseItemInterface *metaDataBaseItem() const; + void setupStringProperty(QtVariantProperty *property, bool isMainContainer); + void setupPaletteProperty(QtVariantProperty *property); + QString realClassName(QObject *object) const; + void storeExpansionState(); + void applyExpansionState(); + void storePropertiesExpansionState(const QList &items); + void applyPropertiesExpansionState(const QList &items); + void applyFilter(); + int applyPropertiesFilter(const QList &items); + void setExpanded(QtBrowserItem *item, bool expanded); + bool isExpanded(QtBrowserItem *item) const; + void setItemVisible(QtBrowserItem *item, bool visible); + bool isItemVisible(QtBrowserItem *item) const; + void collapseAll(); + void clearView(); + void fillView(); + bool isLayoutGroup(QtProperty *group) const; + void updateColors(); + void updateForegroundBrightness(); + QColor propertyColor(QtProperty *property) const; + void updateActionsState(); + QtBrowserItem *nonFakePropertyBrowserItem(QtBrowserItem *item) const; + void saveSettings() const; + void editProperty(const QString &name); + bool isDynamicProperty(const QtBrowserItem* item) const; + + struct Strings { + Strings(); + QSet m_alignmentProperties; + const QString m_fontProperty; + const QString m_qLayoutWidget; + const QString m_designerPrefix; + const QString m_layout; + const QString m_validationModeAttribute; + const QString m_fontAttribute; + const QString m_superPaletteAttribute; + const QString m_enumNamesAttribute; + const QString m_resettableAttribute; + const QString m_flagsAttribute; + }; + + const Strings m_strings; + QDesignerFormEditorInterface *m_core; + QDesignerPropertySheetExtension *m_propertySheet; + QtAbstractPropertyBrowser *m_currentBrowser; + QtButtonPropertyBrowser *m_buttonBrowser; + QtTreePropertyBrowser *m_treeBrowser; + DesignerPropertyManager *m_propertyManager; + DesignerEditorFactory *m_treeFactory; + DesignerEditorFactory *m_groupFactory; + QPointer m_object; + QMap m_nameToProperty; + QMap m_propertyToGroup; + QMap m_nameToGroup; + QList m_groups; + QtProperty *m_dynamicGroup; + QString m_recentlyAddedDynamicProperty; + bool m_updatingBrowser; + + QStackedWidget *m_stackedWidget; + FilterWidget *m_filterWidget; + int m_buttonIndex; + int m_treeIndex; + QAction *m_addDynamicAction; + QAction *m_removeDynamicAction; + QAction *m_sortingAction; + QAction *m_coloringAction; + QAction *m_treeAction; + QAction *m_buttonAction; + ElidingLabel *m_classLabel; + + bool m_sorting; + bool m_coloring; + + QMap m_expansionState; + + QString m_filterPattern; + QVector > m_colors; + QPair m_dynamicColor; + QPair m_layoutColor; + + bool m_brightness; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // PROPERTYEDITOR_H diff --git a/src/designer/src/components/propertyeditor/propertyeditor.pri b/src/designer/src/components/propertyeditor/propertyeditor.pri new file mode 100644 index 000000000..bb1afdb94 --- /dev/null +++ b/src/designer/src/components/propertyeditor/propertyeditor.pri @@ -0,0 +1,52 @@ +#the next line prevents non-shadowbuilds from including the same directory twice +#otherwise, the build command would be too long for some win32 shells. +!exists($$QT_BUILD_TREE/tools/designer/src/components/propertyeditor/propertyeditor.h):INCLUDEPATH += $$QT_BUILD_TREE/tools/designer/src/components/propertyeditor + +INCLUDEPATH += $$PWD + +# --- Property browser is also linked into the designer_shared library. +# Avoid conflict when linking statically +contains(CONFIG, static) { + INCLUDEPATH *= $$QT_SOURCE_TREE/tools/shared/qtpropertybrowser + INCLUDEPATH *= $$QT_SOURCE_TREE/tools/shared/qtgradienteditor +} else { + include(../../../../shared/qtpropertybrowser/qtpropertybrowser.pri) + include(../../../../shared/qtgradienteditor/qtcolorbutton.pri) +} + +FORMS += $$PWD/paletteeditor.ui \ + $$PWD/stringlisteditor.ui \ + $$PWD/previewwidget.ui \ + $$PWD/newdynamicpropertydialog.ui + +HEADERS += $$PWD/propertyeditor.h \ + $$PWD/designerpropertymanager.h \ + $$PWD/paletteeditor.h \ + $$PWD/paletteeditorbutton.h \ + $$PWD/stringlisteditor.h \ + $$PWD/stringlisteditorbutton.h \ + $$PWD/previewwidget.h \ + $$PWD/previewframe.h \ + $$PWD/newdynamicpropertydialog.h \ + $$PWD/brushpropertymanager.h \ + $$PWD/fontpropertymanager.h + +SOURCES += $$PWD/propertyeditor.cpp \ + $$PWD/designerpropertymanager.cpp \ + $$PWD/paletteeditor.cpp \ + $$PWD/paletteeditorbutton.cpp \ + $$PWD/stringlisteditor.cpp \ + $$PWD/stringlisteditorbutton.cpp \ + $$PWD/previewwidget.cpp \ + $$PWD/previewframe.cpp \ + $$PWD/newdynamicpropertydialog.cpp \ + $$PWD/brushpropertymanager.cpp \ + $$PWD/fontpropertymanager.cpp + +HEADERS += \ + $$PWD/propertyeditor_global.h \ + $$PWD/qlonglongvalidator.h + +SOURCES += $$PWD/qlonglongvalidator.cpp + +RESOURCES += $$PWD/propertyeditor.qrc diff --git a/src/designer/src/components/propertyeditor/propertyeditor.qrc b/src/designer/src/components/propertyeditor/propertyeditor.qrc new file mode 100644 index 000000000..68008eca8 --- /dev/null +++ b/src/designer/src/components/propertyeditor/propertyeditor.qrc @@ -0,0 +1,5 @@ + + + fontmapping.xml + + diff --git a/src/designer/src/components/propertyeditor/propertyeditor_global.h b/src/designer/src/components/propertyeditor/propertyeditor_global.h new file mode 100644 index 000000000..f173392f5 --- /dev/null +++ b/src/designer/src/components/propertyeditor/propertyeditor_global.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PROPERTYEDITOR_GLOBAL_H +#define PROPERTYEDITOR_GLOBAL_H + +#include + +QT_BEGIN_NAMESPACE + +#ifdef Q_OS_WIN +#ifdef QT_PROPERTYEDITOR_LIBRARY +# define QT_PROPERTYEDITOR_EXPORT +#else +# define QT_PROPERTYEDITOR_EXPORT +#endif +#else +#define QT_PROPERTYEDITOR_EXPORT +#endif + +QT_END_NAMESPACE + +#endif // PROPERTYEDITOR_GLOBAL_H diff --git a/src/designer/src/components/propertyeditor/qlonglongvalidator.cpp b/src/designer/src/components/propertyeditor/qlonglongvalidator.cpp new file mode 100644 index 000000000..9396009b3 --- /dev/null +++ b/src/designer/src/components/propertyeditor/qlonglongvalidator.cpp @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlonglongvalidator.h" + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +// ---------------------------------------------------------------------------- +QLongLongValidator::QLongLongValidator(QObject * parent) + : QValidator(parent), + b(Q_UINT64_C(0x8000000000000000)), t(Q_UINT64_C(0x7FFFFFFFFFFFFFFF)) +{ +} + +QLongLongValidator::QLongLongValidator(qlonglong minimum, qlonglong maximum, + QObject * parent) + : QValidator(parent), b(minimum), t(maximum) +{ +} + +QLongLongValidator::~QLongLongValidator() +{ + // nothing +} + +QValidator::State QLongLongValidator::validate(QString & input, int &) const +{ + if (input.contains(QLatin1Char(' '))) + return Invalid; + if (input.isEmpty() || (b < 0 && input == QString(QLatin1Char('-')))) + return Intermediate; + bool ok; + qlonglong entered = input.toLongLong(&ok); + if (!ok || (entered < 0 && b >= 0)) { + return Invalid; + } else if (entered >= b && entered <= t) { + return Acceptable; + } else { + if (entered >= 0) + return (entered > t) ? Invalid : Intermediate; + else + return (entered < b) ? Invalid : Intermediate; + } +} + +void QLongLongValidator::setRange(qlonglong bottom, qlonglong top) +{ + b = bottom; + t = top; +} + +void QLongLongValidator::setBottom(qlonglong bottom) +{ + setRange(bottom, top()); +} + +void QLongLongValidator::setTop(qlonglong top) +{ + setRange(bottom(), top); +} + + +// ---------------------------------------------------------------------------- +QULongLongValidator::QULongLongValidator(QObject * parent) + : QValidator(parent), + b(0), t(Q_UINT64_C(0xFFFFFFFFFFFFFFFF)) +{ +} + +QULongLongValidator::QULongLongValidator(qulonglong minimum, qulonglong maximum, + QObject * parent) + : QValidator(parent), b(minimum), t(maximum) +{ +} + +QULongLongValidator::~QULongLongValidator() +{ + // nothing +} + +QValidator::State QULongLongValidator::validate(QString & input, int &) const +{ + if (input.isEmpty()) + return Intermediate; + + bool ok; + qulonglong entered = input.toULongLong(&ok); + if (input.contains(QLatin1Char(' ')) || input.contains(QLatin1Char('-')) || !ok) + return Invalid; + + if (entered >= b && entered <= t) + return Acceptable; + + return Invalid; +} + +void QULongLongValidator::setRange(qulonglong bottom, qulonglong top) +{ + b = bottom; + t = top; +} + +void QULongLongValidator::setBottom(qulonglong bottom) +{ + setRange(bottom, top()); +} + +void QULongLongValidator::setTop(qulonglong top) +{ + setRange(bottom(), top); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/propertyeditor/qlonglongvalidator.h b/src/designer/src/components/propertyeditor/qlonglongvalidator.h new file mode 100644 index 000000000..122351e4a --- /dev/null +++ b/src/designer/src/components/propertyeditor/qlonglongvalidator.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QLONGLONGVALIDATOR_H +#define QLONGLONGVALIDATOR_H + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QLongLongValidator : public QValidator +{ + Q_OBJECT + Q_PROPERTY(qlonglong bottom READ bottom WRITE setBottom) + Q_PROPERTY(qlonglong top READ top WRITE setTop) + +public: + explicit QLongLongValidator(QObject * parent); + QLongLongValidator(qlonglong bottom, qlonglong top, QObject * parent); + ~QLongLongValidator(); + + QValidator::State validate(QString &, int &) const; + + void setBottom(qlonglong); + void setTop(qlonglong); + virtual void setRange(qlonglong bottom, qlonglong top); + + qlonglong bottom() const { return b; } + qlonglong top() const { return t; } + +private: + Q_DISABLE_COPY(QLongLongValidator) + + qlonglong b; + qlonglong t; +}; + +// ---------------------------------------------------------------------------- +class QULongLongValidator : public QValidator +{ + Q_OBJECT + Q_PROPERTY(qulonglong bottom READ bottom WRITE setBottom) + Q_PROPERTY(qulonglong top READ top WRITE setTop) + +public: + explicit QULongLongValidator(QObject * parent); + QULongLongValidator(qulonglong bottom, qulonglong top, QObject * parent); + ~QULongLongValidator(); + + QValidator::State validate(QString &, int &) const; + + void setBottom(qulonglong); + void setTop(qulonglong); + virtual void setRange(qulonglong bottom, qulonglong top); + + qulonglong bottom() const { return b; } + qulonglong top() const { return t; } + +private: + Q_DISABLE_COPY(QULongLongValidator) + + qulonglong b; + qulonglong t; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QLONGLONGVALIDATOR_H diff --git a/src/designer/src/components/propertyeditor/stringlisteditor.cpp b/src/designer/src/components/propertyeditor/stringlisteditor.cpp new file mode 100644 index 000000000..cd55eff2e --- /dev/null +++ b/src/designer/src/components/propertyeditor/stringlisteditor.cpp @@ -0,0 +1,212 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "stringlisteditor.h" +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +StringListEditor::StringListEditor(QWidget *parent) + : QDialog(parent), m_model(new QStringListModel(this)) +{ + setupUi(this); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + listView->setModel(m_model); + + connect(listView->selectionModel(), + SIGNAL(currentChanged(QModelIndex,QModelIndex)), + this, SLOT(currentIndexChanged(QModelIndex,QModelIndex))); + connect(listView->itemDelegate(), + SIGNAL(closeEditor(QWidget*,QAbstractItemDelegate::EndEditHint)), + this, SLOT(currentValueChanged())); + + QIcon upIcon = createIconSet(QString::fromUtf8("up.png")); + QIcon downIcon = createIconSet(QString::fromUtf8("down.png")); + QIcon minusIcon = createIconSet(QString::fromUtf8("minus.png")); + QIcon plusIcon = createIconSet(QString::fromUtf8("plus.png")); + upButton->setIcon(upIcon); + downButton->setIcon(downIcon); + newButton->setIcon(plusIcon); + deleteButton->setIcon(minusIcon); + + updateUi(); +} + +StringListEditor::~StringListEditor() +{ +} + +QStringList StringListEditor::getStringList(QWidget *parent, const QStringList &init, int *result) +{ + StringListEditor dlg(parent); + dlg.setStringList(init); + int res = dlg.exec(); + if (result) + *result = res; + return (res == QDialog::Accepted) ? dlg.stringList() : init; +} + +void StringListEditor::setStringList(const QStringList &stringList) +{ + m_model->setStringList(stringList); + updateUi(); +} + +QStringList StringListEditor::stringList() const +{ + return m_model->stringList(); +} + +void StringListEditor::currentIndexChanged(const QModelIndex ¤t, const QModelIndex &previous) +{ + Q_UNUSED(previous); + setCurrentIndex(current.row()); + updateUi(); +} + +void StringListEditor::currentValueChanged() +{ + setCurrentIndex(currentIndex()); + updateUi(); +} + +void StringListEditor::on_upButton_clicked() +{ + int from = currentIndex(); + int to = currentIndex() - 1; + QString value = stringAt(from); + removeString(from); + insertString(to, value); + setCurrentIndex(to); + updateUi(); +} + +void StringListEditor::on_downButton_clicked() +{ + int from = currentIndex(); + int to = currentIndex() + 1; + QString value = stringAt(from); + removeString(from); + insertString(to, value); + setCurrentIndex(to); + updateUi(); +} + +void StringListEditor::on_newButton_clicked() +{ + int to = currentIndex(); + if (to == -1) + to = count() - 1; + ++to; + insertString(to, QString()); + setCurrentIndex(to); + updateUi(); + editString(to); +} + +void StringListEditor::on_deleteButton_clicked() +{ + removeString(currentIndex()); + setCurrentIndex(currentIndex()); + updateUi(); +} + +void StringListEditor::on_valueEdit_textEdited(const QString &text) +{ + setStringAt(currentIndex(), text); +} + +void StringListEditor::updateUi() +{ + upButton->setEnabled((count() > 1) && (currentIndex() > 0)); + downButton->setEnabled((count() > 1) && (currentIndex() >= 0) && (currentIndex() < (count() - 1))); + deleteButton->setEnabled(currentIndex() != -1); + valueEdit->setEnabled(currentIndex() != -1); +} + +int StringListEditor::currentIndex() const +{ + return listView->currentIndex().row(); +} + +void StringListEditor::setCurrentIndex(int index) +{ + QModelIndex modelIndex = m_model->index(index, 0); + if (listView->currentIndex() != modelIndex) + listView->setCurrentIndex(modelIndex); + valueEdit->setText(stringAt(index)); +} + +int StringListEditor::count() const +{ + return m_model->rowCount(); +} + +QString StringListEditor::stringAt(int index) const +{ + return qvariant_cast(m_model->data(m_model->index(index, 0), Qt::DisplayRole)); +} + +void StringListEditor::setStringAt(int index, const QString &value) +{ + m_model->setData(m_model->index(index, 0), value); +} + +void StringListEditor::removeString(int index) +{ + m_model->removeRows(index, 1); +} + +void StringListEditor::insertString(int index, const QString &value) +{ + m_model->insertRows(index, 1); + m_model->setData(m_model->index(index, 0), value); +} + +void StringListEditor::editString(int index) +{ + listView->edit(m_model->index(index, 0)); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/propertyeditor/stringlisteditor.h b/src/designer/src/components/propertyeditor/stringlisteditor.h new file mode 100644 index 000000000..8848d52d2 --- /dev/null +++ b/src/designer/src/components/propertyeditor/stringlisteditor.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef STRINGLISTEDITOR_H +#define STRINGLISTEDITOR_H + +#include "ui_stringlisteditor.h" +#include + +QT_BEGIN_NAMESPACE +class QStringListModel; + +namespace qdesigner_internal { + +class StringListEditor : public QDialog, private Ui::Dialog +{ + Q_OBJECT +public: + ~StringListEditor(); + void setStringList(const QStringList &stringList); + QStringList stringList() const; + + static QStringList getStringList( + QWidget *parent, const QStringList &init = QStringList(), int *result = 0); + +private slots: + void on_upButton_clicked(); + void on_downButton_clicked(); + void on_newButton_clicked(); + void on_deleteButton_clicked(); + void on_valueEdit_textEdited(const QString &text); + void currentIndexChanged(const QModelIndex ¤t, const QModelIndex &previous); + void currentValueChanged(); + +private: + StringListEditor(QWidget *parent = 0); + void updateUi(); + int currentIndex() const; + void setCurrentIndex(int index); + int count() const; + QString stringAt(int index) const; + void setStringAt(int index, const QString &value); + void removeString(int index); + void insertString(int index, const QString &value); + void editString(int index); + + QStringListModel *m_model; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // STRINGLISTEDITOR_H diff --git a/src/designer/src/components/propertyeditor/stringlisteditor.ui b/src/designer/src/components/propertyeditor/stringlisteditor.ui new file mode 100644 index 000000000..b206789b6 --- /dev/null +++ b/src/designer/src/components/propertyeditor/stringlisteditor.ui @@ -0,0 +1,265 @@ + + ********************************************************************* +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +********************************************************************* + qdesigner_internal::Dialog + + + + 0 + 0 + 400 + 300 + + + + Dialog + + + + 9 + + + 6 + + + + + StringList + + + + 9 + + + 6 + + + + + 0 + + + 6 + + + + + 0 + + + 6 + + + + + New String + + + &New + + + Qt::ToolButtonTextBesideIcon + + + + + + + Delete String + + + &Delete + + + Qt::ToolButtonTextBesideIcon + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + + + 6 + + + + + &Value: + + + valueEdit + + + + + + + + + + + + + + 0 + + + 6 + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Move String Up + + + Up + + + + + + + Move String Down + + + Down + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + qdesigner_internal::Dialog + accept() + + + 258 + 283 + + + 138 + 294 + + + + + buttonBox + rejected() + qdesigner_internal::Dialog + reject() + + + 350 + 284 + + + 369 + 295 + + + + + diff --git a/src/designer/src/components/propertyeditor/stringlisteditorbutton.cpp b/src/designer/src/components/propertyeditor/stringlisteditorbutton.cpp new file mode 100644 index 000000000..9e858cce1 --- /dev/null +++ b/src/designer/src/components/propertyeditor/stringlisteditorbutton.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "stringlisteditorbutton.h" +#include "stringlisteditor.h" + +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +StringListEditorButton::StringListEditorButton( + const QStringList &stringList, QWidget *parent) + : QToolButton(parent), m_stringList(stringList) +{ + setFocusPolicy(Qt::NoFocus); + setText(tr("Change String List")); + setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); + + connect(this, SIGNAL(clicked()), this, SLOT(showStringListEditor())); +} + +StringListEditorButton::~StringListEditorButton() +{ +} + +void StringListEditorButton::setStringList(const QStringList &stringList) +{ + m_stringList = stringList; +} + +void StringListEditorButton::showStringListEditor() +{ + int result; + QStringList lst = StringListEditor::getStringList(0, m_stringList, &result); + if (result == QDialog::Accepted) { + m_stringList = lst; + emit stringListChanged(m_stringList); + } +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/propertyeditor/stringlisteditorbutton.h b/src/designer/src/components/propertyeditor/stringlisteditorbutton.h new file mode 100644 index 000000000..07bd291f5 --- /dev/null +++ b/src/designer/src/components/propertyeditor/stringlisteditorbutton.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef STRINGLISTEDITORBUTTON_H +#define STRINGLISTEDITORBUTTON_H + +#include "propertyeditor_global.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QT_PROPERTYEDITOR_EXPORT StringListEditorButton: public QToolButton +{ + Q_OBJECT +public: + explicit StringListEditorButton(const QStringList &stringList, QWidget *parent = 0); + virtual ~StringListEditorButton(); + + inline QStringList stringList() const + { return m_stringList; } + +signals: + void stringListChanged(const QStringList &stringList); + +public slots: + void setStringList(const QStringList &stringList); + +private slots: + void showStringListEditor(); + +private: + QStringList m_stringList; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // STRINGLISTEDITORBUTTON_H diff --git a/src/designer/src/components/signalsloteditor/connectdialog.cpp b/src/designer/src/components/signalsloteditor/connectdialog.cpp new file mode 100644 index 000000000..64be11345 --- /dev/null +++ b/src/designer/src/components/signalsloteditor/connectdialog.cpp @@ -0,0 +1,335 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "connectdialog_p.h" +#include "signalslot_utils_p.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace { + typedef QList ListWidgetItems; +} + +static QString realClassName(QDesignerFormEditorInterface *core, QWidget *widget) +{ + QString class_name = QLatin1String(widget->metaObject()->className()); + const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase(); + const int idx = wdb->indexOfObject(widget); + if (idx != -1) + class_name = wdb->item(idx)->name(); + return class_name; +} + +static QString widgetLabel(QDesignerFormEditorInterface *core, QWidget *widget) +{ + return QString::fromUtf8("%1 (%2)") + .arg(qdesigner_internal::realObjectName(core, widget)) + .arg(realClassName(core, widget)); +} + +namespace qdesigner_internal { + +ConnectDialog::ConnectDialog(QDesignerFormWindowInterface *formWindow, + QWidget *source, QWidget *destination, + QWidget *parent) : + QDialog(parent), + m_source(source), + m_destination(destination), + m_sourceMode(widgetMode(m_source, formWindow)), + m_destinationMode(widgetMode(m_destination, formWindow)), + m_formWindow(formWindow) +{ + m_ui.setupUi(this); + + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + connect(m_ui.signalList, SIGNAL(itemClicked(QListWidgetItem*)), + this, SLOT(selectSignal(QListWidgetItem*))); + connect(m_ui.slotList, SIGNAL(itemClicked(QListWidgetItem*)), + this, SLOT(selectSlot(QListWidgetItem*))); + m_ui.slotList->setEnabled(false); + + QPushButton *ok_button = okButton(); + ok_button->setDefault(true); + ok_button->setEnabled(false); + + connect(m_ui.showAllCheckBox, SIGNAL(toggled(bool)), this, SLOT(populateLists())); + + QDesignerFormEditorInterface *core = m_formWindow->core(); + m_ui.signalGroupBox->setTitle(widgetLabel(core, source)); + m_ui.slotGroupBox->setTitle(widgetLabel(core, destination)); + + m_ui.editSignalsButton->setEnabled(m_sourceMode != NormalWidget); + connect(m_ui.editSignalsButton, SIGNAL(clicked()), this, SLOT(editSignals())); + + m_ui.editSlotsButton->setEnabled(m_destinationMode != NormalWidget); + connect(m_ui.editSlotsButton, SIGNAL(clicked()), this, SLOT(editSlots())); + + populateLists(); +} + +ConnectDialog::WidgetMode ConnectDialog::widgetMode(QWidget *w, QDesignerFormWindowInterface *formWindow) +{ + QDesignerFormEditorInterface *core = formWindow->core(); + if (qt_extension(core->extensionManager(), core)) + return NormalWidget; + + if (w == formWindow || formWindow->mainContainer() == w) + return MainContainer; + + if (isPromoted(formWindow->core(), w)) + return PromotedWidget; + + return NormalWidget; +} + +QPushButton *ConnectDialog::okButton() +{ + return m_ui.buttonBox->button(QDialogButtonBox::Ok); +} + +void ConnectDialog::setOkButtonEnabled(bool e) +{ + okButton()->setEnabled(e); +} + +void ConnectDialog::populateLists() +{ + populateSignalList(); +} + +void ConnectDialog::setSignalSlot(const QString &signal, const QString &slot) +{ + ListWidgetItems sigItems = m_ui.signalList->findItems(signal, Qt::MatchExactly); + + if (sigItems.empty()) { + m_ui.showAllCheckBox->setChecked(true); + sigItems = m_ui.signalList->findItems(signal, Qt::MatchExactly); + } + + if (!sigItems.empty()) { + selectSignal(sigItems.front()); + ListWidgetItems slotItems = m_ui.slotList->findItems(slot, Qt::MatchExactly); + if (slotItems.empty()) { + m_ui.showAllCheckBox->setChecked(true); + slotItems = m_ui.slotList->findItems(slot, Qt::MatchExactly); + } + if (!slotItems.empty()) + selectSlot(slotItems.front()); + } +} + +bool ConnectDialog::showAllSignalsSlots() const +{ + return m_ui.showAllCheckBox->isChecked(); +} + +void ConnectDialog::setShowAllSignalsSlots(bool showIt) +{ + m_ui.showAllCheckBox->setChecked(showIt); +} + +void ConnectDialog::selectSignal(QListWidgetItem *item) +{ + if (item) { + m_ui.signalList->setCurrentItem(item); + populateSlotList(item->text()); + m_ui.slotList->setEnabled(true); + setOkButtonEnabled(!m_ui.slotList->selectedItems().isEmpty()); + } else { + m_ui.signalList->clearSelection(); + populateSlotList(); + m_ui.slotList->setEnabled(false); + setOkButtonEnabled(false); + } +} + +void ConnectDialog::selectSlot(QListWidgetItem *item) +{ + if (item) { + m_ui.slotList->setCurrentItem(item); + } else { + m_ui.slotList->clearSelection(); + } + setOkButtonEnabled(true); +} + +QString ConnectDialog::signal() const +{ + const ListWidgetItems item_list = m_ui.signalList->selectedItems(); + if (item_list.size() != 1) + return QString(); + return item_list.at(0)->text(); +} + +QString ConnectDialog::slot() const +{ + const ListWidgetItems item_list = m_ui.slotList->selectedItems(); + if (item_list.size() != 1) + return QString(); + return item_list.at(0)->text(); +} + +void ConnectDialog::populateSlotList(const QString &signal) +{ + QString selectedName; + if (const QListWidgetItem * item = m_ui.slotList->currentItem()) + selectedName = item->text(); + + m_ui.slotList->clear(); + + QMap memberToClassName = getMatchingSlots(m_formWindow->core(), m_destination, signal, showAllSignalsSlots()); + + QFont font = QApplication::font(); + font.setItalic(true); + QVariant variantFont = QVariant::fromValue(font); + + QListWidgetItem *curr = 0; + QMap::ConstIterator itMember = memberToClassName.constBegin(); + const QMap::ConstIterator itMemberEnd = memberToClassName.constEnd(); + while (itMember != itMemberEnd) { + const QString member = itMember.key(); + const bool qt3Slot = isQt3Slot(m_formWindow->core(), m_destination, member); + + QListWidgetItem *item = new QListWidgetItem(m_ui.slotList); + item->setText(member); + if (member == selectedName) + curr = item; + + if (qt3Slot) { + item->setData(Qt::FontRole, variantFont); + item->setData(Qt::ForegroundRole, Qt::red); + } + ++itMember; + } + + if (curr) + m_ui.slotList->setCurrentItem(curr); + + if (m_ui.slotList->selectedItems().isEmpty()) + setOkButtonEnabled(false); +} + +void ConnectDialog::populateSignalList() +{ + QString selectedName; + if (const QListWidgetItem *item = m_ui.signalList->currentItem()) + selectedName = item->text(); + + m_ui.signalList->clear(); + + QMap memberToClassName = getSignals(m_formWindow->core(), m_source, showAllSignalsSlots()); + + QFont font = QApplication::font(); + font.setItalic(true); + QVariant variantFont = QVariant::fromValue(font); + + QListWidgetItem *curr = 0; + QMap::ConstIterator itMember = memberToClassName.constBegin(); + const QMap::ConstIterator itMemberEnd = memberToClassName.constEnd(); + while (itMember != itMemberEnd) { + const QString member = itMember.key(); + const bool qt3Signal = isQt3Signal(m_formWindow->core(), m_source, member); + + QListWidgetItem *item = new QListWidgetItem(m_ui.signalList); + item->setText(member); + if (!selectedName.isEmpty() && member == selectedName) + curr = item; + + if (qt3Signal) { + item->setData(Qt::FontRole, variantFont); + item->setData(Qt::ForegroundRole, Qt::red); + } + ++itMember; + } + + if (curr) { + m_ui.signalList->setCurrentItem(curr); + } else { + selectedName.clear(); + } + + populateSlotList(selectedName); + if (!curr) + m_ui.slotList->setEnabled(false); +} + +void ConnectDialog::editSignals() +{ + editSignalsSlots(m_source, m_sourceMode, SignalSlotDialog::FocusSignals); +} + +void ConnectDialog::editSlots() +{ + editSignalsSlots(m_destination, m_destinationMode, SignalSlotDialog::FocusSlots); +} + +void ConnectDialog::editSignalsSlots(QWidget *w, WidgetMode mode, int signalSlotDialogModeInt) +{ + const SignalSlotDialog::FocusMode signalSlotDialogMode = static_cast(signalSlotDialogModeInt); + switch (mode) { + case NormalWidget: + break; + case MainContainer: + if (SignalSlotDialog::editMetaDataBase(m_formWindow, w, this, signalSlotDialogMode)) + populateLists(); + break; + case PromotedWidget: + if (SignalSlotDialog::editPromotedClass(m_formWindow->core(), w, this, signalSlotDialogMode)) + populateLists(); + break; + } +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/signalsloteditor/connectdialog.ui b/src/designer/src/components/signalsloteditor/connectdialog.ui new file mode 100644 index 000000000..568516a42 --- /dev/null +++ b/src/designer/src/components/signalsloteditor/connectdialog.ui @@ -0,0 +1,150 @@ + + ConnectDialog + + + + 0 + 0 + 585 + 361 + + + + Configure Connection + + + + + + GroupBox + + + + + + Qt::ElideMiddle + + + + + + + + + Edit... + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + GroupBox + + + + + + Qt::ElideMiddle + + + + + + + + + Edit... + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Show signals and slots inherited from QWidget + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + ConnectDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ConnectDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/designer/src/components/signalsloteditor/connectdialog_p.h b/src/designer/src/components/signalsloteditor/connectdialog_p.h new file mode 100644 index 000000000..dd81483d5 --- /dev/null +++ b/src/designer/src/components/signalsloteditor/connectdialog_p.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CONNECTDIALOG_H +#define CONNECTDIALOG_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "ui_connectdialog.h" +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QPushButton; + +namespace qdesigner_internal { + +class ConnectDialog : public QDialog +{ + Q_OBJECT +public: + ConnectDialog(QDesignerFormWindowInterface *formWindow, QWidget *sender, QWidget *receiver, QWidget *parent = 0); + + QString signal() const; + QString slot() const; + + void setSignalSlot(const QString &signal, const QString &slot); + + bool showAllSignalsSlots() const; + void setShowAllSignalsSlots(bool showIt); + +private slots: + void populateLists(); + void selectSignal(QListWidgetItem *item); + void selectSlot(QListWidgetItem *item); + void populateSignalList(); + void populateSlotList(const QString &signal = QString()); + void editSignals(); + void editSlots(); + +private: + enum WidgetMode { NormalWidget, MainContainer, PromotedWidget }; + + static WidgetMode widgetMode(QWidget *w, QDesignerFormWindowInterface *formWindow); + QPushButton *okButton(); + void setOkButtonEnabled(bool); + void editSignalsSlots(QWidget *w, WidgetMode mode, int signalSlotDialogMode); + + QWidget *m_source; + QWidget *m_destination; + const WidgetMode m_sourceMode; + const WidgetMode m_destinationMode; + QDesignerFormWindowInterface *m_formWindow; + Ui::ConnectDialog m_ui; +}; + +} + +QT_END_NAMESPACE + +#endif // CONNECTDIALOG_H diff --git a/src/designer/src/components/signalsloteditor/signalslot_utils.cpp b/src/designer/src/components/signalsloteditor/signalslot_utils.cpp new file mode 100644 index 000000000..ac1fe1cbf --- /dev/null +++ b/src/designer/src/components/signalsloteditor/signalslot_utils.cpp @@ -0,0 +1,334 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "signalslot_utils_p.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +typedef QPair ClassNameSignaturePair; + +// Find all member functions that match a predicate on the signature string +// using the member sheet and the fake methods stored in the widget +// database and the meta data base. +// Assign a pair of to OutputIterator. + +template +static void memberList(QDesignerFormEditorInterface *core, + QObject *object, + qdesigner_internal::MemberType member_type, + bool showAll, + SignaturePredicate predicate, + OutputIterator it) +{ + if (!object) + return; + // 1) member sheet + const QDesignerMemberSheetExtension *members = qt_extension(core->extensionManager(), object); + Q_ASSERT(members != 0); + const int count = members->count(); + for (int i = 0; i < count; ++i) { + if (!members->isVisible(i)) + continue; + + if (member_type == qdesigner_internal::SignalMember && !members->isSignal(i)) + continue; + + if (member_type == qdesigner_internal::SlotMember && !members->isSlot(i)) + continue; + + if (!showAll && members->inheritedFromWidget(i)) + continue; + + const QString signature = members->signature(i); + if (predicate(signature)) { + *it = ClassNameSignaturePair(members->declaredInClass(i), signature); + ++it; + } + } + // 2) fake slots from widget DB + const qdesigner_internal::WidgetDataBase *wdb = qobject_cast(core->widgetDataBase()); + if (!wdb) + return; + const int idx = wdb->indexOfObject(object); + Q_ASSERT(idx != -1); + // get the promoted class name + const qdesigner_internal::WidgetDataBaseItem *wdbItem = static_cast(wdb->item(idx)); + const QString className = wdbItem->name(); + + const QStringList wdbFakeMethods = member_type == qdesigner_internal::SlotMember ? wdbItem->fakeSlots() : wdbItem->fakeSignals(); + if (!wdbFakeMethods.empty()) + foreach (const QString &fakeMethod, wdbFakeMethods) + if (predicate(fakeMethod)) { + *it = ClassNameSignaturePair(className, fakeMethod); + ++it; + } + // 3) fake slots from meta DB + qdesigner_internal::MetaDataBase *metaDataBase = qobject_cast(core->metaDataBase()); + if (!metaDataBase) + return; + + if (const qdesigner_internal::MetaDataBaseItem *mdbItem = metaDataBase->metaDataBaseItem(object)) { + const QStringList mdbFakeMethods = member_type == qdesigner_internal::SlotMember ? mdbItem->fakeSlots() : mdbItem->fakeSignals(); + if (!mdbFakeMethods.empty()) + foreach (const QString &fakeMethod, mdbFakeMethods) + if (predicate(fakeMethod)) { + *it = ClassNameSignaturePair(className, fakeMethod); + ++it; + } + } +} + +namespace { + // Predicate that matches the exact signature string + class EqualsPredicate { + public: + EqualsPredicate(const QString &pattern) : m_pattern(pattern) {} + bool operator()(const QString &s) const { return s == m_pattern; } + private: + const QString m_pattern; + }; + // Predicate for a QString member signature that matches signals up with slots and vice versa + class SignalMatchesSlotPredicate { + public: + SignalMatchesSlotPredicate(QDesignerFormEditorInterface *core, const QString &peer, qdesigner_internal::MemberType memberType); + bool operator()(const QString &s) const; + + private: + bool signalMatchesSlot(const QString &signal, const QString &slot) const; + + const QString m_peer; + qdesigner_internal::MemberType m_memberType; + const QDesignerLanguageExtension *m_lang; + }; + + SignalMatchesSlotPredicate::SignalMatchesSlotPredicate(QDesignerFormEditorInterface *core, const QString &peer, qdesigner_internal::MemberType memberType) : + m_peer(peer), + m_memberType(memberType), + m_lang(qt_extension(core->extensionManager(), core)) + { + } + + bool SignalMatchesSlotPredicate::operator()(const QString &s) const + { + return m_memberType == qdesigner_internal::SlotMember ? signalMatchesSlot(m_peer, s) : signalMatchesSlot(s, m_peer); + } + + bool SignalMatchesSlotPredicate::signalMatchesSlot(const QString &signal, const QString &slot) const + { + if (m_lang) + return m_lang->signalMatchesSlot(signal, slot); + + return QDesignerMemberSheet::signalMatchesSlot(signal, slot); + } + + // Output iterator for a pair of pair of + // that builds the reverse class list for reverseClassesMemberFunctions() + // (for the combos of the ToolWindow) + class ReverseClassesMemberIterator { + public: + ReverseClassesMemberIterator(qdesigner_internal::ClassesMemberFunctions *result); + + ReverseClassesMemberIterator &operator*() { return *this; } + ReverseClassesMemberIterator &operator++(int) { return *this; } + ReverseClassesMemberIterator &operator++() { return *this; } + void operator=(const ClassNameSignaturePair &classNameSignature); + + private: + qdesigner_internal::ClassesMemberFunctions *m_result; + QString m_lastClassName; + QStringList *m_memberList; + }; + + ReverseClassesMemberIterator::ReverseClassesMemberIterator(qdesigner_internal::ClassesMemberFunctions *result) : + m_result(result), + m_memberList(0) + { + } + + void ReverseClassesMemberIterator::operator=(const ClassNameSignaturePair &classNameSignature) + { + // prepend a new entry if class changes + if (!m_memberList || classNameSignature.first != m_lastClassName) { + m_lastClassName = classNameSignature.first; + m_result->push_front(qdesigner_internal::ClassMemberFunctions(m_lastClassName)); + m_memberList = &(m_result->front().m_memberList); + } + m_memberList->push_back(classNameSignature.second); + } + + // Output iterator for a pair of pair of + // that adds the signatures to a string list + class SignatureIterator { + public: + SignatureIterator(QMap *result) : m_result(result) {} + + SignatureIterator &operator*() { return *this; } + SignatureIterator &operator++(int) { return *this; } + SignatureIterator &operator++() { return *this; } + void operator=(const ClassNameSignaturePair &classNameSignature) { + m_result->insert(classNameSignature.second, classNameSignature.first); + } + + private: + QMap *m_result; + }; +} + +static inline bool truePredicate(const QString &) { return true; } + +namespace qdesigner_internal { + + ClassMemberFunctions::ClassMemberFunctions(const QString &class_name) : + m_className(class_name) + { + } + + bool signalMatchesSlot(QDesignerFormEditorInterface *core, const QString &signal, const QString &slot) + { + const SignalMatchesSlotPredicate predicate(core, signal, qdesigner_internal::SlotMember); + return predicate(slot); + } + + // return classes and members in reverse class order to + // populate of the combo of the ToolWindow + ClassesMemberFunctions reverseClassesMemberFunctions(const QString &obj_name, MemberType member_type, + const QString &peer, QDesignerFormWindowInterface *form) + { + QObject *object = 0; + if (obj_name == form->mainContainer()->objectName()) { + object = form->mainContainer(); + } else { + object = form->mainContainer()->findChild(obj_name); + } + if (!object) + return ClassesMemberFunctions(); + QDesignerFormEditorInterface *core = form->core(); + + ClassesMemberFunctions rc; + memberList(form->core(), object, member_type, true, SignalMatchesSlotPredicate(core, peer, member_type), + ReverseClassesMemberIterator(&rc)); + return rc; + } + + QMap getSignals(QDesignerFormEditorInterface *core, QObject *object, bool showAll) + { + QMap rc; + memberList(core, object, SignalMember, showAll, truePredicate, SignatureIterator(&rc)); + return rc; + } + + bool isQt3Signal(QDesignerFormEditorInterface *core, + QObject *object, const QString &signalSignature) + { + if (const QDesignerMemberSheetExtension *members + = qt_extension(core->extensionManager(), object)) { + const int count = members->count(); + for (int i = 0; i < count; ++i) + if (members->isSignal(i) && members->signature(i) == signalSignature) { + const QDesignerMemberSheet *memberSheet + = qobject_cast(core->extensionManager()->extension(object, + Q_TYPEID(QDesignerMemberSheetExtension))); + return (memberSheet && memberSheet->isQt3Signal(i)); + } + } + + return false; + } + + bool isQt3Slot(QDesignerFormEditorInterface *core, + QObject *object, const QString &slotSignature) + { + if (const QDesignerMemberSheetExtension *members + = qt_extension(core->extensionManager(), object)) { + Q_ASSERT(members != 0); + const int count = members->count(); + for (int i = 0; i < count; ++i) + if (members->isSlot(i) && members->signature(i) == slotSignature) { + const QDesignerMemberSheet *memberSheet + = qobject_cast(core->extensionManager()->extension(object, + Q_TYPEID(QDesignerMemberSheetExtension))); + return (memberSheet && memberSheet->isQt3Slot(i)); + } + } + return false; + } + + QMap getMatchingSlots(QDesignerFormEditorInterface *core, QObject *object, const QString &signalSignature, bool showAll) + { + QMap rc; + memberList(core, object, SlotMember, showAll, SignalMatchesSlotPredicate(core, signalSignature, qdesigner_internal::SlotMember), SignatureIterator(&rc)); + return rc; + } + + bool memberFunctionListContains(QDesignerFormEditorInterface *core, QObject *object, MemberType type, const QString &signature) + { + QMap rc; + memberList(core, object, type, true, EqualsPredicate(signature), SignatureIterator(&rc)); + return !rc.empty(); + } + + // ### deprecated + QString realObjectName(QDesignerFormEditorInterface *core, QObject *object) + { + if (!object) + return QString(); + + const QDesignerMetaDataBaseInterface *mdb = core->metaDataBase(); + if (const QDesignerMetaDataBaseItemInterface *item = mdb->item(object)) + return item->name(); + + return object->objectName(); + } +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/components/signalsloteditor/signalslot_utils_p.h b/src/designer/src/components/signalsloteditor/signalslot_utils_p.h new file mode 100644 index 000000000..0bc434c98 --- /dev/null +++ b/src/designer/src/components/signalsloteditor/signalslot_utils_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIGNALSLOTUTILS_P_H +#define SIGNALSLOTUTILS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +enum MemberType { SignalMember, SlotMember }; + +// member to class name +QMap getSignals(QDesignerFormEditorInterface *core, QObject *object, bool showAll); +QMap getMatchingSlots(QDesignerFormEditorInterface *core, QObject *object, + const QString &signalSignature, bool showAll); + +bool memberFunctionListContains(QDesignerFormEditorInterface *core, QObject *object, MemberType type, const QString &signature); + +// Members functions listed by class they were inherited from +struct ClassMemberFunctions +{ + ClassMemberFunctions() {} + ClassMemberFunctions(const QString &_class_name); + + QString m_className; + QStringList m_memberList; +}; + +typedef QList ClassesMemberFunctions; + +// Return classes and members in reverse class order to +// populate of the combo of the ToolWindow. + +ClassesMemberFunctions reverseClassesMemberFunctions(const QString &obj_name, MemberType member_type, + const QString &peer, QDesignerFormWindowInterface *form); + +bool signalMatchesSlot(QDesignerFormEditorInterface *core, const QString &signal, const QString &slot); + +QString realObjectName(QDesignerFormEditorInterface *core, QObject *object); + +bool isQt3Signal(QDesignerFormEditorInterface *core, QObject *object, const QString &signalSignature); +bool isQt3Slot(QDesignerFormEditorInterface *core, QObject *object, const QString &signalSignature); + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // SIGNALSLOTUTILS_P_H diff --git a/src/designer/src/components/signalsloteditor/signalsloteditor.cpp b/src/designer/src/components/signalsloteditor/signalsloteditor.cpp new file mode 100644 index 000000000..673864032 --- /dev/null +++ b/src/designer/src/components/signalsloteditor/signalsloteditor.cpp @@ -0,0 +1,528 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "signalsloteditor.h" +#include "signalsloteditor_p.h" +#include "connectdialog_p.h" +#include "signalslot_utils_p.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +/******************************************************************************* +** SignalSlotConnection +*/ + +SignalSlotConnection::SignalSlotConnection(ConnectionEdit *edit, QWidget *source, QWidget *target) + : Connection(edit, source, target) +{ +} + +DomConnection *SignalSlotConnection::toUi() const +{ + DomConnection *result = new DomConnection; + + result->setElementSender(sender()); + result->setElementSignal(signal()); + result->setElementReceiver(receiver()); + result->setElementSlot(slot()); + + DomConnectionHints *hints = new DomConnectionHints; + QList list; + + QPoint sp = endPointPos(EndPoint::Source); + QPoint tp = endPointPos(EndPoint::Target); + + DomConnectionHint *hint = new DomConnectionHint; + hint->setAttributeType(QLatin1String("sourcelabel")); + hint->setElementX(sp.x()); + hint->setElementY(sp.y()); + list.append(hint); + + hint = new DomConnectionHint; + hint->setAttributeType(QLatin1String("destinationlabel")); + hint->setElementX(tp.x()); + hint->setElementY(tp.y()); + list.append(hint); + + hints->setElementHint(list); + result->setElementHints(hints); + + return result; +} + +void SignalSlotConnection::setSignal(const QString &signal) +{ + m_signal = signal; + setLabel(EndPoint::Source, m_signal); +} + +void SignalSlotConnection::setSlot(const QString &slot) +{ + m_slot = slot; + setLabel(EndPoint::Target, m_slot); +} + +QString SignalSlotConnection::sender() const +{ + QObject *source = object(EndPoint::Source); + if (!source) + return QString(); + + SignalSlotEditor *edit = qobject_cast(this->edit()); + Q_ASSERT(edit != 0); + + return realObjectName(edit->formWindow()->core(), source); +} + +QString SignalSlotConnection::receiver() const +{ + QObject *sink = object(EndPoint::Target); + if (!sink) + return QString(); + + SignalSlotEditor *edit = qobject_cast(this->edit()); + Q_ASSERT(edit != 0); + return realObjectName(edit->formWindow()->core(), sink); +} + +void SignalSlotConnection::updateVisibility() +{ + Connection::updateVisibility(); + if (isVisible() && (signal().isEmpty() || slot().isEmpty())) + setVisible(false); +} + +QString SignalSlotConnection::toString() const +{ + return QCoreApplication::translate("SignalSlotConnection", "SENDER(%1), SIGNAL(%2), RECEIVER(%3), SLOT(%4)") + .arg(sender()).arg(signal()).arg(receiver()).arg(slot()); +} + +SignalSlotConnection::State SignalSlotConnection::isValid(const QWidget *background) const +{ + const QObject *source = object(EndPoint::Source); + if (!source) + return ObjectDeleted; + + const QObject *target = object(EndPoint::Target); + if (!target) + return ObjectDeleted; + + if (m_slot.isEmpty() || m_signal.isEmpty()) + return InvalidMethod; + + if (const QWidget *sourceWidget = qobject_cast(source)) + if (!background->isAncestorOf(sourceWidget)) + return NotAncestor; + + if (const QWidget *targetWidget = qobject_cast(target)) + if (!background->isAncestorOf(targetWidget)) + return NotAncestor; + + return Valid; +} + +/******************************************************************************* +** Commands +*/ + +class SetMemberCommand : public QUndoCommand, public CETypes +{ +public: + SetMemberCommand(SignalSlotConnection *con, EndPoint::Type type, + const QString &member, SignalSlotEditor *editor); + virtual void redo(); + virtual void undo(); +private: + const QString m_old_member; + const QString m_new_member; + const EndPoint::Type m_type; + SignalSlotConnection *m_con; + SignalSlotEditor *m_editor; +}; + +SetMemberCommand::SetMemberCommand(SignalSlotConnection *con, EndPoint::Type type, + const QString &member, SignalSlotEditor *editor) : + m_old_member(type == EndPoint::Source ? con->signal() : con->slot()), + m_new_member(member), + m_type(type), + m_con(con), + m_editor(editor) +{ + if (type == EndPoint::Source) + setText(QApplication::translate("Command", "Change signal")); + else + setText(QApplication::translate("Command", "Change slot")); +} + +void SetMemberCommand::redo() +{ + m_con->update(); + if (m_type == EndPoint::Source) + m_con->setSignal(m_new_member); + else + m_con->setSlot(m_new_member); + m_con->update(); + emit m_editor->connectionChanged(m_con); +} + +void SetMemberCommand::undo() +{ + m_con->update(); + if (m_type == EndPoint::Source) + m_con->setSignal(m_old_member); + else + m_con->setSlot(m_old_member); + m_con->update(); + emit m_editor->connectionChanged(m_con); +} + +// Command to modify a connection +class ModifyConnectionCommand : public QDesignerFormWindowCommand +{ +public: + explicit ModifyConnectionCommand(QDesignerFormWindowInterface *form, + SignalSlotConnection *conn, + const QString &newSignal, + const QString &newSlot); + virtual void redo(); + virtual void undo(); + +private: + SignalSlotConnection *m_conn; + const QString m_oldSignal; + const QString m_oldSlot; + const QString m_newSignal; + const QString m_newSlot; +}; + +ModifyConnectionCommand::ModifyConnectionCommand(QDesignerFormWindowInterface *form, + SignalSlotConnection *conn, + const QString &newSignal, + const QString &newSlot) : + QDesignerFormWindowCommand(QCoreApplication::translate("Command", "Change signal-slot connection"), form), + m_conn(conn), + m_oldSignal(conn->signal()), + m_oldSlot(conn->slot()), + m_newSignal(newSignal), + m_newSlot(newSlot) +{ +} + +void ModifyConnectionCommand::redo() +{ + m_conn->setSignal(m_newSignal); + m_conn->setSlot(m_newSlot); +} + +void ModifyConnectionCommand::undo() +{ + m_conn->setSignal(m_oldSignal); + m_conn->setSlot(m_oldSlot); +} + +/******************************************************************************* +** SignalSlotEditor +*/ + +SignalSlotEditor::SignalSlotEditor(QDesignerFormWindowInterface *form_window, QWidget *parent) : + ConnectionEdit(parent, form_window), + m_form_window(form_window), + m_showAllSignalsSlots(false) +{ +} + +void SignalSlotEditor::modifyConnection(Connection *con) +{ + SignalSlotConnection *sigslot_con = static_cast(con); + ConnectDialog dialog(m_form_window, + sigslot_con->widget(EndPoint::Source), + sigslot_con->widget(EndPoint::Target), + m_form_window->core()->topLevel()); + + dialog.setSignalSlot(sigslot_con->signal(), sigslot_con->slot()); + dialog.setShowAllSignalsSlots(m_showAllSignalsSlots); + + if (dialog.exec() == QDialog::Accepted) { + const QString newSignal = dialog.signal(); + const QString newSlot = dialog.slot(); + if (sigslot_con->signal() != newSignal || sigslot_con->slot() != newSlot) { + ModifyConnectionCommand *cmd = new ModifyConnectionCommand(m_form_window, sigslot_con, newSignal, newSlot); + m_form_window->commandHistory()->push(cmd); + } + } + + m_showAllSignalsSlots = dialog.showAllSignalsSlots(); +} + +Connection *SignalSlotEditor::createConnection(QWidget *source, QWidget *destination) +{ + SignalSlotConnection *con = 0; + + Q_ASSERT(source != 0); + Q_ASSERT(destination != 0); + + ConnectDialog dialog(m_form_window, source, destination, m_form_window->core()->topLevel()); + dialog.setShowAllSignalsSlots(m_showAllSignalsSlots); + + if (dialog.exec() == QDialog::Accepted) { + con = new SignalSlotConnection(this, source, destination); + con->setSignal(dialog.signal()); + con->setSlot(dialog.slot()); + } + + m_showAllSignalsSlots = dialog.showAllSignalsSlots(); + + return con; +} + +DomConnections *SignalSlotEditor::toUi() const +{ + DomConnections *result = new DomConnections; + QList list; + + const int count = connectionCount(); + for (int i = 0; i < count; ++i) { + const SignalSlotConnection *con = static_cast(connection(i)); + Q_ASSERT(con != 0); + + // If a widget's parent has been removed or moved to a different form, + // and the parent was not a managed widget + // (a page in a tab widget), we never get a widgetRemoved(). So we filter out + // these child widgets here (check QPointer and verify ancestor). + // Also, the user might demote a promoted widget or remove a fake + // slot in the editor, which causes the connection to become invalid + // once he doubleclicks on the method combo. + switch (con->isValid(background())) { + case SignalSlotConnection::Valid: + list.append(con->toUi()); + break; + case SignalSlotConnection::ObjectDeleted: + case SignalSlotConnection::InvalidMethod: + case SignalSlotConnection::NotAncestor: + break; + } + } + result->setElementConnection(list); + return result; +} + +QObject *SignalSlotEditor::objectByName(QWidget *topLevel, const QString &name) const +{ + if (name.isEmpty()) + return 0; + + Q_ASSERT(topLevel); + QObject *object = 0; + if (topLevel->objectName() == name) + object = topLevel; + else + object = topLevel->findChild(name); + const QDesignerMetaDataBaseInterface *mdb = formWindow()->core()->metaDataBase(); + if (mdb->item(object)) + return object; + return 0; +} + +void SignalSlotEditor::fromUi(const DomConnections *connections, QWidget *parent) +{ + if (connections == 0) + return; + + setBackground(parent); + clear(); + const QList list = connections->elementConnection(); + foreach (const DomConnection *dom_con, list) { + QObject *source = objectByName(parent, dom_con->elementSender()); + if (source == 0) { + qDebug("SignalSlotEditor::fromUi(): no source widget called \"%s\"", + dom_con->elementSender().toUtf8().constData()); + continue; + } + QObject *destination = objectByName(parent, dom_con->elementReceiver()); + if (destination == 0) { + qDebug("SignalSlotEditor::fromUi(): no destination widget called \"%s\"", + dom_con->elementReceiver().toUtf8().constData()); + continue; + } + + QPoint sp = QPoint(20, 20), tp = QPoint(20, 20); + const DomConnectionHints *dom_hints = dom_con->elementHints(); + if (dom_hints != 0) { + QList list = dom_hints->elementHint(); + foreach (DomConnectionHint *hint, list) { + QString attr_type = hint->attributeType(); + QPoint p = QPoint(hint->elementX(), hint->elementY()); + if (attr_type == QLatin1String("sourcelabel")) + sp = p; + else if (attr_type == QLatin1String("destinationlabel")) + tp = p; + } + } + + SignalSlotConnection *con = new SignalSlotConnection(this); + + con->setEndPoint(EndPoint::Source, source, sp); + con->setEndPoint(EndPoint::Target, destination, tp); + con->setSignal(dom_con->elementSignal()); + con->setSlot(dom_con->elementSlot()); + addConnection(con); + } +} + +static bool skipWidget(const QWidget *w) +{ + const QString name = QLatin1String(w->metaObject()->className()); + if (name == QLatin1String("QDesignerWidget")) + return true; + if (name == QLatin1String("QLayoutWidget")) + return true; + if (name == QLatin1String("qdesigner_internal::FormWindow")) + return true; + if (name == QLatin1String("Spacer")) + return true; + return false; +} + +QWidget *SignalSlotEditor::widgetAt(const QPoint &pos) const +{ + QWidget *widget = ConnectionEdit::widgetAt(pos); + + if (widget == m_form_window->mainContainer()) + return widget; + + for (; widget != 0; widget = widget->parentWidget()) { + QDesignerMetaDataBaseItemInterface *item = m_form_window->core()->metaDataBase()->item(widget); + if (item == 0) + continue; + if (skipWidget(widget)) + continue; + break; + } + + return widget; +} + +void SignalSlotEditor::setSignal(SignalSlotConnection *con, const QString &member) +{ + if (member == con->signal()) + return; + + m_form_window->beginCommand(QApplication::translate("Command", "Change signal")); + undoStack()->push(new SetMemberCommand(con, EndPoint::Source, member, this)); + if (!signalMatchesSlot(m_form_window->core(), member, con->slot())) + undoStack()->push(new SetMemberCommand(con, EndPoint::Target, QString(), this)); + m_form_window->endCommand(); +} + +void SignalSlotEditor::setSlot(SignalSlotConnection *con, const QString &member) +{ + if (member == con->slot()) + return; + + m_form_window->beginCommand(QApplication::translate("Command", "Change slot")); + undoStack()->push(new SetMemberCommand(con, EndPoint::Target, member, this)); + if (!signalMatchesSlot(m_form_window->core(), con->signal(), member)) + undoStack()->push(new SetMemberCommand(con, EndPoint::Source, QString(), this)); + m_form_window->endCommand(); +} + +void SignalSlotEditor::setSource(Connection *_con, const QString &obj_name) +{ + SignalSlotConnection *con = static_cast(_con); + + if (con->sender() == obj_name) + return; + + m_form_window->beginCommand(QApplication::translate("Command", "Change sender")); + ConnectionEdit::setSource(con, obj_name); + + QObject *sourceObject = con->object(EndPoint::Source); + + if (!memberFunctionListContains(m_form_window->core(), sourceObject, SignalMember, con->signal())) + undoStack()->push(new SetMemberCommand(con, EndPoint::Source, QString(), this)); + + m_form_window->endCommand(); +} + +void SignalSlotEditor::setTarget(Connection *_con, const QString &obj_name) +{ + SignalSlotConnection *con = static_cast(_con); + + if (con->receiver() == obj_name) + return; + + m_form_window->beginCommand(QApplication::translate("Command", "Change receiver")); + ConnectionEdit::setTarget(con, obj_name); + + QObject *targetObject = con->object(EndPoint::Target); + if (!memberFunctionListContains(m_form_window->core(), targetObject, SlotMember, con->slot())) + undoStack()->push(new SetMemberCommand(con, EndPoint::Target, QString(), this)); + + m_form_window->endCommand(); +} + +void SignalSlotEditor::addEmptyConnection() +{ + SignalSlotConnection *con = new SignalSlotConnection(this); + undoStack()->push(new AddConnectionCommand(this, con)); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/components/signalsloteditor/signalsloteditor.h b/src/designer/src/components/signalsloteditor/signalsloteditor.h new file mode 100644 index 000000000..fca358760 --- /dev/null +++ b/src/designer/src/components/signalsloteditor/signalsloteditor.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIGNALSLOTEDITOR_H +#define SIGNALSLOTEDITOR_H + +#include "signalsloteditor_global.h" + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class DomConnections; + +namespace qdesigner_internal { + +class SignalSlotConnection; + +class QT_SIGNALSLOTEDITOR_EXPORT SignalSlotEditor : public ConnectionEdit +{ + Q_OBJECT + +public: + SignalSlotEditor(QDesignerFormWindowInterface *form_window, QWidget *parent); + + virtual void setSignal(SignalSlotConnection *con, const QString &member); + virtual void setSlot(SignalSlotConnection *con, const QString &member); + virtual void setSource(Connection *con, const QString &obj_name); + virtual void setTarget(Connection *con, const QString &obj_name); + + DomConnections *toUi() const; + void fromUi(const DomConnections *connections, QWidget *parent); + + QDesignerFormWindowInterface *formWindow() const { return m_form_window; } + + QObject *objectByName(QWidget *topLevel, const QString &name) const; + + void addEmptyConnection(); + +protected: + virtual QWidget *widgetAt(const QPoint &pos) const; + +private: + virtual Connection *createConnection(QWidget *source, QWidget *destination); + virtual void modifyConnection(Connection *con); + + QDesignerFormWindowInterface *m_form_window; + bool m_showAllSignalsSlots; + + friend class SetMemberCommand; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // SIGNALSLOTEDITOR_H diff --git a/src/designer/src/components/signalsloteditor/signalsloteditor.pri b/src/designer/src/components/signalsloteditor/signalsloteditor.pri new file mode 100644 index 000000000..e903ce114 --- /dev/null +++ b/src/designer/src/components/signalsloteditor/signalsloteditor.pri @@ -0,0 +1,21 @@ + +INCLUDEPATH += $$PWD + +HEADERS += $$PWD/signalslot_utils_p.h \ + $$PWD/connectdialog_p.h \ + $$PWD/signalsloteditor.h \ + $$PWD/signalsloteditor_tool.h \ + $$PWD/signalsloteditor_plugin.h \ + $$PWD/signalsloteditor_global.h \ + $$PWD/signalsloteditor_p.h \ + $$PWD/signalsloteditorwindow.h + +SOURCES += $$PWD/signalslot_utils.cpp \ + $$PWD/connectdialog.cpp \ + $$PWD/signalsloteditor.cpp \ + $$PWD/signalsloteditor_tool.cpp \ + $$PWD/signalsloteditor_plugin.cpp \ + $$PWD/signalsloteditor_instance.cpp \ + $$PWD/signalsloteditorwindow.cpp + +FORMS += $$PWD/connectdialog.ui diff --git a/src/designer/src/components/signalsloteditor/signalsloteditor_global.h b/src/designer/src/components/signalsloteditor/signalsloteditor_global.h new file mode 100644 index 000000000..122a32a92 --- /dev/null +++ b/src/designer/src/components/signalsloteditor/signalsloteditor_global.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIGNALSLOTEDITOR_GLOBAL_H +#define SIGNALSLOTEDITOR_GLOBAL_H + +#include + +#ifdef Q_OS_WIN +#ifdef QT_SIGNALSLOTEDITOR_LIBRARY +# define QT_SIGNALSLOTEDITOR_EXPORT +#else +# define QT_SIGNALSLOTEDITOR_EXPORT +#endif +#else +#define QT_SIGNALSLOTEDITOR_EXPORT +#endif + +#endif // SIGNALSLOTEDITOR_GLOBAL_H diff --git a/src/designer/src/components/signalsloteditor/signalsloteditor_instance.cpp b/src/designer/src/components/signalsloteditor/signalsloteditor_instance.cpp new file mode 100644 index 000000000..6c2aa3c11 --- /dev/null +++ b/src/designer/src/components/signalsloteditor/signalsloteditor_instance.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "signalsloteditor_plugin.h" + +QT_USE_NAMESPACE + +using namespace qdesigner_internal; + +Q_EXPORT_PLUGIN(SignalSlotEditorPlugin) diff --git a/src/designer/src/components/signalsloteditor/signalsloteditor_p.h b/src/designer/src/components/signalsloteditor/signalsloteditor_p.h new file mode 100644 index 000000000..bd01c2ef1 --- /dev/null +++ b/src/designer/src/components/signalsloteditor/signalsloteditor_p.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIGNALSLOTEDITOR_P_H +#define SIGNALSLOTEDITOR_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QDesignerFormEditorInterface; +class DomConnection; + +namespace qdesigner_internal { + +class SignalSlotEditor; + +class SignalSlotConnection : public Connection +{ +public: + explicit SignalSlotConnection(ConnectionEdit *edit, QWidget *source = 0, QWidget *target = 0); + + void setSignal(const QString &signal); + void setSlot(const QString &slot); + + QString sender() const; + QString receiver() const; + inline QString signal() const { return m_signal; } + inline QString slot() const { return m_slot; } + + DomConnection *toUi() const; + + virtual void updateVisibility(); + + enum State { Valid, ObjectDeleted, InvalidMethod, NotAncestor }; + State isValid(const QWidget *background) const; + + // format for messages, etc. + QString toString() const; + +private: + QString m_signal, m_slot; +}; + +class ConnectionModel : public QAbstractItemModel +{ + Q_OBJECT +public: + explicit ConnectionModel(QObject *parent = 0); + void setEditor(SignalSlotEditor *editor = 0); + + virtual QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const; + virtual QModelIndex parent(const QModelIndex &child) const; + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + virtual bool setData(const QModelIndex &index, const QVariant &data, int role = Qt::DisplayRole); + virtual Qt::ItemFlags flags(const QModelIndex &index) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, + int role = Qt::DisplayRole) const; + + QModelIndex connectionToIndex(Connection *con) const; + Connection *indexToConnection(const QModelIndex &index) const; + void updateAll(); + +private slots: + void connectionAdded(Connection *con); + void connectionRemoved(int idx); + void aboutToRemoveConnection(Connection *con); + void aboutToAddConnection(int idx); + void connectionChanged(Connection *con); + +private: + QPointer m_editor; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // SIGNALSLOTEDITOR_P_H diff --git a/src/designer/src/components/signalsloteditor/signalsloteditor_plugin.cpp b/src/designer/src/components/signalsloteditor/signalsloteditor_plugin.cpp new file mode 100644 index 000000000..7e1f67f08 --- /dev/null +++ b/src/designer/src/components/signalsloteditor/signalsloteditor_plugin.cpp @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "signalsloteditor_plugin.h" +#include "signalsloteditor_tool.h" + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +SignalSlotEditorPlugin::SignalSlotEditorPlugin() + : m_initialized(false), m_action(0) +{ +} + +SignalSlotEditorPlugin::~SignalSlotEditorPlugin() +{ +} + +bool SignalSlotEditorPlugin::isInitialized() const +{ + return m_initialized; +} + +void SignalSlotEditorPlugin::initialize(QDesignerFormEditorInterface *core) +{ + Q_ASSERT(!isInitialized()); + + m_action = new QAction(tr("Edit Signals/Slots"), this); + m_action->setObjectName(QLatin1String("__qt_edit_signals_slots_action")); + m_action->setShortcut(tr("F4")); + QIcon icon = QIcon::fromTheme("designer-edit-signals", + QIcon(core->resourceLocation() + QLatin1String("/signalslottool.png"))); + m_action->setIcon(icon); + m_action->setEnabled(false); + + setParent(core); + m_core = core; + m_initialized = true; + + connect(core->formWindowManager(), SIGNAL(formWindowAdded(QDesignerFormWindowInterface*)), + this, SLOT(addFormWindow(QDesignerFormWindowInterface*))); + + connect(core->formWindowManager(), SIGNAL(formWindowRemoved(QDesignerFormWindowInterface*)), + this, SLOT(removeFormWindow(QDesignerFormWindowInterface*))); + + connect(core->formWindowManager(), SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)), + this, SLOT(activeFormWindowChanged(QDesignerFormWindowInterface*))); +} + +QDesignerFormEditorInterface *SignalSlotEditorPlugin::core() const +{ + return m_core; +} + +void SignalSlotEditorPlugin::addFormWindow(QDesignerFormWindowInterface *formWindow) +{ + Q_ASSERT(formWindow != 0); + Q_ASSERT(m_tools.contains(formWindow) == false); + + SignalSlotEditorTool *tool = new SignalSlotEditorTool(formWindow, this); + connect(m_action, SIGNAL(triggered()), tool->action(), SLOT(trigger())); + m_tools[formWindow] = tool; + formWindow->registerTool(tool); +} + +void SignalSlotEditorPlugin::removeFormWindow(QDesignerFormWindowInterface *formWindow) +{ + Q_ASSERT(formWindow != 0); + Q_ASSERT(m_tools.contains(formWindow) == true); + + SignalSlotEditorTool *tool = m_tools.value(formWindow); + m_tools.remove(formWindow); + disconnect(m_action, SIGNAL(triggered()), tool->action(), SLOT(trigger())); + // ### FIXME disable the tool + + delete tool; +} + +QAction *SignalSlotEditorPlugin::action() const +{ + return m_action; +} + +void SignalSlotEditorPlugin::activeFormWindowChanged(QDesignerFormWindowInterface *formWindow) +{ + m_action->setEnabled(formWindow != 0); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/signalsloteditor/signalsloteditor_plugin.h b/src/designer/src/components/signalsloteditor/signalsloteditor_plugin.h new file mode 100644 index 000000000..7ef5e2f5b --- /dev/null +++ b/src/designer/src/components/signalsloteditor/signalsloteditor_plugin.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIGNALSLOTEDITOR_PLUGIN_H +#define SIGNALSLOTEDITOR_PLUGIN_H + +#include "signalsloteditor_global.h" + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class SignalSlotEditorTool; + +class QT_SIGNALSLOTEDITOR_EXPORT SignalSlotEditorPlugin: public QObject, public QDesignerFormEditorPluginInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerFormEditorPluginInterface) +public: + SignalSlotEditorPlugin(); + virtual ~SignalSlotEditorPlugin(); + + virtual bool isInitialized() const; + virtual void initialize(QDesignerFormEditorInterface *core); + virtual QAction *action() const; + + virtual QDesignerFormEditorInterface *core() const; + +public slots: + void activeFormWindowChanged(QDesignerFormWindowInterface *formWindow); + +private slots: + void addFormWindow(QDesignerFormWindowInterface *formWindow); + void removeFormWindow(QDesignerFormWindowInterface *formWindow); + +private: + QPointer m_core; + QHash m_tools; + bool m_initialized; + QAction *m_action; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // SIGNALSLOTEDITOR_PLUGIN_H diff --git a/src/designer/src/components/signalsloteditor/signalsloteditor_tool.cpp b/src/designer/src/components/signalsloteditor/signalsloteditor_tool.cpp new file mode 100644 index 000000000..a56acc37d --- /dev/null +++ b/src/designer/src/components/signalsloteditor/signalsloteditor_tool.cpp @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "signalsloteditor_tool.h" +#include "signalsloteditor.h" +#include "ui4_p.h" + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +SignalSlotEditorTool::SignalSlotEditorTool(QDesignerFormWindowInterface *formWindow, QObject *parent) + : QDesignerFormWindowToolInterface(parent), + m_formWindow(formWindow), + m_action(new QAction(tr("Edit Signals/Slots"), this)) +{ +} + +SignalSlotEditorTool::~SignalSlotEditorTool() +{ +} + +QDesignerFormEditorInterface *SignalSlotEditorTool::core() const +{ + return m_formWindow->core(); +} + +QDesignerFormWindowInterface *SignalSlotEditorTool::formWindow() const +{ + return m_formWindow; +} + +bool SignalSlotEditorTool::handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event) +{ + Q_UNUSED(widget); + Q_UNUSED(managedWidget); + Q_UNUSED(event); + + return false; +} + +QWidget *SignalSlotEditorTool::editor() const +{ + if (!m_editor) { + Q_ASSERT(formWindow() != 0); + m_editor = new qdesigner_internal::SignalSlotEditor(formWindow(), 0); + connect(formWindow(), SIGNAL(mainContainerChanged(QWidget*)), m_editor, SLOT(setBackground(QWidget*))); + connect(formWindow(), SIGNAL(changed()), + m_editor, SLOT(updateBackground())); + } + + return m_editor; +} + +QAction *SignalSlotEditorTool::action() const +{ + return m_action; +} + +void SignalSlotEditorTool::activated() +{ + m_editor->enableUpdateBackground(true); +} + +void SignalSlotEditorTool::deactivated() +{ + m_editor->enableUpdateBackground(false); +} + +void SignalSlotEditorTool::saveToDom(DomUI *ui, QWidget*) +{ + ui->setElementConnections(m_editor->toUi()); +} + +void SignalSlotEditorTool::loadFromDom(DomUI *ui, QWidget *mainContainer) +{ + m_editor->fromUi(ui->elementConnections(), mainContainer); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/signalsloteditor/signalsloteditor_tool.h b/src/designer/src/components/signalsloteditor/signalsloteditor_tool.h new file mode 100644 index 000000000..89b861ed3 --- /dev/null +++ b/src/designer/src/components/signalsloteditor/signalsloteditor_tool.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIGNALSLOTEDITOR_TOOL_H +#define SIGNALSLOTEDITOR_TOOL_H + +#include "signalsloteditor_global.h" +#include "signalsloteditor.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; +class QAction; + +namespace qdesigner_internal { + +class SignalSlotEditor; + +class QT_SIGNALSLOTEDITOR_EXPORT SignalSlotEditorTool: public QDesignerFormWindowToolInterface +{ + Q_OBJECT +public: + explicit SignalSlotEditorTool(QDesignerFormWindowInterface *formWindow, QObject *parent = 0); + virtual ~SignalSlotEditorTool(); + + virtual QDesignerFormEditorInterface *core() const; + virtual QDesignerFormWindowInterface *formWindow() const; + + virtual QWidget *editor() const; + + QAction *action() const; + + virtual void activated(); + virtual void deactivated(); + + virtual bool handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event); + + virtual void saveToDom(DomUI *ui, QWidget *mainContainer); + virtual void loadFromDom(DomUI *ui, QWidget *mainContainer); + +private: + QDesignerFormWindowInterface *m_formWindow; + mutable QPointer m_editor; + QAction *m_action; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // SIGNALSLOTEDITOR_TOOL_H diff --git a/src/designer/src/components/signalsloteditor/signalsloteditorwindow.cpp b/src/designer/src/components/signalsloteditor/signalsloteditorwindow.cpp new file mode 100644 index 000000000..b06a66f2c --- /dev/null +++ b/src/designer/src/components/signalsloteditor/signalsloteditorwindow.cpp @@ -0,0 +1,864 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "signalsloteditorwindow.h" +#include "signalsloteditor_p.h" +#include "signalsloteditor.h" +#include "qdesigner_integration_p.h" +#include "signalslot_utils_p.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +// Add suitable form widgets to a list of objects for the signal slot +// editor. Prevent special widgets from showing up there. +static void addWidgetToObjectList(const QWidget *w, QStringList &r) +{ + const QMetaObject *mo = w->metaObject(); + if (mo != &QLayoutWidget::staticMetaObject && mo != &Spacer::staticMetaObject) { + const QString name = w->objectName().trimmed(); + if (!name.isEmpty()) + r.push_back(name); + } +} + +static QStringList objectNameList(QDesignerFormWindowInterface *form) +{ + typedef QList ActionList; + typedef QList ButtonGroupList; + + QStringList result; + + QWidget *mainContainer = form->mainContainer(); + if (!mainContainer) + return result; + + // Add main container container pages (QStatusBar, QWizardPages) etc. + // to the list. Pages of containers on the form are not added, however. + if (const QDesignerContainerExtension *c = qt_extension(form->core()->extensionManager(), mainContainer)) { + const int count = c->count(); + for (int i = 0 ; i < count; i++) + addWidgetToObjectList(c->widget(i), result); + } + + const QDesignerFormWindowCursorInterface *cursor = form->cursor(); + const int widgetCount = cursor->widgetCount(); + for (int i = 0; i < widgetCount; ++i) + addWidgetToObjectList(cursor->widget(i), result); + + const QDesignerMetaDataBaseInterface *mdb = form->core()->metaDataBase(); + + // Add managed actions and actions with managed menus + const ActionList actions = mainContainer->findChildren(); + if (!actions.empty()) { + const ActionList::const_iterator cend = actions.constEnd(); + for (ActionList::const_iterator it = actions.constBegin(); it != cend; ++it) { + QAction *a = *it; + if (!a->isSeparator()) { + if (QMenu *menu = a->menu()) { + if (mdb->item(menu)) + result.push_back(menu->objectName()); + } else { + if (mdb->item(a)) + result.push_back(a->objectName()); + } + } + } + } + + // Add managed buttons groups + const ButtonGroupList buttonGroups = mainContainer->findChildren(); + if (!buttonGroups.empty()) { + const ButtonGroupList::const_iterator cend = buttonGroups.constEnd(); + for (ButtonGroupList::const_iterator it = buttonGroups.constBegin(); it != cend; ++it) + if (mdb->item(*it)) + result.append((*it)->objectName()); + } + + result.sort(); + return result; +} + +namespace qdesigner_internal { + +// ------------ ConnectionModel + +ConnectionModel::ConnectionModel(QObject *parent) : + QAbstractItemModel(parent) +{ +} + +void ConnectionModel::setEditor(SignalSlotEditor *editor) +{ + if (m_editor == editor) + return; + + if (m_editor) { + disconnect(m_editor, SIGNAL(connectionAdded(Connection*)), + this, SLOT(connectionAdded(Connection*))); + disconnect(m_editor, SIGNAL(connectionRemoved(int)), + this, SLOT(connectionRemoved(int))); + disconnect(m_editor, SIGNAL(aboutToRemoveConnection(Connection*)), + this, SLOT(aboutToRemoveConnection(Connection*))); + disconnect(m_editor, SIGNAL(aboutToAddConnection(int)), + this, SLOT(aboutToAddConnection(int))); + disconnect(m_editor, SIGNAL(connectionChanged(Connection*)), + this, SLOT(connectionChanged(Connection*))); + } + m_editor = editor; + if (m_editor) { + connect(m_editor, SIGNAL(connectionAdded(Connection*)), + this, SLOT(connectionAdded(Connection*))); + connect(m_editor, SIGNAL(connectionRemoved(int)), + this, SLOT(connectionRemoved(int))); + connect(m_editor, SIGNAL(aboutToRemoveConnection(Connection*)), + this, SLOT(aboutToRemoveConnection(Connection*))); + connect(m_editor, SIGNAL(aboutToAddConnection(int)), + this, SLOT(aboutToAddConnection(int))); + connect(m_editor, SIGNAL(connectionChanged(Connection*)), + this, SLOT(connectionChanged(Connection*))); + } + reset(); +} + +QVariant ConnectionModel::headerData(int section, Qt::Orientation orientation, + int role) const +{ + if (orientation == Qt::Vertical || role != Qt::DisplayRole) + return QVariant(); + + static const QVariant senderTitle = tr("Sender"); + static const QVariant signalTitle = tr("Signal"); + static const QVariant receiverTitle = tr("Receiver"); + static const QVariant slotTitle = tr("Slot"); + + switch (section) { + case 0: + return senderTitle; + case 1: + return signalTitle; + case 2: + return receiverTitle; + case 3: + return slotTitle; + } + return QVariant(); +} + +QModelIndex ConnectionModel::index(int row, int column, + const QModelIndex &parent) const +{ + if (parent.isValid() || !m_editor) + return QModelIndex(); + if (row < 0 || row >= m_editor->connectionCount()) + return QModelIndex(); + return createIndex(row, column); +} + +Connection *ConnectionModel::indexToConnection(const QModelIndex &index) const +{ + if (!index.isValid() || !m_editor) + return 0; + if (index.row() < 0 || index.row() >= m_editor->connectionCount()) + return 0; + return m_editor->connection(index.row()); +} + +QModelIndex ConnectionModel::connectionToIndex(Connection *con) const +{ + Q_ASSERT(m_editor); + return createIndex(m_editor->indexOfConnection(con), 0); +} + +QModelIndex ConnectionModel::parent(const QModelIndex&) const +{ + return QModelIndex(); +} + +int ConnectionModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid() || !m_editor) + return 0; + return m_editor->connectionCount(); +} + +int ConnectionModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + return 4; +} + +QVariant ConnectionModel::data(const QModelIndex &index, int role) const +{ + if ((role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::FontRole && role != Qt::ForegroundRole) || !m_editor) + return QVariant(); + + if (index.row() < 0 || index.row() >= m_editor->connectionCount()) { + return QVariant(); + } + + const SignalSlotConnection *con = static_cast(m_editor->connection(index.row())); + Q_ASSERT(con != 0); + + if (role == Qt::FontRole || role == Qt::ForegroundRole) { + bool isQt3Member = false; + if (index.column() == 1) { + QDesignerFormEditorInterface *core = m_editor->formWindow()->core(); + isQt3Member = isQt3Signal(core, con->object(CETypes::EndPoint::Source), con->signal()); + } else if (index.column() == 3) { + QDesignerFormEditorInterface *core = m_editor->formWindow()->core(); + isQt3Member = isQt3Signal(core, con->object(CETypes::EndPoint::Target), con->slot()); + } + if (isQt3Member) { + if (role == Qt::ForegroundRole) + return Qt::red; + QFont font = QApplication::font(); + font.setItalic(true); + return font; + } + return QVariant(); + } + + static const QVariant senderDefault = tr(""); + static const QVariant signalDefault = tr(""); + static const QVariant receiverDefault = tr(""); + static const QVariant slotDefault = tr(""); + + switch (index.column()) { + case 0: { + const QString sender = con->sender(); + if (sender.isEmpty()) + return senderDefault; + return sender; + } + case 1: { + const QString signal = con->signal(); + if (signal.isEmpty()) + return signalDefault; + return signal; + } + case 2: { + const QString receiver = con->receiver(); + if (receiver.isEmpty()) + return receiverDefault; + return receiver; + } + case 3: { + const QString slot = con->slot(); + if (slot.isEmpty()) + return slotDefault; + return slot; + } + } + return QVariant(); +} + +bool ConnectionModel::setData(const QModelIndex &index, const QVariant &data, int) +{ + if (!index.isValid() || !m_editor) + return false; + if (data.type() != QVariant::String) + return false; + + SignalSlotConnection *con = static_cast(m_editor->connection(index.row())); + QDesignerFormWindowInterface *form = m_editor->formWindow(); + + QString s = data.toString(); + switch (index.column()) { + case 0: + if (!s.isEmpty() && !objectNameList(form).contains(s)) + s.clear(); + m_editor->setSource(con, s); + break; + case 1: + if (!memberFunctionListContains(form->core(), con->object(CETypes::EndPoint::Source), SignalMember, s)) + s.clear(); + m_editor->setSignal(con, s); + break; + case 2: + if (!s.isEmpty() && !objectNameList(form).contains(s)) + s.clear(); + m_editor->setTarget(con, s); + break; + case 3: + if (!memberFunctionListContains(form->core(), con->object(CETypes::EndPoint::Target), SlotMember, s)) + s.clear(); + m_editor->setSlot(con, s); + break; + } + + return true; +} + +void ConnectionModel::connectionAdded(Connection*) +{ + endInsertRows(); +} + +void ConnectionModel::connectionRemoved(int) +{ + endRemoveRows(); +} + +void ConnectionModel::aboutToRemoveConnection(Connection *con) +{ + Q_ASSERT(m_editor); + int idx = m_editor->indexOfConnection(con); + beginRemoveRows(QModelIndex(), idx, idx); +} + +void ConnectionModel::aboutToAddConnection(int idx) +{ + Q_ASSERT(m_editor); + beginInsertRows(QModelIndex(), idx, idx); +} + +Qt::ItemFlags ConnectionModel::flags(const QModelIndex&) const +{ + return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled; +} + +void ConnectionModel::connectionChanged(Connection *con) +{ + Q_ASSERT(m_editor); + const int idx = m_editor->indexOfConnection(con); + SignalSlotConnection *changedCon = static_cast(m_editor->connection(idx)); + SignalSlotConnection *c = 0; + for (int i=0; iconnectionCount(); ++i) { + if (i == idx) + continue; + c = static_cast(m_editor->connection(i)); + if (c->sender() == changedCon->sender() && c->signal() == changedCon->signal() + && c->receiver() == changedCon->receiver() && c->slot() == changedCon->slot()) { + const QString message = tr("The connection already exists!
%1").arg(changedCon->toString()); + m_editor->formWindow()->core()->dialogGui()->message(m_editor->parentWidget(), QDesignerDialogGuiInterface::SignalSlotEditorMessage, + QMessageBox::Warning, tr("Signal and Slot Editor"), message, QMessageBox::Ok); + break; + } + } + emit dataChanged(createIndex(idx, 0), createIndex(idx, 3)); +} + +void ConnectionModel::updateAll() +{ + emit dataChanged(index(0, 0), index(rowCount(), columnCount())); +} +} + +namespace { +// ---------------------- InlineEditorModel + +class InlineEditorModel : public QStandardItemModel +{ + Q_OBJECT +public: + enum { TitleItem = 1 }; + + InlineEditorModel(int rows, int cols, QObject *parent = 0); + + void addTitle(const QString &title); + void addTextList(const QMap &text_list); + void addText(const QString &text); + bool isTitle(int idx) const; + + int findText(const QString &text) const; + + virtual Qt::ItemFlags flags(const QModelIndex &index) const; +}; + +InlineEditorModel::InlineEditorModel(int rows, int cols, QObject *parent) + : QStandardItemModel(rows, cols, parent) +{ +} + +void InlineEditorModel::addTitle(const QString &title) +{ + const int cnt = rowCount(); + insertRows(cnt, 1); + QModelIndex cat_idx = index(cnt, 0); + setData(cat_idx, title + QLatin1Char(':'), Qt::DisplayRole); + setData(cat_idx, TitleItem, Qt::UserRole); + QFont font = QApplication::font(); + font.setBold(true); + setData(cat_idx, font, Qt::FontRole); +} + +bool InlineEditorModel::isTitle(int idx) const +{ + if (idx == -1) + return false; + + return data(index(idx, 0), Qt::UserRole).toInt() == TitleItem; +} + +void InlineEditorModel::addText(const QString &text) +{ + const int cnt = rowCount(); + insertRows(cnt, 1); + setData(index(cnt, 0), text, Qt::DisplayRole); +} + +void InlineEditorModel::addTextList(const QMap &text_list) +{ + int cnt = rowCount(); + insertRows(cnt, text_list.size()); + QFont font = QApplication::font(); + font.setItalic(true); + QVariant fontVariant = QVariant::fromValue(font); + QMap::ConstIterator it = text_list.constBegin(); + const QMap::ConstIterator itEnd = text_list.constEnd(); + while (it != itEnd) { + const QModelIndex text_idx = index(cnt++, 0); + setData(text_idx, it.key(), Qt::DisplayRole); + if (it.value()) { + setData(text_idx, fontVariant, Qt::FontRole); + setData(text_idx, Qt::red, Qt::ForegroundRole); + } + ++it; + } +} + +Qt::ItemFlags InlineEditorModel::flags(const QModelIndex &index) const +{ + if (isTitle(index.row())) + return Qt::ItemIsEnabled; + else + return Qt::ItemIsSelectable | Qt::ItemIsEnabled; +} + +int InlineEditorModel::findText(const QString &text) const +{ + const int cnt = rowCount(); + for (int i = 0; i < cnt; ++i) { + const QModelIndex idx = index(i, 0); + if (data(idx, Qt::UserRole).toInt() == TitleItem) + continue; + if (data(idx, Qt::DisplayRole).toString() == text) + return i; + } + return -1; +} + +// ------------ InlineEditor +class InlineEditor : public QComboBox +{ + Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText USER true) +public: + InlineEditor(QWidget *parent = 0); + + QString text() const; + void setText(const QString &text); + + void addTitle(const QString &title); + void addText(const QString &text); + void addTextList(const QMap &text_list); + +private slots: + void checkSelection(int idx); + +private: + InlineEditorModel *m_model; + int m_idx; +}; + +InlineEditor::InlineEditor(QWidget *parent) : + QComboBox(parent), + m_idx(-1) +{ + setModel(m_model = new InlineEditorModel(0, 4, this)); + setFrame(false); + m_idx = -1; + connect(this, SIGNAL(activated(int)), this, SLOT(checkSelection(int))); +} + +void InlineEditor::checkSelection(int idx) +{ + if (idx == m_idx) + return; + + if (m_model->isTitle(idx)) + setCurrentIndex(m_idx); + else + m_idx = idx; +} + +void InlineEditor::addTitle(const QString &title) +{ + m_model->addTitle(title); +} + +void InlineEditor::addTextList(const QMap &text_list) +{ + m_model->addTextList(text_list); +} + +void InlineEditor::addText(const QString &text) +{ + m_model->addText(text); +} + +QString InlineEditor::text() const +{ + return currentText(); +} + +void InlineEditor::setText(const QString &text) +{ + m_idx = m_model->findText(text); + if (m_idx == -1) + m_idx = 0; + setCurrentIndex(m_idx); +} + +// ------------------ ConnectionDelegate + +class ConnectionDelegate : public QItemDelegate +{ + Q_OBJECT +public: + ConnectionDelegate(QWidget *parent = 0); + + void setForm(QDesignerFormWindowInterface *form); + + virtual QWidget *createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const; + +private slots: + void emitCommitData(); + +private: + QDesignerFormWindowInterface *m_form; +}; + +ConnectionDelegate::ConnectionDelegate(QWidget *parent) + : QItemDelegate(parent) +{ + m_form = 0; + + static QItemEditorFactory *factory = 0; + if (factory == 0) { + factory = new QItemEditorFactory; + QItemEditorCreatorBase *creator + = new QItemEditorCreator("text"); + factory->registerEditor(QVariant::String, creator); + } + + setItemEditorFactory(factory); +} + +void ConnectionDelegate::setForm(QDesignerFormWindowInterface *form) +{ + m_form = form; +} + +QWidget *ConnectionDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + if (m_form == 0) + return 0; + + QWidget *w = QItemDelegate::createEditor(parent, option, index); + InlineEditor *inline_editor = qobject_cast(w); + Q_ASSERT(inline_editor != 0); + const QAbstractItemModel *model = index.model(); + + const QModelIndex obj_name_idx = model->index(index.row(), index.column() <= 1 ? 0 : 2); + const QString obj_name = model->data(obj_name_idx, Qt::DisplayRole).toString(); + + switch (index.column()) { + case 0: + case 2: { // object names + QStringList obj_name_list = objectNameList(m_form); + QMap markedNameList; + markedNameList.insert(tr(""), false); + inline_editor->addTextList(markedNameList); + markedNameList.clear(); + foreach (const QString &name, obj_name_list) + markedNameList.insert(name, false); + inline_editor->addTextList(markedNameList); + } + break; + case 1: + case 3: { // signals, slots + const qdesigner_internal::MemberType type = index.column() == 1 ? qdesigner_internal::SignalMember : qdesigner_internal::SlotMember; + const QModelIndex peer_index = model->index(index.row(), type == qdesigner_internal::SignalMember ? 3 : 1); + const QString peer = model->data(peer_index, Qt::DisplayRole).toString(); + + const qdesigner_internal::ClassesMemberFunctions class_list = qdesigner_internal::reverseClassesMemberFunctions(obj_name, type, peer, m_form); + + QObject *object = 0; + if (obj_name == m_form->mainContainer()->objectName()) { + object = m_form->mainContainer(); + } else { + object = m_form->mainContainer()->findChild(obj_name); + } + inline_editor->addText(type == qdesigner_internal::SignalMember ? tr("") : tr("")); + foreach (const qdesigner_internal::ClassMemberFunctions &class_info, class_list) { + if (class_info.m_className.isEmpty() || class_info.m_memberList.isEmpty()) + continue; + QStringList memberList = class_info.m_memberList; + QMap markedMemberList; + foreach (const QString &member, memberList) { + bool mark = false; + if (type == qdesigner_internal::SignalMember) + mark = qdesigner_internal::isQt3Signal(m_form->core(), object, member); + else + mark = qdesigner_internal::isQt3Slot(m_form->core(), object, member); + + if (!mark) + markedMemberList.insert(member, mark); + } + inline_editor->addTitle(class_info.m_className); + inline_editor->addTextList(markedMemberList); + } + } + break; + default: + break; + } + + connect(inline_editor, SIGNAL(activated(int)), this, SLOT(emitCommitData())); + + return inline_editor; +} + +void ConnectionDelegate::emitCommitData() +{ + InlineEditor *editor = qobject_cast(sender()); + emit commitData(editor); +} + +} + +namespace qdesigner_internal { + +/******************************************************************************* +** SignalSlotEditorWindow +*/ + +SignalSlotEditorWindow::SignalSlotEditorWindow(QDesignerFormEditorInterface *core, + QWidget *parent) : + QWidget(parent), + m_view(new QTreeView), + m_editor(0), + m_add_button(new QToolButton), + m_remove_button(new QToolButton), + m_core(core), + m_model(new ConnectionModel(this)), + m_proxy_model(new QSortFilterProxyModel(this)), + m_handling_selection_change(false) +{ + m_proxy_model->setSourceModel(m_model); + m_view->setModel(m_proxy_model); + m_view->setSortingEnabled(true); + m_view->setItemDelegate(new ConnectionDelegate(this)); + m_view->setEditTriggers(QAbstractItemView::DoubleClicked + | QAbstractItemView::EditKeyPressed); + m_view->setRootIsDecorated(false); + m_view->setTextElideMode (Qt::ElideMiddle); + connect(m_view->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(updateUi())); + connect(m_view->header(), SIGNAL(sectionDoubleClicked(int)), m_view, SLOT(resizeColumnToContents(int))); + + QVBoxLayout *layout = new QVBoxLayout(this); + layout->setMargin(0); + layout->setSpacing(0); + + QToolBar *toolBar = new QToolBar; + toolBar->setIconSize(QSize(22, 22)); + m_add_button->setIcon(createIconSet(QLatin1String("plus.png"))); + connect(m_add_button, SIGNAL(clicked()), this, SLOT(addConnection())); + toolBar->addWidget(m_add_button); + + m_remove_button->setIcon(createIconSet(QLatin1String("minus.png"))); + connect(m_remove_button, SIGNAL(clicked()), this, SLOT(removeConnection())); + toolBar->addWidget(m_remove_button); + + layout->addWidget(toolBar); + layout->addWidget(m_view); + + connect(core->formWindowManager(), + SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)), + this, SLOT(setActiveFormWindow(QDesignerFormWindowInterface*))); + + updateUi(); +} + +void SignalSlotEditorWindow::setActiveFormWindow(QDesignerFormWindowInterface *form) +{ + QDesignerIntegration *integration = qobject_cast(m_core->integration()); + + if (!m_editor.isNull()) { + disconnect(m_view->selectionModel(), + SIGNAL(currentChanged(QModelIndex,QModelIndex)), + this, SLOT(updateEditorSelection(QModelIndex))); + disconnect(m_editor, SIGNAL(connectionSelected(Connection*)), + this, SLOT(updateDialogSelection(Connection*))); + if (integration) { + disconnect(integration, SIGNAL(objectNameChanged(QDesignerFormWindowInterface*,QObject*,QString,QString)), + this, SLOT(objectNameChanged(QDesignerFormWindowInterface*,QObject*,QString,QString))); + } + } + + m_editor = form->findChild(); + m_model->setEditor(m_editor); + if (!m_editor.isNull()) { + ConnectionDelegate *delegate + = qobject_cast(m_view->itemDelegate()); + if (delegate != 0) + delegate->setForm(form); + + connect(m_view->selectionModel(), + SIGNAL(currentChanged(QModelIndex,QModelIndex)), + this, SLOT(updateEditorSelection(QModelIndex))); + connect(m_editor, SIGNAL(connectionSelected(Connection*)), + this, SLOT(updateDialogSelection(Connection*))); + if (integration) { + connect(integration, SIGNAL(objectNameChanged(QDesignerFormWindowInterface*,QObject*,QString,QString)), + this, SLOT(objectNameChanged(QDesignerFormWindowInterface*,QObject*,QString,QString))); + } + } + + updateUi(); +} + +void SignalSlotEditorWindow::updateDialogSelection(Connection *con) +{ + if (m_handling_selection_change || m_editor == 0) + return; + + QModelIndex index = m_proxy_model->mapFromSource(m_model->connectionToIndex(con)); + if (index == m_view->currentIndex()) + return; + m_handling_selection_change = true; + m_view->setCurrentIndex(index); + m_handling_selection_change = false; + + updateUi(); +} + +void SignalSlotEditorWindow::updateEditorSelection(const QModelIndex &index) +{ + if (m_handling_selection_change || m_editor == 0) + return; + + if (m_editor == 0) + return; + + Connection *con = m_model->indexToConnection(m_proxy_model->mapToSource(index)); + if (m_editor->selected(con)) + return; + m_handling_selection_change = true; + m_editor->selectNone(); + m_editor->setSelected(con, true); + m_handling_selection_change = false; + + updateUi(); +} + +void SignalSlotEditorWindow::objectNameChanged(QDesignerFormWindowInterface *, QObject *, const QString &, const QString &) +{ + if (m_editor) + m_model->updateAll(); +} + +void SignalSlotEditorWindow::addConnection() +{ + if (m_editor.isNull()) + return; + + m_editor->addEmptyConnection(); + updateUi(); +} + +void SignalSlotEditorWindow::removeConnection() +{ + if (m_editor.isNull()) + return; + + m_editor->deleteSelected(); + updateUi(); +} + +void SignalSlotEditorWindow::updateUi() +{ + m_add_button->setEnabled(!m_editor.isNull()); + m_remove_button->setEnabled(!m_editor.isNull() && m_view->currentIndex().isValid()); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#include "signalsloteditorwindow.moc" diff --git a/src/designer/src/components/signalsloteditor/signalsloteditorwindow.h b/src/designer/src/components/signalsloteditor/signalsloteditorwindow.h new file mode 100644 index 000000000..179b6c5f4 --- /dev/null +++ b/src/designer/src/components/signalsloteditor/signalsloteditorwindow.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SIGNALSLOTEDITORWINDOW_H +#define SIGNALSLOTEDITORWINDOW_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QDesignerFormEditorInterface; +class QModelIndex; +class QSortFilterProxyModel; +class QTreeView; +class QToolButton; + +namespace qdesigner_internal { + +class SignalSlotEditor; +class ConnectionModel; +class Connection; + +class SignalSlotEditorWindow : public QWidget +{ + Q_OBJECT +public: + explicit SignalSlotEditorWindow(QDesignerFormEditorInterface *core, QWidget *parent = 0); + +public slots: + void setActiveFormWindow(QDesignerFormWindowInterface *form); + +private slots: + void updateDialogSelection(Connection *con); + void updateEditorSelection(const QModelIndex &index); + + void objectNameChanged(QDesignerFormWindowInterface *formWindow, QObject *object, const QString &newName, const QString &oldName); + + void addConnection(); + void removeConnection(); + void updateUi(); + +private: + QTreeView *m_view; + QPointer m_editor; + QToolButton *m_add_button, *m_remove_button; + QDesignerFormEditorInterface *m_core; + ConnectionModel *m_model; + QSortFilterProxyModel *m_proxy_model; + bool m_handling_selection_change; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // SIGNALSLOTEDITORWINDOW_H diff --git a/src/designer/src/components/tabordereditor/tabordereditor.cpp b/src/designer/src/components/tabordereditor/tabordereditor.cpp new file mode 100644 index 000000000..e372bdc14 --- /dev/null +++ b/src/designer/src/components/tabordereditor/tabordereditor.cpp @@ -0,0 +1,433 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "tabordereditor.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +Q_DECLARE_METATYPE(QWidgetList) + +QT_BEGIN_NAMESPACE + +namespace { + enum { VBOX_MARGIN = 1, HBOX_MARGIN = 4, BG_ALPHA = 32 }; +} + +static QRect fixRect(const QRect &r) +{ + return QRect(r.x(), r.y(), r.width() - 1, r.height() - 1); +} + +namespace qdesigner_internal { + +TabOrderEditor::TabOrderEditor(QDesignerFormWindowInterface *form, QWidget *parent) : + QWidget(parent), + m_form_window(form), + m_bg_widget(0), + m_undo_stack(form->commandHistory()), + m_font_metrics(font()), + m_current_index(0), + m_beginning(true) +{ + connect(form, SIGNAL(widgetRemoved(QWidget*)), this, SLOT(widgetRemoved(QWidget*))); + + QFont tabFont = font(); + tabFont.setPointSize(tabFont.pointSize()*2); + tabFont.setBold(true); + setFont(tabFont); + m_font_metrics = QFontMetrics(tabFont); + setAttribute(Qt::WA_MouseTracking, true); +} + +QDesignerFormWindowInterface *TabOrderEditor::formWindow() const +{ + return m_form_window; +} + +void TabOrderEditor::setBackground(QWidget *background) +{ + if (background == m_bg_widget) { + return; + } + + m_bg_widget = background; + updateBackground(); +} + +void TabOrderEditor::updateBackground() +{ + if (m_bg_widget == 0) { + // nothing to do + return; + } + + initTabOrder(); + update(); +} + +void TabOrderEditor::widgetRemoved(QWidget*) +{ + initTabOrder(); +} + +void TabOrderEditor::showEvent(QShowEvent *e) +{ + QWidget::showEvent(e); + updateBackground(); +} + +QRect TabOrderEditor::indicatorRect(int index) const +{ + if (index < 0 || index >= m_tab_order_list.size()) + return QRect(); + + const QWidget *w = m_tab_order_list.at(index); + const QString text = QString::number(index + 1); + + const QPoint tl = mapFromGlobal(w->mapToGlobal(w->rect().topLeft())); + const QSize size = m_font_metrics.size(Qt::TextSingleLine, text); + QRect r(tl - QPoint(size.width(), size.height())/2, size); + r = QRect(r.left() - HBOX_MARGIN, r.top() - VBOX_MARGIN, + r.width() + HBOX_MARGIN*2, r.height() + VBOX_MARGIN*2); + + return r; +} + +static bool isWidgetVisible(QWidget *widget) +{ + while (widget && widget->parentWidget()) { + if (!widget->isVisibleTo(widget->parentWidget())) + return false; + + widget = widget->parentWidget(); + } + + return true; +} + +void TabOrderEditor::paintEvent(QPaintEvent *e) +{ + QPainter p(this); + p.setClipRegion(e->region()); + + int cur = m_current_index - 1; + if (m_beginning == false && cur < 0) + cur = m_tab_order_list.size() - 1; + + for (int i = 0; i < m_tab_order_list.size(); ++i) { + QWidget *widget = m_tab_order_list.at(i); + if (!isWidgetVisible(widget)) + continue; + + const QRect r = indicatorRect(i); + + QColor c = Qt::darkGreen; + if (i == cur) + c = Qt::red; + else if (i > cur) + c = Qt::blue; + p.setPen(c); + c.setAlpha(BG_ALPHA); + p.setBrush(c); + p.drawRect(fixRect(r)); + + p.setPen(Qt::white); + p.drawText(r, QString::number(i + 1), QTextOption(Qt::AlignCenter)); + } +} + +bool TabOrderEditor::skipWidget(QWidget *w) const +{ + if (qobject_cast(w) + || w == formWindow()->mainContainer() + || w->isHidden()) + return true; + + if (!formWindow()->isManaged(w)) { + return true; + } + + QExtensionManager *ext = formWindow()->core()->extensionManager(); + if (const QDesignerPropertySheetExtension *sheet = qt_extension(ext, w)) { + const int index = sheet->indexOf(QLatin1String("focusPolicy")); + if (index != -1) { + bool ok = false; + Qt::FocusPolicy q = (Qt::FocusPolicy) Utils::valueOf(sheet->property(index), &ok); + return !ok || q == Qt::NoFocus; + } + } + + return true; +} + +void TabOrderEditor::initTabOrder() +{ + m_tab_order_list.clear(); + + QDesignerFormEditorInterface *core = formWindow()->core(); + + if (const QDesignerMetaDataBaseItemInterface *item = core->metaDataBase()->item(formWindow())) { + m_tab_order_list = item->tabOrder(); + } + + // Remove any widgets that have been removed form the form + for (int i = 0; i < m_tab_order_list.size(); ) { + QWidget *w = m_tab_order_list.at(i); + if (!formWindow()->mainContainer()->isAncestorOf(w) || skipWidget(w)) + m_tab_order_list.removeAt(i); + else + ++i; + } + + // Append any widgets that are in the form but are not in the tab order + QList childQueue; + childQueue.append(formWindow()->mainContainer()); + while (!childQueue.isEmpty()) { + QWidget *child = childQueue.takeFirst(); + childQueue += qvariant_cast(child->property("_q_widgetOrder")); + + if (skipWidget(child)) + continue; + + if (!m_tab_order_list.contains(child)) + m_tab_order_list.append(child); + } + + // Just in case we missed some widgets + QDesignerFormWindowCursorInterface *cursor = formWindow()->cursor(); + for (int i = 0; i < cursor->widgetCount(); ++i) { + + QWidget *widget = cursor->widget(i); + if (skipWidget(widget)) + continue; + + if (!m_tab_order_list.contains(widget)) + m_tab_order_list.append(widget); + } + + m_indicator_region = QRegion(); + for (int i = 0; i < m_tab_order_list.size(); ++i) { + if (m_tab_order_list.at(i)->isVisible()) + m_indicator_region |= indicatorRect(i); + } + + if (m_current_index >= m_tab_order_list.size()) + m_current_index = m_tab_order_list.size() - 1; + if (m_current_index < 0) + m_current_index = 0; +} + +void TabOrderEditor::mouseMoveEvent(QMouseEvent *e) +{ + e->accept(); +#ifndef QT_NO_CURSOR + if (m_indicator_region.contains(e->pos())) + setCursor(Qt::PointingHandCursor); + else + setCursor(QCursor()); +#endif +} + +int TabOrderEditor::widgetIndexAt(const QPoint &pos) const +{ + int target_index = -1; + for (int i = 0; i < m_tab_order_list.size(); ++i) { + if (!m_tab_order_list.at(i)->isVisible()) + continue; + if (indicatorRect(i).contains(pos)) { + target_index = i; + break; + } + } + + return target_index; +} + +void TabOrderEditor::mousePressEvent(QMouseEvent *e) +{ + e->accept(); + + if (!m_indicator_region.contains(e->pos())) { + if (QWidget *child = m_bg_widget->childAt(e->pos())) { + QDesignerFormEditorInterface *core = m_form_window->core(); + if (core->widgetFactory()->isPassiveInteractor(child)) { + + QMouseEvent event(QEvent::MouseButtonPress, + child->mapFromGlobal(e->globalPos()), + e->button(), e->buttons(), e->modifiers()); + + qApp->sendEvent(child, &event); + + QMouseEvent event2(QEvent::MouseButtonRelease, + child->mapFromGlobal(e->globalPos()), + e->button(), e->buttons(), e->modifiers()); + + qApp->sendEvent(child, &event2); + + updateBackground(); + } + } + return; + } + + if (e->button() != Qt::LeftButton) + return; + + const int target_index = widgetIndexAt(e->pos()); + if (target_index == -1) + return; + + m_beginning = false; + + if (e->modifiers() & Qt::ControlModifier) { + m_current_index = target_index + 1; + if (m_current_index >= m_tab_order_list.size()) + m_current_index = 0; + update(); + return; + } + + if (m_current_index == -1) + return; + + m_tab_order_list.swap(target_index, m_current_index); + + ++m_current_index; + if (m_current_index == m_tab_order_list.size()) + m_current_index = 0; + + TabOrderCommand *cmd = new TabOrderCommand(formWindow()); + cmd->init(m_tab_order_list); + formWindow()->commandHistory()->push(cmd); +} + +void TabOrderEditor::contextMenuEvent(QContextMenuEvent *e) +{ + QMenu menu(this); + const int target_index = widgetIndexAt(e->pos()); + QAction *setIndex = menu.addAction(tr("Start from Here")); + setIndex->setEnabled(target_index >= 0); + + QAction *resetIndex = menu.addAction(tr("Restart")); + menu.addSeparator(); + QAction *showDialog = menu.addAction(tr("Tab Order List...")); + showDialog->setEnabled(m_tab_order_list.size() > 1); + + QAction *result = menu.exec(e->globalPos()); + if (result == resetIndex) { + m_current_index = 0; + m_beginning = true; + update(); + } else if (result == setIndex) { + m_beginning = false; + m_current_index = target_index + 1; + if (m_current_index >= m_tab_order_list.size()) + m_current_index = 0; + update(); + } else if (result == showDialog) { + showTabOrderDialog(); + } +} + +void TabOrderEditor::mouseDoubleClickEvent(QMouseEvent *e) +{ + if (e->button() != Qt::LeftButton) + return; + + const int target_index = widgetIndexAt(e->pos()); + if (target_index >= 0) + return; + + m_beginning = true; + m_current_index = 0; + update(); +} + +void TabOrderEditor::resizeEvent(QResizeEvent *e) +{ + updateBackground(); + QWidget::resizeEvent(e); +} + +void TabOrderEditor::showTabOrderDialog() +{ + if (m_tab_order_list.size() < 2) + return; + OrderDialog dlg(this); + dlg.setWindowTitle(tr("Tab Order List")); + dlg.setDescription(tr("Tab Order")); + dlg.setFormat(OrderDialog::TabOrderFormat); + dlg.setPageList(m_tab_order_list); + + if (dlg.exec() == QDialog::Rejected) + return; + + const QWidgetList newOrder = dlg.pageList(); + if (newOrder == m_tab_order_list) + return; + + m_tab_order_list = newOrder; + TabOrderCommand *cmd = new TabOrderCommand(formWindow()); + cmd->init(m_tab_order_list); + formWindow()->commandHistory()->push(cmd); + update(); +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/tabordereditor/tabordereditor.h b/src/designer/src/components/tabordereditor/tabordereditor.h new file mode 100644 index 000000000..3eacd3739 --- /dev/null +++ b/src/designer/src/components/tabordereditor/tabordereditor.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TABORDEREDITOR_H +#define TABORDEREDITOR_H + +#include "tabordereditor_global.h" + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QUndoStack; +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class QT_TABORDEREDITOR_EXPORT TabOrderEditor : public QWidget +{ + Q_OBJECT + +public: + TabOrderEditor(QDesignerFormWindowInterface *form, QWidget *parent); + + QDesignerFormWindowInterface *formWindow() const; + +public slots: + void setBackground(QWidget *background); + void updateBackground(); + void widgetRemoved(QWidget*); + void initTabOrder(); + +private slots: + void showTabOrderDialog(); + +protected: + virtual void paintEvent(QPaintEvent *e); + virtual void mouseMoveEvent(QMouseEvent *e); + virtual void mousePressEvent(QMouseEvent *e); + virtual void mouseDoubleClickEvent(QMouseEvent *e); + virtual void contextMenuEvent(QContextMenuEvent *e); + virtual void resizeEvent(QResizeEvent *e); + virtual void showEvent(QShowEvent *e); + +private: + QRect indicatorRect(int index) const; + int widgetIndexAt(const QPoint &pos) const; + bool skipWidget(QWidget *w) const; + + QPointer m_form_window; + + QWidgetList m_tab_order_list; + + QWidget *m_bg_widget; + QUndoStack *m_undo_stack; + QRegion m_indicator_region; + + QFontMetrics m_font_metrics; + int m_current_index; + bool m_beginning; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif diff --git a/src/designer/src/components/tabordereditor/tabordereditor.pri b/src/designer/src/components/tabordereditor/tabordereditor.pri new file mode 100644 index 000000000..786c6ae02 --- /dev/null +++ b/src/designer/src/components/tabordereditor/tabordereditor.pri @@ -0,0 +1,16 @@ + +QT += xml + +INCLUDEPATH += $$PWD + +HEADERS += \ + $$PWD/tabordereditor.h \ + $$PWD/tabordereditor_plugin.h \ + $$PWD/tabordereditor_tool.h \ + $$PWD/tabordereditor_global.h + +SOURCES += \ + $$PWD/tabordereditor.cpp \ + $$PWD/tabordereditor_tool.cpp \ + $$PWD/tabordereditor_plugin.cpp \ + $$PWD/tabordereditor_instance.cpp diff --git a/src/designer/src/components/tabordereditor/tabordereditor_global.h b/src/designer/src/components/tabordereditor/tabordereditor_global.h new file mode 100644 index 000000000..13b5e348d --- /dev/null +++ b/src/designer/src/components/tabordereditor/tabordereditor_global.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TABORDEREDITOR_GLOBAL_H +#define TABORDEREDITOR_GLOBAL_H + +#include + +#ifdef Q_OS_WIN +#ifdef QT_TABORDEREDITOR_LIBRARY +# define QT_TABORDEREDITOR_EXPORT +#else +# define QT_TABORDEREDITOR_EXPORT +#endif +#else +#define QT_TABORDEREDITOR_EXPORT +#endif + +#endif // TABORDEREDITOR_GLOBAL_H diff --git a/src/designer/src/components/tabordereditor/tabordereditor_instance.cpp b/src/designer/src/components/tabordereditor/tabordereditor_instance.cpp new file mode 100644 index 000000000..6ff7903f7 --- /dev/null +++ b/src/designer/src/components/tabordereditor/tabordereditor_instance.cpp @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "tabordereditor_plugin.h" + +QT_USE_NAMESPACE +using namespace qdesigner_internal; + +Q_EXPORT_PLUGIN(TabOrderEditorPlugin) diff --git a/src/designer/src/components/tabordereditor/tabordereditor_plugin.cpp b/src/designer/src/components/tabordereditor/tabordereditor_plugin.cpp new file mode 100644 index 000000000..49581e5f6 --- /dev/null +++ b/src/designer/src/components/tabordereditor/tabordereditor_plugin.cpp @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "tabordereditor_plugin.h" +#include "tabordereditor_tool.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +TabOrderEditorPlugin::TabOrderEditorPlugin() + : m_initialized(false) +{ +} + +TabOrderEditorPlugin::~TabOrderEditorPlugin() +{ +} + +bool TabOrderEditorPlugin::isInitialized() const +{ + return m_initialized; +} + +void TabOrderEditorPlugin::initialize(QDesignerFormEditorInterface *core) +{ + Q_ASSERT(!isInitialized()); + + m_action = new QAction(tr("Edit Tab Order"), this); + m_action->setObjectName(QLatin1String("_qt_edit_tab_order_action")); + QIcon icon = QIcon::fromTheme("designer-edit-tabs", + QIcon(core->resourceLocation() + QLatin1String("/tabordertool.png"))); + m_action->setIcon(icon); + m_action->setEnabled(false); + + setParent(core); + m_core = core; + m_initialized = true; + + connect(core->formWindowManager(), SIGNAL(formWindowAdded(QDesignerFormWindowInterface*)), + this, SLOT(addFormWindow(QDesignerFormWindowInterface*))); + + connect(core->formWindowManager(), SIGNAL(formWindowRemoved(QDesignerFormWindowInterface*)), + this, SLOT(removeFormWindow(QDesignerFormWindowInterface*))); + + connect(core->formWindowManager(), SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)), + this, SLOT(activeFormWindowChanged(QDesignerFormWindowInterface*))); +} + +void TabOrderEditorPlugin::activeFormWindowChanged(QDesignerFormWindowInterface *formWindow) +{ + m_action->setEnabled(formWindow != 0); +} + +QDesignerFormEditorInterface *TabOrderEditorPlugin::core() const +{ + return m_core; +} + +void TabOrderEditorPlugin::addFormWindow(QDesignerFormWindowInterface *formWindow) +{ + Q_ASSERT(formWindow != 0); + Q_ASSERT(m_tools.contains(formWindow) == false); + + TabOrderEditorTool *tool = new TabOrderEditorTool(formWindow, this); + m_tools[formWindow] = tool; + connect(m_action, SIGNAL(triggered()), tool->action(), SLOT(trigger())); + formWindow->registerTool(tool); +} + +void TabOrderEditorPlugin::removeFormWindow(QDesignerFormWindowInterface *formWindow) +{ + Q_ASSERT(formWindow != 0); + Q_ASSERT(m_tools.contains(formWindow) == true); + + TabOrderEditorTool *tool = m_tools.value(formWindow); + m_tools.remove(formWindow); + disconnect(m_action, SIGNAL(triggered()), tool->action(), SLOT(trigger())); + // ### FIXME disable the tool + + delete tool; +} + +QAction *TabOrderEditorPlugin::action() const +{ + return m_action; +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/tabordereditor/tabordereditor_plugin.h b/src/designer/src/components/tabordereditor/tabordereditor_plugin.h new file mode 100644 index 000000000..685804624 --- /dev/null +++ b/src/designer/src/components/tabordereditor/tabordereditor_plugin.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TABORDEREDITOR_PLUGIN_H +#define TABORDEREDITOR_PLUGIN_H + +#include "tabordereditor_global.h" + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QAction; + +namespace qdesigner_internal { + +class TabOrderEditorTool; + +class QT_TABORDEREDITOR_EXPORT TabOrderEditorPlugin: public QObject, public QDesignerFormEditorPluginInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerFormEditorPluginInterface) +public: + TabOrderEditorPlugin(); + virtual ~TabOrderEditorPlugin(); + + virtual bool isInitialized() const; + virtual void initialize(QDesignerFormEditorInterface *core); + QAction *action() const; + + virtual QDesignerFormEditorInterface *core() const; + +public slots: + void activeFormWindowChanged(QDesignerFormWindowInterface *formWindow); + +private slots: + void addFormWindow(QDesignerFormWindowInterface *formWindow); + void removeFormWindow(QDesignerFormWindowInterface *formWindow); + +private: + QPointer m_core; + QHash m_tools; + bool m_initialized; + QAction *m_action; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // TABORDEREDITOR_PLUGIN_H diff --git a/src/designer/src/components/tabordereditor/tabordereditor_tool.cpp b/src/designer/src/components/tabordereditor/tabordereditor_tool.cpp new file mode 100644 index 000000000..2914cb58a --- /dev/null +++ b/src/designer/src/components/tabordereditor/tabordereditor_tool.cpp @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "tabordereditor_tool.h" +#include "tabordereditor.h" + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +TabOrderEditorTool::TabOrderEditorTool(QDesignerFormWindowInterface *formWindow, QObject *parent) + : QDesignerFormWindowToolInterface(parent), + m_formWindow(formWindow), + m_action(new QAction(tr("Edit Tab Order"), this)) +{ +} + +TabOrderEditorTool::~TabOrderEditorTool() +{ +} + +QDesignerFormEditorInterface *TabOrderEditorTool::core() const +{ + return m_formWindow->core(); +} + +QDesignerFormWindowInterface *TabOrderEditorTool::formWindow() const +{ + return m_formWindow; +} + +bool TabOrderEditorTool::handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event) +{ + Q_UNUSED(widget); + Q_UNUSED(managedWidget); + + if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) + return true; + + return false; +} + +QWidget *TabOrderEditorTool::editor() const +{ + if (!m_editor) { + Q_ASSERT(formWindow() != 0); + m_editor = new TabOrderEditor(formWindow(), 0); + connect(formWindow(), SIGNAL(mainContainerChanged(QWidget*)), m_editor, SLOT(setBackground(QWidget*))); + } + + return m_editor; +} + +void TabOrderEditorTool::activated() +{ + connect(formWindow(), SIGNAL(changed()), + m_editor, SLOT(updateBackground())); +} + +void TabOrderEditorTool::deactivated() +{ + disconnect(formWindow(), SIGNAL(changed()), + m_editor, SLOT(updateBackground())); +} + +QAction *TabOrderEditorTool::action() const +{ + return m_action; +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/tabordereditor/tabordereditor_tool.h b/src/designer/src/components/tabordereditor/tabordereditor_tool.h new file mode 100644 index 000000000..d978e4949 --- /dev/null +++ b/src/designer/src/components/tabordereditor/tabordereditor_tool.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TABORDEREDITOR_TOOL_H +#define TABORDEREDITOR_TOOL_H + +#include "tabordereditor_global.h" + +#include + +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; +class QAction; + +namespace qdesigner_internal { + +class TabOrderEditor; + +class QT_TABORDEREDITOR_EXPORT TabOrderEditorTool: public QDesignerFormWindowToolInterface +{ + Q_OBJECT +public: + explicit TabOrderEditorTool(QDesignerFormWindowInterface *formWindow, QObject *parent = 0); + virtual ~TabOrderEditorTool(); + + virtual QDesignerFormEditorInterface *core() const; + virtual QDesignerFormWindowInterface *formWindow() const; + + virtual QWidget *editor() const; + virtual QAction *action() const; + + virtual void activated(); + virtual void deactivated(); + + virtual bool handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event); + +private: + QDesignerFormWindowInterface *m_formWindow; + mutable QPointer m_editor; + QAction *m_action; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // TABORDEREDITOR_TOOL_H diff --git a/src/designer/src/components/taskmenu/button_taskmenu.cpp b/src/designer/src/components/taskmenu/button_taskmenu.cpp new file mode 100644 index 000000000..953996b8c --- /dev/null +++ b/src/designer/src/components/taskmenu/button_taskmenu.cpp @@ -0,0 +1,709 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "button_taskmenu.h" +#include "inplace_editor.h" +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +Q_DECLARE_METATYPE(QButtonGroup*) + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +enum { debugButtonMenu = 0 }; + +typedef QList ButtonList; +typedef QList ButtonGroupList; + +// ButtonGroupCommand: Base for commands handling button groups and button lists +// addButtonsToGroup() and removeButtonsFromGroup() are low-level helpers for +// adding/removing members to/from existing groups. +// +// createButtonGroup()/breakButtonGroup() create and remove the groups from scratch. +// When using them in a command, the command must be executed within +// a macro since it makes the form emit objectRemoved() which might cause other components +// to add commands (for example, removal of signals and slots) +class ButtonGroupCommand : public QDesignerFormWindowCommand { + +protected: + ButtonGroupCommand(const QString &description, QDesignerFormWindowInterface *formWindow); + + void initialize(const ButtonList &bl, QButtonGroup *buttonGroup); + + // Helper: Add the buttons to the group + void addButtonsToGroup(); + // Helper; Remove the buttons + void removeButtonsFromGroup(); + + // Create the button group in Designer + void createButtonGroup(); + // Remove the button group from Designer + void breakButtonGroup(); + +public: + static QString nameList(const ButtonList& bl); + static ButtonGroupList managedButtonGroups(const QDesignerFormWindowInterface *formWindow); + +private: + ButtonList m_buttonList; + QButtonGroup *m_buttonGroup; +}; + +ButtonGroupCommand::ButtonGroupCommand(const QString &description, QDesignerFormWindowInterface *formWindow) : + QDesignerFormWindowCommand(description, formWindow), + m_buttonGroup(0) +{ +} + +void ButtonGroupCommand::initialize(const ButtonList &bl, QButtonGroup *buttonGroup) +{ + m_buttonList = bl; + m_buttonGroup = buttonGroup; +} + +void ButtonGroupCommand::addButtonsToGroup() +{ + if (debugButtonMenu) + qDebug() << "Adding " << m_buttonList << " to " << m_buttonGroup; + const ButtonList::const_iterator cend = m_buttonList.constEnd(); + for (ButtonList::const_iterator it = m_buttonList.constBegin(); it != cend; ++it) + m_buttonGroup->addButton(*it); +} + +void ButtonGroupCommand::removeButtonsFromGroup() +{ + if (debugButtonMenu) + qDebug() << "Removing " << m_buttonList << " from " << m_buttonGroup; + const ButtonList::const_iterator cend = m_buttonList.constEnd(); + for (ButtonList::const_iterator it = m_buttonList.constBegin(); it != cend; ++it) + m_buttonGroup->removeButton(*it); +} + +void ButtonGroupCommand::createButtonGroup() +{ + if (debugButtonMenu) + qDebug() << "Creating " << m_buttonGroup << " from " << m_buttonList; + + QDesignerFormWindowInterface *fw = formWindow(); + QDesignerFormEditorInterface *core = fw->core(); + core->metaDataBase()->add(m_buttonGroup); + addButtonsToGroup(); + // Make button group visible + core->objectInspector()->setFormWindow(fw); +} + +void ButtonGroupCommand::breakButtonGroup() +{ + if (debugButtonMenu) + qDebug() << "Removing " << m_buttonGroup << " consisting of " << m_buttonList; + + QDesignerFormWindowInterface *fw = formWindow(); + QDesignerFormEditorInterface *core = fw->core(); + // Button group was selected, that is, break was invoked via its context menu. Remove it from property editor, select the buttons + if (core->propertyEditor()->object() == m_buttonGroup) { + fw->clearSelection(false); + const ButtonList::const_iterator cend = m_buttonList.constEnd(); + for (ButtonList::const_iterator it = m_buttonList.constBegin(); it != cend; ++it) + fw->selectWidget(*it, true); + } + // Now remove and refresh object inspector + removeButtonsFromGroup(); + // Notify components (for example, signal slot editor) + if (qdesigner_internal::FormWindowBase *fwb = qobject_cast(fw)) + fwb->emitObjectRemoved(m_buttonGroup); + core->metaDataBase()->remove(m_buttonGroup); + core->objectInspector()->setFormWindow(fw); +} + +QString ButtonGroupCommand::nameList(const ButtonList& bl) +{ + QString rc; + const QChar quote = QLatin1Char('\''); + const QString separator = QLatin1String(", "); + const int size = bl.size(); + for (int i = 0; i < size; i++) { + if (i) + rc += separator; + rc += quote; + rc += bl[i]->objectName(); + rc += quote; + } + return rc; + +} + +ButtonGroupList ButtonGroupCommand::managedButtonGroups(const QDesignerFormWindowInterface *formWindow) +{ + const QDesignerMetaDataBaseInterface *mdb = formWindow->core()->metaDataBase(); + ButtonGroupList bl; + // Check 1st order children for managed button groups + const QObjectList children = formWindow->mainContainer()->children(); + const QObjectList::const_iterator cend = children.constEnd(); + for (QObjectList::const_iterator it = children.constBegin(); it != cend; ++it) { + if (!(*it)->isWidgetType()) + if (QButtonGroup *bg = qobject_cast(*it)) + if (mdb->item(bg)) + bl.push_back(bg); + } + return bl; +} + +// --------------- CreateButtonGroupCommand +// This command might be executed in a macro with a remove +// command to move buttons from one group to a new one. +class CreateButtonGroupCommand : public ButtonGroupCommand { +public: + CreateButtonGroupCommand(QDesignerFormWindowInterface *formWindow); + bool init(const ButtonList &bl); + + virtual void undo() { breakButtonGroup(); } + virtual void redo() { createButtonGroup(); } +}; + +CreateButtonGroupCommand::CreateButtonGroupCommand(QDesignerFormWindowInterface *formWindow) : + ButtonGroupCommand(QApplication::translate("Command", "Create button group"), formWindow) +{ +} + +bool CreateButtonGroupCommand::init(const ButtonList &bl) +{ + if (bl.empty()) + return false; + QDesignerFormWindowInterface *fw = formWindow(); + QButtonGroup *buttonGroup = new QButtonGroup(fw->mainContainer()); + buttonGroup->setObjectName(QLatin1String("buttonGroup")); + fw->ensureUniqueObjectName(buttonGroup); + initialize(bl, buttonGroup); + return true; +} + +// --------------- BreakButtonGroupCommand +class BreakButtonGroupCommand : public ButtonGroupCommand { +public: + BreakButtonGroupCommand(QDesignerFormWindowInterface *formWindow); + bool init(QButtonGroup *group); + + virtual void undo() { createButtonGroup(); } + virtual void redo() { breakButtonGroup(); } +}; + +BreakButtonGroupCommand::BreakButtonGroupCommand(QDesignerFormWindowInterface *formWindow) : + ButtonGroupCommand(QApplication::translate("Command", "Break button group"), formWindow) +{ +} + +bool BreakButtonGroupCommand::init(QButtonGroup *group) +{ + if (!group) + return false; + initialize(group->buttons(), group); + setText(QApplication::translate("Command", "Break button group '%1'").arg(group->objectName())); + return true; +} + +// --------------- AddButtonsToGroupCommand +// This command might be executed in a macro with a remove +// command to move buttons from one group to a new one. +class AddButtonsToGroupCommand : public ButtonGroupCommand { +public: + AddButtonsToGroupCommand(QDesignerFormWindowInterface *formWindow); + void init(const ButtonList &bl, QButtonGroup *group); + + virtual void undo() { removeButtonsFromGroup(); } + virtual void redo() { addButtonsToGroup(); } +}; + +AddButtonsToGroupCommand::AddButtonsToGroupCommand(QDesignerFormWindowInterface *formWindow) : + ButtonGroupCommand(QApplication::translate("Command", "Add buttons to group"), formWindow) +{ +} + +void AddButtonsToGroupCommand::init(const ButtonList &bl, QButtonGroup *group) +{ + initialize(bl, group); + //: Command description for adding buttons to a QButtonGroup + setText(QApplication::translate("Command", "Add '%1' to '%2'").arg(nameList(bl), group->objectName())); +} + +//-------------------- RemoveButtonsFromGroupCommand +class RemoveButtonsFromGroupCommand : public ButtonGroupCommand { +public: + RemoveButtonsFromGroupCommand(QDesignerFormWindowInterface *formWindow); + bool init(const ButtonList &bl); + + virtual void undo() { addButtonsToGroup(); } + virtual void redo() { removeButtonsFromGroup(); } +}; + +RemoveButtonsFromGroupCommand::RemoveButtonsFromGroupCommand(QDesignerFormWindowInterface *formWindow) : + ButtonGroupCommand(QApplication::translate("Command", "Remove buttons from group"), formWindow) +{ +} + +bool RemoveButtonsFromGroupCommand::init(const ButtonList &bl) +{ + if (bl.empty()) + return false; + QButtonGroup *group = bl.front()->group(); + if (!group) + return false; + if (bl.size() >= group->buttons().size()) + return false; + initialize(bl, group); + //: Command description for removing buttons from a QButtonGroup + setText(QApplication::translate("Command", "Remove '%1' from '%2'").arg(nameList(bl), group->objectName())); + return true; +} + +// -------- ButtonGroupMenu +ButtonGroupMenu::ButtonGroupMenu(QObject *parent) : + QObject(parent), + m_selectGroupAction(new QAction(tr("Select members"), this)), + m_breakGroupAction(new QAction(tr("Break"), this)), + m_formWindow(0), + m_buttonGroup(0), + m_currentButton(0) +{ + connect(m_breakGroupAction, SIGNAL(triggered()), this, SLOT(breakGroup())); + connect(m_selectGroupAction, SIGNAL(triggered()), this, SLOT(selectGroup())); +} + +void ButtonGroupMenu::initialize(QDesignerFormWindowInterface *formWindow, QButtonGroup *buttonGroup, QAbstractButton *currentButton) +{ + m_buttonGroup = buttonGroup; + m_currentButton = currentButton; + m_formWindow = formWindow; + Q_ASSERT(m_formWindow); + + const bool canBreak = buttonGroup != 0; + m_breakGroupAction->setEnabled(canBreak); + m_selectGroupAction->setEnabled(canBreak); +} + +void ButtonGroupMenu::selectGroup() +{ + // Select and make current button "current" again by selecting it last (if there is any) + const ButtonList buttons = m_buttonGroup->buttons(); + m_formWindow->clearSelection(false); + const ButtonList::const_iterator cend = buttons.constEnd(); + for (ButtonList::const_iterator it = buttons.constBegin(); it != cend; ++it) + if (*it != m_currentButton) + m_formWindow->selectWidget(*it, true); + if (m_currentButton) + m_formWindow->selectWidget(m_currentButton, true); +} + +void ButtonGroupMenu::breakGroup() +{ + BreakButtonGroupCommand *cmd = new BreakButtonGroupCommand(m_formWindow); + if (cmd->init(m_buttonGroup)) { + // Need a macro since the command might trigger additional commands + QUndoStack *history = m_formWindow->commandHistory(); + history->beginMacro(cmd->text()); + history->push(cmd); + history->endMacro(); + } else { + qWarning("** WARNING Failed to initialize BreakButtonGroupCommand!"); + delete cmd; + } +} + +// ButtonGroupTaskMenu +ButtonGroupTaskMenu::ButtonGroupTaskMenu(QButtonGroup *buttonGroup, QObject *parent) : + QObject(parent), + m_buttonGroup(buttonGroup) +{ + m_taskActions.push_back(m_menu.breakGroupAction()); + m_taskActions.push_back(m_menu.selectGroupAction()); +} + +QAction *ButtonGroupTaskMenu::preferredEditAction() const +{ + return m_menu.selectGroupAction(); +} + +QList ButtonGroupTaskMenu::taskActions() const +{ + m_menu.initialize(QDesignerFormWindowInterface::findFormWindow(m_buttonGroup), m_buttonGroup); + return m_taskActions; +} + +// -------- Text area editor +class ButtonTextTaskMenuInlineEditor : public TaskMenuInlineEditor +{ +public: + ButtonTextTaskMenuInlineEditor(QAbstractButton *button, QObject *parent); + +protected: + virtual QRect editRectangle() const; +}; + +ButtonTextTaskMenuInlineEditor::ButtonTextTaskMenuInlineEditor(QAbstractButton *button, QObject *parent) : + TaskMenuInlineEditor(button, ValidationMultiLine, QLatin1String("text"), parent) +{ +} + +QRect ButtonTextTaskMenuInlineEditor::editRectangle() const +{ + QWidget *w = widget(); + QStyleOptionButton opt; + opt.init(w); + return w->style()->subElementRect(QStyle::SE_PushButtonContents, &opt, w); +} + +// -------- Command link button description editor +class LinkDescriptionTaskMenuInlineEditor : public TaskMenuInlineEditor +{ +public: + LinkDescriptionTaskMenuInlineEditor(QAbstractButton *button, QObject *parent); + +protected: + virtual QRect editRectangle() const; +}; + +LinkDescriptionTaskMenuInlineEditor::LinkDescriptionTaskMenuInlineEditor(QAbstractButton *button, QObject *parent) : + TaskMenuInlineEditor(button, ValidationMultiLine, QLatin1String("description"), parent) +{ +} + +QRect LinkDescriptionTaskMenuInlineEditor::editRectangle() const +{ + QWidget *w = widget(); // TODO: What is the exact description area? + QStyleOptionButton opt; + opt.init(w); + return w->style()->subElementRect(QStyle::SE_PushButtonContents, &opt, w); +} + +// ----------- ButtonTaskMenu: + +ButtonTaskMenu::ButtonTaskMenu(QAbstractButton *button, QObject *parent) : + QDesignerTaskMenu(button, parent), + m_assignGroupSubMenu(new QMenu), + m_assignActionGroup(0), + m_assignToGroupSubMenuAction(new QAction(tr("Assign to button group"), this)), + m_currentGroupSubMenu(new QMenu), + m_currentGroupSubMenuAction(new QAction(tr("Button group"), this)), + m_createGroupAction(new QAction(tr("New button group"), this)), + m_preferredEditAction(new QAction(tr("Change text..."), this)), + m_removeFromGroupAction(new QAction(tr("None"), this)) +{ + connect(m_createGroupAction, SIGNAL(triggered()), this, SLOT(createGroup())); + TaskMenuInlineEditor *textEditor = new ButtonTextTaskMenuInlineEditor(button, this); + connect(m_preferredEditAction, SIGNAL(triggered()), textEditor, SLOT(editText())); + connect(m_removeFromGroupAction, SIGNAL(triggered()), this, SLOT(removeFromGroup())); + + m_assignToGroupSubMenuAction->setMenu(m_assignGroupSubMenu); + + m_currentGroupSubMenu->addAction(m_groupMenu.breakGroupAction()); + m_currentGroupSubMenu->addAction(m_groupMenu.selectGroupAction()); + m_currentGroupSubMenuAction->setMenu(m_currentGroupSubMenu); + + + m_taskActions.append(m_preferredEditAction); + m_taskActions.append(m_assignToGroupSubMenuAction); + m_taskActions.append(m_currentGroupSubMenuAction); + m_taskActions.append(createSeparator()); +} + +ButtonTaskMenu::~ButtonTaskMenu() +{ + delete m_assignGroupSubMenu; + delete m_currentGroupSubMenu; +} + +QAction *ButtonTaskMenu::preferredEditAction() const +{ + return m_preferredEditAction; +} + +bool ButtonTaskMenu::refreshAssignMenu(const QDesignerFormWindowInterface *fw, int buttonCount, SelectionType st, QButtonGroup *currentGroup) +{ + // clear + if (m_assignActionGroup) { + delete m_assignActionGroup; + m_assignActionGroup = 0; + } + m_assignGroupSubMenu->clear(); + if (st == OtherSelection) + return false; + + + // Assign to new: Need several + const bool canAssignToNewGroup = buttonCount > 1; + m_createGroupAction->setEnabled(canAssignToNewGroup); + if (canAssignToNewGroup) + m_assignGroupSubMenu->addAction(m_createGroupAction); + + // Assign to other + const ButtonGroupList bl = ButtonGroupCommand::managedButtonGroups(fw); + // Groups: Any groups to add to except the current? + const int groupCount = bl.size(); + const bool hasAddGroups = groupCount > 1 || (groupCount == 1 && !bl.contains(currentGroup)); + if (hasAddGroups) { + if (!m_assignGroupSubMenu->isEmpty()) + m_assignGroupSubMenu->addSeparator(); + // Create a new action group + m_assignActionGroup = new QActionGroup(this); + connect(m_assignActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(addToGroup(QAction*))); + + const ButtonGroupList::const_iterator cend = bl.constEnd(); + for (ButtonGroupList::const_iterator it = bl.constBegin(); it != cend; ++it) { + QButtonGroup *bg = *it; + if (*it != currentGroup) { + QAction *a = new QAction(bg->objectName(), m_assignGroupSubMenu); + a->setData(QVariant::fromValue(bg)); + m_assignActionGroup->addAction(a); + m_assignGroupSubMenu->addAction(a); + } + } + } + // Can remove: A homogenous selection of another group that does not completely break it. + const bool canRemoveFromGroup = st == GroupedButtonSelection; + m_removeFromGroupAction->setEnabled(canRemoveFromGroup); + if (canRemoveFromGroup) { + if (!m_assignGroupSubMenu->isEmpty()) + m_assignGroupSubMenu->addSeparator(); + m_assignGroupSubMenu->addAction(m_removeFromGroupAction); + } + return !m_assignGroupSubMenu->isEmpty(); +} + +QList ButtonTaskMenu::taskActions() const +{ + ButtonTaskMenu *ncThis = const_cast(this); + QButtonGroup *buttonGroup = 0; + + QDesignerFormWindowInterface *fw = formWindow(); + const SelectionType st = selectionType(fw->cursor(), &buttonGroup); + + m_groupMenu.initialize(fw, buttonGroup, button()); + const bool hasAssignOptions = ncThis->refreshAssignMenu(fw, fw->cursor()->selectedWidgetCount(), st, buttonGroup); + m_assignToGroupSubMenuAction->setVisible(hasAssignOptions); + // add/remove + switch (st) { + case UngroupedButtonSelection: + case OtherSelection: + m_currentGroupSubMenuAction->setVisible(false); + break; + case GroupedButtonSelection: + m_currentGroupSubMenuAction->setText(tr("Button group '%1'").arg(buttonGroup->objectName())); + m_currentGroupSubMenuAction->setVisible(true); + break; + } + + return m_taskActions + QDesignerTaskMenu::taskActions(); +} + + +void ButtonTaskMenu::insertAction(int index, QAction *a) +{ + m_taskActions.insert(index, a); +} + +/* Create a button list from the cursor selection */ +static ButtonList buttonList(const QDesignerFormWindowCursorInterface *cursor) +{ + ButtonList rc; + const int selectionCount = cursor->selectedWidgetCount(); + for (int i = 0; i < selectionCount; i++) { + QAbstractButton *ab = qobject_cast(cursor->selectedWidget(i)); + Q_ASSERT(ab); + rc += ab; + } + return rc; +} + +// Create a command to remove the buttons from their group +// If it would leave an empty or 1-member group behind, create a break command instead + +static QUndoCommand *createRemoveButtonsCommand(QDesignerFormWindowInterface *fw, const ButtonList &bl) +{ + + QButtonGroup *bg = bl.front()->group(); + // Complete group or 1-member group? + if (bl.size() >= bg->buttons().size() - 1) { + BreakButtonGroupCommand *breakCmd = new BreakButtonGroupCommand(fw); + if (!breakCmd->init(bg)) { + qWarning("** WARNING Failed to initialize BreakButtonGroupCommand!"); + delete breakCmd; + return 0; + } + return breakCmd; + } + // Just remove the buttons + + RemoveButtonsFromGroupCommand *removeCmd = new RemoveButtonsFromGroupCommand(fw); + if (!removeCmd->init(bl)) { + qWarning("** WARNING Failed to initialize RemoveButtonsFromGroupCommand!"); + delete removeCmd; + return 0; + } + return removeCmd; +} + +void ButtonTaskMenu::createGroup() +{ + QDesignerFormWindowInterface *fw = formWindow(); + const ButtonList bl = buttonList(fw->cursor()); + // Do we need to remove the buttons from an existing group? + QUndoCommand *removeCmd = 0; + if (bl.front()->group()) { + removeCmd = createRemoveButtonsCommand(fw, bl); + if (!removeCmd) + return; + } + // Add cmd + CreateButtonGroupCommand *addCmd = new CreateButtonGroupCommand(fw); + if (!addCmd->init(bl)) { + qWarning("** WARNING Failed to initialize CreateButtonGroupCommand!"); + delete addCmd; + return; + } + // Need a macro [even if we only have the add command] since the command might trigger additional commands + QUndoStack *history = fw->commandHistory(); + history->beginMacro(addCmd->text()); + if (removeCmd) + history->push(removeCmd); + history->push(addCmd); + history->endMacro(); +} + +QAbstractButton *ButtonTaskMenu::button() const +{ + return qobject_cast(widget()); +} + +// Figure out if we have a homogenous selections (buttons of the same group or no group) +ButtonTaskMenu::SelectionType ButtonTaskMenu::selectionType(const QDesignerFormWindowCursorInterface *cursor, QButtonGroup **ptrToGroup) const +{ + const int selectionCount = cursor->selectedWidgetCount(); + if (!selectionCount) + return OtherSelection; + + QButtonGroup *commonGroup = 0; + for (int i = 0; i < selectionCount; i++) { + if (const QAbstractButton *ab = qobject_cast(cursor->selectedWidget(i))) { + QButtonGroup *buttonGroup = ab->group(); + if (i) { + if (buttonGroup != commonGroup) + return OtherSelection; + } else { + commonGroup = buttonGroup; + } + } else { + return OtherSelection; + } + } + + if (ptrToGroup) + *ptrToGroup = commonGroup; + + return commonGroup ? GroupedButtonSelection : UngroupedButtonSelection; +} + +void ButtonTaskMenu::addToGroup(QAction *a) +{ + QButtonGroup *bg = qvariant_cast(a->data()); + Q_ASSERT(bg); + + QDesignerFormWindowInterface *fw = formWindow(); + const ButtonList bl = buttonList(fw->cursor()); + // Do we need to remove the buttons from an existing group? + QUndoCommand *removeCmd = 0; + if (bl.front()->group()) { + removeCmd = createRemoveButtonsCommand(fw, bl); + if (!removeCmd) + return; + } + AddButtonsToGroupCommand *addCmd = new AddButtonsToGroupCommand(fw); + addCmd->init(bl, bg); + + QUndoStack *history = fw->commandHistory(); + if (removeCmd) { + history->beginMacro(addCmd->text()); + history->push(removeCmd); + history->push(addCmd); + history->endMacro(); + } else { + history->push(addCmd); + } +} + +void ButtonTaskMenu::removeFromGroup() +{ + QDesignerFormWindowInterface *fw = formWindow(); + if (QUndoCommand *cmd = createRemoveButtonsCommand(fw, buttonList(fw->cursor()))) + fw->commandHistory()->push(cmd); +} + +// -------------- CommandLinkButtonTaskMenu + +CommandLinkButtonTaskMenu::CommandLinkButtonTaskMenu(QCommandLinkButton *button, QObject *parent) : + ButtonTaskMenu(button, parent) +{ + TaskMenuInlineEditor *descriptonEditor = new LinkDescriptionTaskMenuInlineEditor(button, this); + QAction *descriptionAction = new QAction(tr("Change description..."), this); + connect(descriptionAction, SIGNAL(triggered()), descriptonEditor, SLOT(editText())); + insertAction(1, descriptionAction); +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/taskmenu/button_taskmenu.h b/src/designer/src/components/taskmenu/button_taskmenu.h new file mode 100644 index 000000000..e7350ca87 --- /dev/null +++ b/src/designer/src/components/taskmenu/button_taskmenu.h @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BUTTON_TASKMENU_H +#define BUTTON_TASKMENU_H + +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QMenu; +class QActionGroup; +class QDesignerFormWindowCursorInterface; + +namespace qdesigner_internal { + +// ButtonGroupMenu: Mixin menu for the 'select members'/'break group' options of +// the task menu of buttons and button group +class ButtonGroupMenu : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(ButtonGroupMenu) +public: + ButtonGroupMenu(QObject *parent = 0); + + void initialize(QDesignerFormWindowInterface *formWindow, + QButtonGroup *buttonGroup = 0, + /* Current button for selection in ButtonMode */ + QAbstractButton *currentButton = 0); + + QAction *selectGroupAction() const { return m_selectGroupAction; } + QAction *breakGroupAction() const { return m_breakGroupAction; } + +private slots: + void selectGroup(); + void breakGroup(); + +private: + QAction *m_selectGroupAction; + QAction *m_breakGroupAction; + + QDesignerFormWindowInterface *m_formWindow; + QButtonGroup *m_buttonGroup; + QAbstractButton *m_currentButton; +}; + +// Task menu extension of a QButtonGroup +class ButtonGroupTaskMenu : public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_DISABLE_COPY(ButtonGroupTaskMenu) + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + explicit ButtonGroupTaskMenu(QButtonGroup *buttonGroup, QObject *parent = 0); + + virtual QAction *preferredEditAction() const; + virtual QList taskActions() const; + +private: + QButtonGroup *m_buttonGroup; + QList m_taskActions; + mutable ButtonGroupMenu m_menu; +}; + +// Task menu extension of a QAbstractButton +class ButtonTaskMenu: public QDesignerTaskMenu +{ + Q_OBJECT + Q_DISABLE_COPY(ButtonTaskMenu) +public: + explicit ButtonTaskMenu(QAbstractButton *button, QObject *parent = 0); + virtual ~ButtonTaskMenu(); + + virtual QAction *preferredEditAction() const; + virtual QList taskActions() const; + + QAbstractButton *button() const; + +protected: + void insertAction(int index, QAction *a); + +private slots: + void createGroup(); + void addToGroup(QAction *a); + void removeFromGroup(); + +private: + enum SelectionType { + OtherSelection, + UngroupedButtonSelection, + GroupedButtonSelection + }; + + SelectionType selectionType(const QDesignerFormWindowCursorInterface *cursor, QButtonGroup ** ptrToGroup = 0) const; + bool refreshAssignMenu(const QDesignerFormWindowInterface *fw, int buttonCount, SelectionType st, QButtonGroup *currentGroup); + QMenu *createGroupSelectionMenu(const QDesignerFormWindowInterface *fw); + + QList m_taskActions; + mutable ButtonGroupMenu m_groupMenu; + QMenu *m_assignGroupSubMenu; + QActionGroup *m_assignActionGroup; + QAction *m_assignToGroupSubMenuAction; + QMenu *m_currentGroupSubMenu; + QAction *m_currentGroupSubMenuAction; + + QAction *m_createGroupAction; + QAction *m_preferredEditAction; + QAction *m_removeFromGroupAction; +}; + +// Task menu extension of a QCommandLinkButton +class CommandLinkButtonTaskMenu: public ButtonTaskMenu +{ + Q_OBJECT + Q_DISABLE_COPY(CommandLinkButtonTaskMenu) +public: + explicit CommandLinkButtonTaskMenu(QCommandLinkButton *button, QObject *parent = 0); +}; + +typedef ExtensionFactory ButtonGroupTaskMenuFactory; +typedef ExtensionFactory CommandLinkButtonTaskMenuFactory; +typedef ExtensionFactory ButtonTaskMenuFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // BUTTON_TASKMENU_H diff --git a/src/designer/src/components/taskmenu/combobox_taskmenu.cpp b/src/designer/src/components/taskmenu/combobox_taskmenu.cpp new file mode 100644 index 000000000..2b9b1fe19 --- /dev/null +++ b/src/designer/src/components/taskmenu/combobox_taskmenu.cpp @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "combobox_taskmenu.h" +#include "listwidgeteditor.h" +#include "qdesigner_utils_p.h" +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +ComboBoxTaskMenu::ComboBoxTaskMenu(QComboBox *button, QObject *parent) + : QDesignerTaskMenu(button, parent), + m_comboBox(button) +{ + m_editItemsAction = new QAction(this); + m_editItemsAction->setText(tr("Edit Items...")); + connect(m_editItemsAction, SIGNAL(triggered()), this, SLOT(editItems())); + m_taskActions.append(m_editItemsAction); + + QAction *sep = new QAction(this); + sep->setSeparator(true); + m_taskActions.append(sep); +} + +ComboBoxTaskMenu::~ComboBoxTaskMenu() +{ +} + +QAction *ComboBoxTaskMenu::preferredEditAction() const +{ + return m_editItemsAction; +} + +QList ComboBoxTaskMenu::taskActions() const +{ + return m_taskActions + QDesignerTaskMenu::taskActions(); +} + +void ComboBoxTaskMenu::editItems() +{ + m_formWindow = QDesignerFormWindowInterface::findFormWindow(m_comboBox); + if (m_formWindow.isNull()) + return; + + Q_ASSERT(m_comboBox != 0); + + ListWidgetEditor dlg(m_formWindow, m_comboBox->window()); + ListContents oldItems = dlg.fillContentsFromComboBox(m_comboBox); + if (dlg.exec() == QDialog::Accepted) { + ListContents items = dlg.contents(); + if (items != oldItems) { + ChangeListContentsCommand *cmd = new ChangeListContentsCommand(m_formWindow); + cmd->init(m_comboBox, oldItems, items); + cmd->setText(tr("Change Combobox Contents")); + m_formWindow->commandHistory()->push(cmd); + } + } +} + +ComboBoxTaskMenuFactory::ComboBoxTaskMenuFactory(const QString &iid, QExtensionManager *extensionManager) : + ExtensionFactory(iid, extensionManager) +{ +} + +QComboBox *ComboBoxTaskMenuFactory::checkObject(QObject *qObject) const +{ + QComboBox *combo = qobject_cast(qObject); + if (!combo) + return 0; + if (qobject_cast(combo)) + return 0; + return combo; +} + +void ComboBoxTaskMenu::updateSelection() +{ + if (m_editor) + m_editor->deleteLater(); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/taskmenu/combobox_taskmenu.h b/src/designer/src/components/taskmenu/combobox_taskmenu.h new file mode 100644 index 000000000..c1eee4837 --- /dev/null +++ b/src/designer/src/components/taskmenu/combobox_taskmenu.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef COMBOBOX_TASKMENU_H +#define COMBOBOX_TASKMENU_H + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QLineEdit; +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class ComboBoxTaskMenu: public QDesignerTaskMenu +{ + Q_OBJECT +public: + explicit ComboBoxTaskMenu(QComboBox *button, + QObject *parent = 0); + virtual ~ComboBoxTaskMenu(); + + virtual QAction *preferredEditAction() const; + virtual QList taskActions() const; + +private slots: + void editItems(); + void updateSelection(); + +private: + QComboBox *m_comboBox; + QPointer m_formWindow; + QPointer m_editor; + mutable QList m_taskActions; + QAction *m_editItemsAction; +}; + +class ComboBoxTaskMenuFactory : public ExtensionFactory +{ +public: + explicit ComboBoxTaskMenuFactory(const QString &iid, QExtensionManager *extensionManager); + +private: + virtual QComboBox *checkObject(QObject *qObject) const; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // COMBOBOX_TASKMENU_H diff --git a/src/designer/src/components/taskmenu/containerwidget_taskmenu.cpp b/src/designer/src/components/taskmenu/containerwidget_taskmenu.cpp new file mode 100644 index 000000000..244ea00ff --- /dev/null +++ b/src/designer/src/components/taskmenu/containerwidget_taskmenu.cpp @@ -0,0 +1,348 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "containerwidget_taskmenu.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +ContainerWidgetTaskMenu::ContainerWidgetTaskMenu(QWidget *widget, ContainerType type, QObject *parent) : + QDesignerTaskMenu(widget, parent), + m_type(type), + m_containerWidget(widget), + m_core(formWindow()->core()), + m_pagePromotionTaskMenu(new PromotionTaskMenu(0, PromotionTaskMenu::ModeSingleWidget, this)), + m_pageMenuAction(new QAction(this)), + m_pageMenu(new QMenu), + m_actionDeletePage(new QAction(tr("Delete"), this)) +{ + Q_ASSERT(m_core); + m_taskActions.append(createSeparator()); + + connect(m_actionDeletePage, SIGNAL(triggered()), this, SLOT(removeCurrentPage())); + + QAction *actionInsertPageAfter = new QAction(this); + connect(actionInsertPageAfter, SIGNAL(triggered()), this, SLOT(addPageAfter())); + // Empty Per-Page submenu, deletion and promotion. Updated on demand due to promotion state + switch (m_type) { + case WizardContainer: + case PageContainer: + m_taskActions.append(createSeparator()); // for the browse actions + break; + case MdiContainer: + break; + } + // submenu + m_pageMenuAction->setMenu(m_pageMenu); + m_taskActions.append(m_pageMenuAction); + // Insertion + switch (m_type) { + case WizardContainer: + case PageContainer: { // Before and after in a submenu + QAction *insertMenuAction = new QAction(tr("Insert"), this); + QMenu *insertMenu = new QMenu; + // before + QAction *actionInsertPage = new QAction(tr("Insert Page Before Current Page"), this); + connect(actionInsertPage, SIGNAL(triggered()), this, SLOT(addPage())); + insertMenu->addAction(actionInsertPage); + // after + actionInsertPageAfter->setText(tr("Insert Page After Current Page")); + insertMenu->addAction(actionInsertPageAfter); + + insertMenuAction->setMenu(insertMenu); + m_taskActions.append(insertMenuAction); + } + break; + case MdiContainer: // No concept of order + actionInsertPageAfter->setText(tr("Add Subwindow")); + m_taskActions.append(actionInsertPageAfter); + break; + } +} + +ContainerWidgetTaskMenu::~ContainerWidgetTaskMenu() +{ +} + +QAction *ContainerWidgetTaskMenu::preferredEditAction() const +{ + return 0; +} + +bool ContainerWidgetTaskMenu::canDeletePage() const +{ + switch (pageCount()) { + case 0: + return false; + case 1: + return m_type != PageContainer; // Do not delete last page of page-type container + default: + break; + } + return true; +} + +int ContainerWidgetTaskMenu::pageCount() const +{ + if (const QDesignerContainerExtension *ce = containerExtension()) + return ce->count(); + return 0; +} + +QString ContainerWidgetTaskMenu::pageMenuText(ContainerType ct, int index, int count) +{ + if (ct == MdiContainer) + return tr("Subwindow"); // No concept of order, same text everywhere + if (index < 0) + return tr("Page"); + return tr("Page %1 of %2").arg(index + 1).arg(count); +} + +QList ContainerWidgetTaskMenu::taskActions() const +{ + QList actions = QDesignerTaskMenu::taskActions(); + actions += m_taskActions; + // Update the page submenu, deletion and promotion. Updated on demand due to promotion state. + m_pageMenu->clear(); + m_pageMenu->addAction(m_actionDeletePage); + m_actionDeletePage->setEnabled(canDeletePage()); + const QDesignerContainerExtension *ce = containerExtension(); + const int index = ce->currentIndex(); + m_pageMenuAction->setText(pageMenuText(m_type, index, ce->count())); + if (index != -1) { // Has a page + m_pageMenuAction->setEnabled(true); + m_pagePromotionTaskMenu->setWidget(ce->widget(index)); + m_pagePromotionTaskMenu->addActions(PromotionTaskMenu::LeadingSeparator|PromotionTaskMenu::SuppressGlobalEdit, m_pageMenu); + } else { // No page + m_pageMenuAction->setEnabled(false); + } + + return actions; +} + +QDesignerFormWindowInterface *ContainerWidgetTaskMenu::formWindow() const +{ + return QDesignerFormWindowInterface::findFormWindow(m_containerWidget); +} + +QDesignerContainerExtension *ContainerWidgetTaskMenu::containerExtension() const +{ + QExtensionManager *mgr = m_core->extensionManager(); + return qt_extension(mgr, m_containerWidget); +} + +void ContainerWidgetTaskMenu::removeCurrentPage() +{ + if (QDesignerContainerExtension *c = containerExtension()) { + if (c->currentIndex() == -1) + return; + + QDesignerFormWindowInterface *fw = formWindow(); + DeleteContainerWidgetPageCommand *cmd = new DeleteContainerWidgetPageCommand(fw); + cmd->init(m_containerWidget, m_type); + fw->commandHistory()->push(cmd); + } +} + +void ContainerWidgetTaskMenu::addPage() +{ + if (containerExtension()) { + QDesignerFormWindowInterface *fw = formWindow(); + AddContainerWidgetPageCommand *cmd = new AddContainerWidgetPageCommand(fw); + cmd->init(m_containerWidget, m_type, AddContainerWidgetPageCommand::InsertBefore); + fw->commandHistory()->push(cmd); + } +} + +void ContainerWidgetTaskMenu::addPageAfter() +{ + if (containerExtension()) { + QDesignerFormWindowInterface *fw = formWindow(); + AddContainerWidgetPageCommand *cmd = new AddContainerWidgetPageCommand(fw); + cmd->init(m_containerWidget, m_type, AddContainerWidgetPageCommand::InsertAfter); + fw->commandHistory()->push(cmd); + } +} + +// -------------- WizardContainerWidgetTaskMenu +WizardContainerWidgetTaskMenu::WizardContainerWidgetTaskMenu(QWizard *w, QObject *parent) : + ContainerWidgetTaskMenu(w, WizardContainer, parent), + m_nextAction(new QAction(tr("Next"), this)), + m_previousAction(new QAction(tr("Back"), this)) +{ + connect(m_nextAction, SIGNAL(triggered()), w, SLOT(next())); + connect(m_previousAction, SIGNAL(triggered()), w, SLOT(back())); + QList &l = containerActions(); + l.push_front(createSeparator()); + l.push_front(m_nextAction); + l.push_front(m_previousAction); + l.push_front(createSeparator()); +} + +QList WizardContainerWidgetTaskMenu::taskActions() const +{ + // Enable + const QDesignerContainerExtension *ce = containerExtension(); + const int index = ce->currentIndex(); + m_previousAction->setEnabled(index > 0); + m_nextAction->setEnabled(index >= 0 && index < (ce->count() - 1)); + return ContainerWidgetTaskMenu::taskActions(); +} + +// -------------- MdiContainerWidgetTaskMenu + +MdiContainerWidgetTaskMenu::MdiContainerWidgetTaskMenu(QMdiArea *m, QObject *parent) : + ContainerWidgetTaskMenu(m, MdiContainer, parent) +{ + initializeActions(); + connect(m_nextAction, SIGNAL(triggered()), m, SLOT(activateNextSubWindow())); + connect(m_previousAction, SIGNAL(triggered()), m , SLOT(activatePreviousSubWindow())); + connect(m_tileAction, SIGNAL(triggered()), m, SLOT(tileSubWindows())); + connect(m_cascadeAction, SIGNAL(triggered()), m, SLOT(cascadeSubWindows())); +} + +MdiContainerWidgetTaskMenu::MdiContainerWidgetTaskMenu(QWorkspace *m, QObject *parent) : + ContainerWidgetTaskMenu(m, MdiContainer, parent) +{ + initializeActions(); + connect(m_nextAction, SIGNAL(triggered()), m, SLOT(activateNextWindow())); + connect(m_previousAction, SIGNAL(triggered()), m, SLOT(activatePreviousWindow())); + connect(m_tileAction, SIGNAL(triggered()),m , SLOT(tile())); + connect(m_cascadeAction, SIGNAL(triggered()), m, SLOT(cascade())); +} + +void MdiContainerWidgetTaskMenu::initializeActions() +{ + m_nextAction =new QAction(tr("Next Subwindow"), this); + m_previousAction = new QAction(tr("Previous Subwindow"), this); + m_tileAction = new QAction(tr("Tile"), this); + m_cascadeAction = new QAction(tr("Cascade"), this); + + QList &l = containerActions(); + l.push_front(createSeparator()); + l.push_front(m_tileAction); + l.push_front(m_cascadeAction); + l.push_front(m_previousAction); + l.push_front(m_nextAction); + l.push_front(createSeparator()); +} + +QList MdiContainerWidgetTaskMenu::taskActions() const +{ + const QList rc = ContainerWidgetTaskMenu::taskActions(); + // Enable + const int count = pageCount(); + m_nextAction->setEnabled(count > 1); + m_previousAction->setEnabled(count > 1); + m_tileAction->setEnabled(count); + m_cascadeAction->setEnabled(count); + return rc; +} + +// -------------- ContainerWidgetTaskMenuFactory + +ContainerWidgetTaskMenuFactory::ContainerWidgetTaskMenuFactory(QDesignerFormEditorInterface *core, QExtensionManager *extensionManager) : + QExtensionFactory(extensionManager), + m_core(core) +{ +} + +QObject *ContainerWidgetTaskMenuFactory::createExtension(QObject *object, const QString &iid, QObject *parent) const +{ + if (iid != QLatin1String("QDesignerInternalTaskMenuExtension") || !object->isWidgetType()) + return 0; + + QWidget *widget = qobject_cast(object); + + if (qobject_cast(widget) + || qobject_cast(widget) + || qobject_cast(widget) + || qobject_cast(widget) + || qobject_cast(widget) + || qobject_cast(widget)) { + // Are we using Designer's own container extensions and task menus or did + // someone provide an extra one with an addpage method, for example for a QScrollArea? + if (const WidgetDataBase *wb = qobject_cast(m_core->widgetDataBase())) { + const int idx = wb->indexOfObject(widget); + const WidgetDataBaseItem *item = static_cast(wb->item(idx)); + if (item->addPageMethod().isEmpty()) + return 0; + } + } + + if (qt_extension(extensionManager(), object) == 0) + return 0; + + if (QMdiArea* ma = qobject_cast(widget)) + return new MdiContainerWidgetTaskMenu(ma, parent); + if (QWorkspace *ws = qobject_cast(widget)) + return new MdiContainerWidgetTaskMenu(ws, parent); + if (QWizard *wz = qobject_cast(widget)) + return new WizardContainerWidgetTaskMenu(wz, parent); + return new ContainerWidgetTaskMenu(widget, PageContainer, parent); +} + +} +QT_END_NAMESPACE diff --git a/src/designer/src/components/taskmenu/containerwidget_taskmenu.h b/src/designer/src/components/taskmenu/containerwidget_taskmenu.h new file mode 100644 index 000000000..6c5f1d481 --- /dev/null +++ b/src/designer/src/components/taskmenu/containerwidget_taskmenu.h @@ -0,0 +1,157 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CONTAINERWIDGER_TASKMENU_H +#define CONTAINERWIDGER_TASKMENU_H + +#include +#include + +#include + +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QDesignerFormEditorInterface; +class QDesignerContainerExtension; +class QAction; +class QMdiArea; +class QWorkspace; +class QMenu; +class QWizard; + +namespace qdesigner_internal { + +class PromotionTaskMenu; + +// ContainerWidgetTaskMenu: Task menu for containers with extension + +class ContainerWidgetTaskMenu: public QDesignerTaskMenu +{ + Q_OBJECT +public: + explicit ContainerWidgetTaskMenu(QWidget *widget, ContainerType type, QObject *parent = 0); + virtual ~ContainerWidgetTaskMenu(); + + virtual QAction *preferredEditAction() const; + virtual QList taskActions() const; + +private slots: + void removeCurrentPage(); + void addPage(); + void addPageAfter(); + +protected: + QDesignerContainerExtension *containerExtension() const; + QList &containerActions() { return m_taskActions; } + int pageCount() const; + +private: + QDesignerFormWindowInterface *formWindow() const; + +private: + static QString pageMenuText(ContainerType ct, int index, int count); + bool canDeletePage() const; + + const ContainerType m_type; + QWidget *m_containerWidget; + QDesignerFormEditorInterface *m_core; + PromotionTaskMenu *m_pagePromotionTaskMenu; + QAction *m_pageMenuAction; + QMenu *m_pageMenu; + QList m_taskActions; + QAction *m_actionDeletePage; +}; + +// WizardContainerWidgetTaskMenu: Provide next/back since QWizard +// has modes in which the "Back" button is not visible. + +class WizardContainerWidgetTaskMenu : public ContainerWidgetTaskMenu { + Q_OBJECT +public: + explicit WizardContainerWidgetTaskMenu(QWizard *w, QObject *parent = 0); + + virtual QList taskActions() const; + +private: + QAction *m_nextAction; + QAction *m_previousAction; +}; + + +// MdiContainerWidgetTaskMenu: Provide tile/cascade for MDI containers in addition + +class MdiContainerWidgetTaskMenu : public ContainerWidgetTaskMenu { + Q_OBJECT +public: + explicit MdiContainerWidgetTaskMenu(QMdiArea *m, QObject *parent = 0); + explicit MdiContainerWidgetTaskMenu(QWorkspace *m, QObject *parent = 0); + + virtual QList taskActions() const; +private: + void initializeActions(); + + QAction *m_nextAction; + QAction *m_previousAction; + QAction *m_tileAction; + QAction *m_cascadeAction; +}; + +class ContainerWidgetTaskMenuFactory: public QExtensionFactory +{ + Q_OBJECT +public: + explicit ContainerWidgetTaskMenuFactory(QDesignerFormEditorInterface *core, QExtensionManager *extensionManager = 0); + +protected: + virtual QObject *createExtension(QObject *object, const QString &iid, QObject *parent) const; + +private: + QDesignerFormEditorInterface *m_core; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // CONTAINERWIDGER_TASKMENU_H diff --git a/src/designer/src/components/taskmenu/groupbox_taskmenu.cpp b/src/designer/src/components/taskmenu/groupbox_taskmenu.cpp new file mode 100644 index 000000000..1fae0f8ba --- /dev/null +++ b/src/designer/src/components/taskmenu/groupbox_taskmenu.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "groupbox_taskmenu.h" +#include "inplace_editor.h" + +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// -------- GroupBoxTaskMenuInlineEditor +class GroupBoxTaskMenuInlineEditor : public TaskMenuInlineEditor +{ +public: + GroupBoxTaskMenuInlineEditor(QGroupBox *button, QObject *parent); + +protected: + virtual QRect editRectangle() const; +}; + +GroupBoxTaskMenuInlineEditor::GroupBoxTaskMenuInlineEditor(QGroupBox *w, QObject *parent) : + TaskMenuInlineEditor(w, ValidationSingleLine, QLatin1String("title"), parent) +{ +} + +QRect GroupBoxTaskMenuInlineEditor::editRectangle() const +{ + QWidget *w = widget(); + QStyleOption opt; // ## QStyleOptionGroupBox + opt.init(w); + return QRect(QPoint(), QSize(w->width(),20)); +} + +// --------------- GroupBoxTaskMenu + +GroupBoxTaskMenu::GroupBoxTaskMenu(QGroupBox *groupbox, QObject *parent) + : QDesignerTaskMenu(groupbox, parent), + m_editTitleAction(new QAction(tr("Change title..."), this)) + +{ + TaskMenuInlineEditor *editor = new GroupBoxTaskMenuInlineEditor(groupbox, this); + connect(m_editTitleAction, SIGNAL(triggered()), editor, SLOT(editText())); + m_taskActions.append(m_editTitleAction); + + QAction *sep = new QAction(this); + sep->setSeparator(true); + m_taskActions.append(sep); +} + +QList GroupBoxTaskMenu::taskActions() const +{ + return m_taskActions + QDesignerTaskMenu::taskActions(); +} + +QAction *GroupBoxTaskMenu::preferredEditAction() const +{ + return m_editTitleAction; +} + +} +QT_END_NAMESPACE diff --git a/src/designer/src/components/taskmenu/groupbox_taskmenu.h b/src/designer/src/components/taskmenu/groupbox_taskmenu.h new file mode 100644 index 000000000..d30d8b1b6 --- /dev/null +++ b/src/designer/src/components/taskmenu/groupbox_taskmenu.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef GROUPBOX_TASKMENU_H +#define GROUPBOX_TASKMENU_H + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { +class InPlaceEditor; + +class GroupBoxTaskMenu: public QDesignerTaskMenu +{ + Q_OBJECT +public: + explicit GroupBoxTaskMenu(QGroupBox *groupbox, QObject *parent = 0); + + virtual QAction *preferredEditAction() const; + virtual QList taskActions() const; + +private: + QAction *m_editTitleAction; + QList m_taskActions; +}; + +typedef ExtensionFactory GroupBoxTaskMenuFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // GROUPBOX_TASKMENU_H diff --git a/src/designer/src/components/taskmenu/inplace_editor.cpp b/src/designer/src/components/taskmenu/inplace_editor.cpp new file mode 100644 index 000000000..fd74b25f4 --- /dev/null +++ b/src/designer/src/components/taskmenu/inplace_editor.cpp @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractformwindow.h" +#include "inplace_editor.h" + +#include +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// ----------------- InPlaceEditor + +InPlaceEditor::InPlaceEditor(QWidget *widget, + TextPropertyValidationMode validationMode, + QDesignerFormWindowInterface *fw, + const QString& text, + const QRect& r) : + TextPropertyEditor(widget, EmbeddingInPlace, validationMode), + m_InPlaceWidgetHelper(this, widget, fw) +{ + setAlignment(m_InPlaceWidgetHelper.alignment()); + setObjectName(QLatin1String("__qt__passive_m_editor")); + + setText(text); + selectAll(); + + setGeometry(QRect(widget->mapTo(widget->window(), r.topLeft()), r.size())); + setFocus(); + show(); + + connect(this, SIGNAL(editingFinished()),this, SLOT(close())); +} + + +// -------------- TaskMenuInlineEditor + +TaskMenuInlineEditor::TaskMenuInlineEditor(QWidget *w, TextPropertyValidationMode vm, + const QString &property, QObject *parent) : + QObject(parent), + m_vm(vm), + m_property(property), + m_widget(w), + m_managed(true) +{ +} + +void TaskMenuInlineEditor::editText() +{ + m_formWindow = QDesignerFormWindowInterface::findFormWindow(m_widget); + if (m_formWindow.isNull()) + return; + m_managed = m_formWindow->isManaged(m_widget); + // Close as soon as a different widget is selected + connect(m_formWindow, SIGNAL(selectionChanged()), this, SLOT(updateSelection())); + + // get old value + QDesignerFormEditorInterface *core = m_formWindow->core(); + const QDesignerPropertySheetExtension *sheet = qt_extension(core->extensionManager(), m_widget); + const int index = sheet->indexOf(m_property); + if (index == -1) + return; + m_value = qvariant_cast(sheet->property(index)); + const QString oldValue = m_value.value(); + + m_editor = new InPlaceEditor(m_widget, m_vm, m_formWindow, oldValue, editRectangle()); + connect(m_editor, SIGNAL(textChanged(QString)), this, SLOT(updateText(QString))); +} + +void TaskMenuInlineEditor::updateText(const QString &text) +{ + // In the [rare] event we are invoked on an unmanaged widget, + // do not use the cursor selection + m_value.setValue(text); + if (m_managed) { + m_formWindow->cursor()->setProperty(m_property, QVariant::fromValue(m_value)); + } else { + m_formWindow->cursor()->setWidgetProperty(m_widget, m_property, QVariant::fromValue(m_value)); + } +} + +void TaskMenuInlineEditor::updateSelection() +{ + if (m_editor) + m_editor->deleteLater(); +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/taskmenu/inplace_editor.h b/src/designer/src/components/taskmenu/inplace_editor.h new file mode 100644 index 000000000..573185cb8 --- /dev/null +++ b/src/designer/src/components/taskmenu/inplace_editor.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef INPLACE_EDITOR_H +#define INPLACE_EDITOR_H + +#include +#include + +#include "inplace_widget_helper.h" +#include + +#include + +QT_BEGIN_NAMESPACE + + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class InPlaceEditor: public TextPropertyEditor +{ + Q_OBJECT +public: + InPlaceEditor(QWidget *widget, + TextPropertyValidationMode validationMode, + QDesignerFormWindowInterface *fw, + const QString& text, + const QRect& r); +private: + InPlaceWidgetHelper m_InPlaceWidgetHelper; +}; + +// Base class for inline editor helpers to be embedded into a task menu. +// Inline-edits a property on a multi-selection. +// To use it for a particular widget/property, overwrite the method +// returning the edit area. + +class TaskMenuInlineEditor : public QObject { + TaskMenuInlineEditor(const TaskMenuInlineEditor&); + TaskMenuInlineEditor &operator=(const TaskMenuInlineEditor&); + Q_OBJECT + +public slots: + void editText(); + +private slots: + void updateText(const QString &text); + void updateSelection(); + +protected: + TaskMenuInlineEditor(QWidget *w, TextPropertyValidationMode vm, const QString &property, QObject *parent); + // Overwrite to return the area for the inline editor. + virtual QRect editRectangle() const = 0; + QWidget *widget() const { return m_widget; } + +private: + const TextPropertyValidationMode m_vm; + const QString m_property; + QWidget *m_widget; + QPointer m_formWindow; + QPointer m_editor; + bool m_managed; + qdesigner_internal::PropertySheetStringValue m_value; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // INPLACE_EDITOR_H diff --git a/src/designer/src/components/taskmenu/inplace_widget_helper.cpp b/src/designer/src/components/taskmenu/inplace_widget_helper.cpp new file mode 100644 index 000000000..47554b3a8 --- /dev/null +++ b/src/designer/src/components/taskmenu/inplace_widget_helper.cpp @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractformwindow.h" +#include "inplace_widget_helper.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + InPlaceWidgetHelper::InPlaceWidgetHelper(QWidget *editorWidget, QWidget *parentWidget, QDesignerFormWindowInterface *fw) + : QObject(0), + m_editorWidget(editorWidget), + m_parentWidget(parentWidget), + m_noChildEvent(m_parentWidget->testAttribute(Qt::WA_NoChildEventsForParent)) + { + m_editorWidget->setAttribute(Qt::WA_DeleteOnClose); + m_editorWidget->setParent(m_parentWidget->window()); + m_parentWidget->installEventFilter(this); + m_editorWidget->installEventFilter(this); + connect(m_editorWidget, SIGNAL(destroyed()), fw->mainContainer(), SLOT(setFocus())); + } + + InPlaceWidgetHelper::~InPlaceWidgetHelper() + { + m_parentWidget->setAttribute(Qt::WA_NoChildEventsForParent, m_noChildEvent); + } + + Qt::Alignment InPlaceWidgetHelper::alignment() const { + if (m_parentWidget->metaObject()->indexOfProperty("alignment") != -1) + return Qt::Alignment(m_parentWidget->property("alignment").toInt()); + + if (qobject_cast(m_parentWidget) + || qobject_cast(m_parentWidget) /* tool needs to be more complex */) + return Qt::AlignHCenter; + + return Qt::AlignJustify; + } + + + bool InPlaceWidgetHelper::eventFilter(QObject *object, QEvent *e) + { + if (object == m_parentWidget) { + if (e->type() == QEvent::Resize) { + const QResizeEvent *event = static_cast(e); + const QPoint localPos = m_parentWidget->geometry().topLeft(); + const QPoint globalPos = m_parentWidget->parentWidget() ? m_parentWidget->parentWidget()->mapToGlobal(localPos) : localPos; + const QPoint newPos = (m_editorWidget->parentWidget() ? m_editorWidget->parentWidget()->mapFromGlobal(globalPos) : globalPos) + + m_posOffset; + const QSize newSize = event->size() + m_sizeOffset; + m_editorWidget->setGeometry(QRect(newPos, newSize)); + } + } else if (object == m_editorWidget) { + if (e->type() == QEvent::ShortcutOverride) { + if (static_cast(e)->key() == Qt::Key_Escape) { + e->accept(); + return false; + } + } else if (e->type() == QEvent::KeyPress) { + if (static_cast(e)->key() == Qt::Key_Escape) { + e->accept(); + m_editorWidget->close(); + return true; + } + } else if (e->type() == QEvent::Show) { + const QPoint localPos = m_parentWidget->geometry().topLeft(); + const QPoint globalPos = m_parentWidget->parentWidget() ? m_parentWidget->parentWidget()->mapToGlobal(localPos) : localPos; + const QPoint newPos = m_editorWidget->parentWidget() ? m_editorWidget->parentWidget()->mapFromGlobal(globalPos) : globalPos; + m_posOffset = m_editorWidget->geometry().topLeft() - newPos; + m_sizeOffset = m_editorWidget->size() - m_parentWidget->size(); + } + } + + return QObject::eventFilter(object, e); + } +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/taskmenu/inplace_widget_helper.h b/src/designer/src/components/taskmenu/inplace_widget_helper.h new file mode 100644 index 000000000..663516004 --- /dev/null +++ b/src/designer/src/components/taskmenu/inplace_widget_helper.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef INPLACE_WIDGETHELPER_H +#define INPLACE_WIDGETHELPER_H + + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + + // A helper class to make an editor widget suitable for form inline + // editing. Derive from the editor widget class and make InPlaceWidgetHelper a member. + // + // Sets "destructive close" on the editor widget and + // wires "ESC" to it. + // Installs an event filter on the parent to listen for + // resize events and passes them on to the child. + // You might want to connect editingFinished() to close() of the editor widget. + class InPlaceWidgetHelper: public QObject + { + Q_OBJECT + public: + InPlaceWidgetHelper(QWidget *editorWidget, QWidget *parentWidget, QDesignerFormWindowInterface *fw); + virtual ~InPlaceWidgetHelper(); + + virtual bool eventFilter(QObject *object, QEvent *event); + + // returns a recommended alignment for the editor widget determined from the parent. + Qt::Alignment alignment() const; + private: + QWidget *m_editorWidget; + QWidget *m_parentWidget; + const bool m_noChildEvent; + QPoint m_posOffset; + QSize m_sizeOffset; + }; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // INPLACE_WIDGETHELPER_H diff --git a/src/designer/src/components/taskmenu/itemlisteditor.cpp b/src/designer/src/components/taskmenu/itemlisteditor.cpp new file mode 100644 index 000000000..a04246de5 --- /dev/null +++ b/src/designer/src/components/taskmenu/itemlisteditor.cpp @@ -0,0 +1,478 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "itemlisteditor.h" +#include +#include +#include +#include + +#include + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class ItemPropertyBrowser : public QtTreePropertyBrowser +{ +public: + ItemPropertyBrowser() + { + setResizeMode(Interactive); + //: Sample string to determinate the width for the first column of the list item property browser + const QString widthSampleString = QCoreApplication::translate("ItemPropertyBrowser", "XX Icon Selected off"); + m_width = fontMetrics().width(widthSampleString); + setSplitterPosition(m_width); + m_width += fontMetrics().width(QLatin1String("/this/is/some/random/path")); + } + + virtual QSize sizeHint() const + { + return QSize(m_width, 1); + } + +private: + int m_width; +}; + +////////////////// Item editor /////////////// +AbstractItemEditor::AbstractItemEditor(QDesignerFormWindowInterface *form, QWidget *parent) + : QWidget(parent), + m_iconCache(qobject_cast(form)->iconCache()), + m_updatingBrowser(false) +{ + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + m_propertyManager = new DesignerPropertyManager(form->core(), this); + m_editorFactory = new DesignerEditorFactory(form->core(), this); + m_editorFactory->setSpacing(0); + m_propertyBrowser = new ItemPropertyBrowser; + m_propertyBrowser->setFactoryForManager((QtVariantPropertyManager *)m_propertyManager, + m_editorFactory); + + connect(m_editorFactory, SIGNAL(resetProperty(QtProperty*)), + SLOT(resetProperty(QtProperty*))); + connect(m_propertyManager, SIGNAL(valueChanged(QtProperty*,QVariant,bool)), + SLOT(propertyChanged(QtProperty*))); + connect(iconCache(), SIGNAL(reloaded()), this, SLOT(cacheReloaded())); +} + +AbstractItemEditor::~AbstractItemEditor() +{ + m_propertyBrowser->unsetFactoryForManager(m_propertyManager); +} + +static const char * const itemFlagNames[] = { + QT_TRANSLATE_NOOP("AbstractItemEditor", "Selectable"), + QT_TRANSLATE_NOOP("AbstractItemEditor", "Editable"), + QT_TRANSLATE_NOOP("AbstractItemEditor", "DragEnabled"), + QT_TRANSLATE_NOOP("AbstractItemEditor", "DropEnabled"), + QT_TRANSLATE_NOOP("AbstractItemEditor", "UserCheckable"), + QT_TRANSLATE_NOOP("AbstractItemEditor", "Enabled"), + QT_TRANSLATE_NOOP("AbstractItemEditor", "Tristate"), + 0 +}; + +static const char * const checkStateNames[] = { + QT_TRANSLATE_NOOP("AbstractItemEditor", "Unchecked"), + QT_TRANSLATE_NOOP("AbstractItemEditor", "PartiallyChecked"), + QT_TRANSLATE_NOOP("AbstractItemEditor", "Checked"), + 0 +}; + +static QStringList c2qStringList(const char * const in[]) +{ + QStringList out; + for (int i = 0; in[i]; i++) + out << AbstractItemEditor::tr(in[i]); + return out; +} + +void AbstractItemEditor::setupProperties(PropertyDefinition *propList) +{ + for (int i = 0; propList[i].name; i++) { + int type = propList[i].typeFunc ? propList[i].typeFunc() : propList[i].type; + int role = propList[i].role; + QtVariantProperty *prop = m_propertyManager->addProperty(type, QLatin1String(propList[i].name)); + Q_ASSERT(prop); + if (role == Qt::ToolTipPropertyRole || role == Qt::WhatsThisPropertyRole) + prop->setAttribute(QLatin1String("validationMode"), ValidationRichText); + else if (role == Qt::DisplayPropertyRole) + prop->setAttribute(QLatin1String("validationMode"), ValidationMultiLine); + else if (role == Qt::StatusTipPropertyRole) + prop->setAttribute(QLatin1String("validationMode"), ValidationSingleLine); + else if (role == ItemFlagsShadowRole) + prop->setAttribute(QLatin1String("flagNames"), c2qStringList(itemFlagNames)); + else if (role == Qt::CheckStateRole) + prop->setAttribute(QLatin1String("enumNames"), c2qStringList(checkStateNames)); + prop->setAttribute(QLatin1String("resettable"), true); + m_properties.append(prop); + m_rootProperties.append(prop); + m_propertyToRole.insert(prop, role); + } +} + +void AbstractItemEditor::setupObject(QWidget *object) +{ + m_propertyManager->setObject(object); + QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(object); + FormWindowBase *fwb = qobject_cast(formWindow); + m_editorFactory->setFormWindowBase(fwb); +} + +void AbstractItemEditor::setupEditor(QWidget *object, PropertyDefinition *propList) +{ + setupProperties(propList); + setupObject(object); +} + +void AbstractItemEditor::propertyChanged(QtProperty *property) +{ + if (m_updatingBrowser) + return; + + + BoolBlocker block(m_updatingBrowser); + QtVariantProperty *prop = m_propertyManager->variantProperty(property); + int role; + if ((role = m_propertyToRole.value(prop, -1)) == -1) + // Subproperty + return; + + if ((role == ItemFlagsShadowRole && prop->value().toInt() == (int)QListWidgetItem().flags()) + || (role == Qt::DecorationPropertyRole && !qvariant_cast(prop->value()).mask()) + || (role == Qt::FontRole && !qvariant_cast(prop->value()).resolve())) { + prop->setModified(false); + setItemData(role, QVariant()); + } else { + prop->setModified(true); + setItemData(role, prop->value()); + } + + switch (role) { + case Qt::DecorationPropertyRole: + setItemData(Qt::DecorationRole, QVariant::fromValue(iconCache()->icon(qvariant_cast(prop->value())))); + break; + case Qt::DisplayPropertyRole: + setItemData(Qt::EditRole, QVariant::fromValue(qvariant_cast(prop->value()).value())); + break; + case Qt::ToolTipPropertyRole: + setItemData(Qt::ToolTipRole, QVariant::fromValue(qvariant_cast(prop->value()).value())); + break; + case Qt::StatusTipPropertyRole: + setItemData(Qt::StatusTipRole, QVariant::fromValue(qvariant_cast(prop->value()).value())); + break; + case Qt::WhatsThisPropertyRole: + setItemData(Qt::WhatsThisRole, QVariant::fromValue(qvariant_cast(prop->value()).value())); + break; + default: + break; + } + + prop->setValue(getItemData(role)); +} + +void AbstractItemEditor::resetProperty(QtProperty *property) +{ + if (m_propertyManager->resetFontSubProperty(property)) + return; + + if (m_propertyManager->resetIconSubProperty(property)) + return; + + BoolBlocker block(m_updatingBrowser); + + QtVariantProperty *prop = m_propertyManager->variantProperty(property); + int role = m_propertyToRole.value(prop); + if (role == ItemFlagsShadowRole) + prop->setValue(QVariant::fromValue((int)QListWidgetItem().flags())); + else + prop->setValue(QVariant(prop->valueType(), (void *)0)); + prop->setModified(false); + + setItemData(role, QVariant()); + if (role == Qt::DecorationPropertyRole) + setItemData(Qt::DecorationRole, QVariant::fromValue(QIcon())); + if (role == Qt::DisplayPropertyRole) + setItemData(Qt::EditRole, QVariant::fromValue(QString())); + if (role == Qt::ToolTipPropertyRole) + setItemData(Qt::ToolTipRole, QVariant::fromValue(QString())); + if (role == Qt::StatusTipPropertyRole) + setItemData(Qt::StatusTipRole, QVariant::fromValue(QString())); + if (role == Qt::WhatsThisPropertyRole) + setItemData(Qt::WhatsThisRole, QVariant::fromValue(QString())); +} + +void AbstractItemEditor::cacheReloaded() +{ + BoolBlocker block(m_updatingBrowser); + m_propertyManager->reloadResourceProperties(); +} + +void AbstractItemEditor::updateBrowser() +{ + BoolBlocker block(m_updatingBrowser); + foreach (QtVariantProperty *prop, m_properties) { + int role = m_propertyToRole.value(prop); + QVariant val = getItemData(role); + if (!val.isValid()) { + if (role == ItemFlagsShadowRole) + val = QVariant::fromValue((int)QListWidgetItem().flags()); + else + val = QVariant((int)prop->value().userType(), (void *)0); + prop->setModified(false); + } else { + prop->setModified(true); + } + prop->setValue(val); + } + + if (m_propertyBrowser->topLevelItems().isEmpty()) + foreach (QtVariantProperty *prop, m_rootProperties) + m_propertyBrowser->addProperty(prop); +} + +void AbstractItemEditor::injectPropertyBrowser(QWidget *parent, QWidget *widget) +{ + // It is impossible to design a splitter with just one widget, so we do it by hand. + m_propertySplitter = new QSplitter; + m_propertySplitter->addWidget(widget); + m_propertySplitter->addWidget(m_propertyBrowser); + m_propertySplitter->setStretchFactor(0, 1); + m_propertySplitter->setStretchFactor(1, 0); + parent->layout()->addWidget(m_propertySplitter); +} + +////////////////// List editor /////////////// +ItemListEditor::ItemListEditor(QDesignerFormWindowInterface *form, QWidget *parent) + : AbstractItemEditor(form, parent), + m_updating(false) +{ + ui.setupUi(this); + + injectPropertyBrowser(this, ui.widget); + connect(ui.showPropertiesButton, SIGNAL(clicked()), + this, SLOT(togglePropertyBrowser())); + setPropertyBrowserVisible(false); + + QIcon upIcon = createIconSet(QString::fromUtf8("up.png")); + QIcon downIcon = createIconSet(QString::fromUtf8("down.png")); + QIcon minusIcon = createIconSet(QString::fromUtf8("minus.png")); + QIcon plusIcon = createIconSet(QString::fromUtf8("plus.png")); + ui.moveListItemUpButton->setIcon(upIcon); + ui.moveListItemDownButton->setIcon(downIcon); + ui.newListItemButton->setIcon(plusIcon); + ui.deleteListItemButton->setIcon(minusIcon); + + connect(iconCache(), SIGNAL(reloaded()), this, SLOT(cacheReloaded())); +} + +void ItemListEditor::setupEditor(QWidget *object, PropertyDefinition *propList) +{ + AbstractItemEditor::setupEditor(object, propList); + + if (ui.listWidget->count() > 0) + ui.listWidget->setCurrentRow(0); + else + updateEditor(); +} + +void ItemListEditor::setCurrentIndex(int idx) +{ + m_updating = true; + ui.listWidget->setCurrentRow(idx); + m_updating = false; +} + +void ItemListEditor::on_newListItemButton_clicked() +{ + int row = ui.listWidget->currentRow() + 1; + + QListWidgetItem *item = new QListWidgetItem(m_newItemText); + item->setData(Qt::DisplayPropertyRole, QVariant::fromValue(PropertySheetStringValue(m_newItemText))); + item->setFlags(item->flags() | Qt::ItemIsEditable); + if (row < ui.listWidget->count()) + ui.listWidget->insertItem(row, item); + else + ui.listWidget->addItem(item); + emit itemInserted(row); + + ui.listWidget->setCurrentItem(item); + ui.listWidget->editItem(item); +} + +void ItemListEditor::on_deleteListItemButton_clicked() +{ + int row = ui.listWidget->currentRow(); + + if (row != -1) { + delete ui.listWidget->takeItem(row); + emit itemDeleted(row); + } + + if (row == ui.listWidget->count()) + row--; + if (row < 0) + updateEditor(); + else + ui.listWidget->setCurrentRow(row); +} + +void ItemListEditor::on_moveListItemUpButton_clicked() +{ + int row = ui.listWidget->currentRow(); + if (row <= 0) + return; // nothing to do + + ui.listWidget->insertItem(row - 1, ui.listWidget->takeItem(row)); + ui.listWidget->setCurrentRow(row - 1); + emit itemMovedUp(row); +} + +void ItemListEditor::on_moveListItemDownButton_clicked() +{ + int row = ui.listWidget->currentRow(); + if (row == -1 || row == ui.listWidget->count() - 1) + return; // nothing to do + + ui.listWidget->insertItem(row + 1, ui.listWidget->takeItem(row)); + ui.listWidget->setCurrentRow(row + 1); + emit itemMovedDown(row); +} + +void ItemListEditor::on_listWidget_currentRowChanged() +{ + updateEditor(); + if (!m_updating) + emit indexChanged(ui.listWidget->currentRow()); +} + +void ItemListEditor::on_listWidget_itemChanged(QListWidgetItem *item) +{ + if (m_updatingBrowser) + return; + + PropertySheetStringValue val = qvariant_cast(item->data(Qt::DisplayPropertyRole)); + val.setValue(item->text()); + BoolBlocker block(m_updatingBrowser); + item->setData(Qt::DisplayPropertyRole, QVariant::fromValue(val)); + + // The checkState could change, too, but if this signal is connected, + // checkState is not in the list anyway, as we are editing a header item. + emit itemChanged(ui.listWidget->currentRow(), Qt::DisplayPropertyRole, + QVariant::fromValue(val)); + updateBrowser(); +} + +void ItemListEditor::togglePropertyBrowser() +{ + setPropertyBrowserVisible(!m_propertyBrowser->isVisible()); +} + +void ItemListEditor::setPropertyBrowserVisible(bool v) +{ + ui.showPropertiesButton->setText(v ? tr("Properties &>>") : tr("Properties &<<")); + m_propertyBrowser->setVisible(v); +} + +void ItemListEditor::setItemData(int role, const QVariant &v) +{ + QListWidgetItem *item = ui.listWidget->currentItem(); + bool reLayout = false; + if ((role == Qt::EditRole && (v.toString().count(QLatin1Char('\n')) != item->data(role).toString().count(QLatin1Char('\n')))) + || role == Qt::FontRole) + reLayout = true; + QVariant newValue = v; + if (role == Qt::FontRole && newValue.type() == QVariant::Font) { + QFont oldFont = ui.listWidget->font(); + QFont newFont = qvariant_cast(newValue).resolve(oldFont); + newValue = QVariant::fromValue(newFont); + item->setData(role, QVariant()); // force the right font with the current resolve mask is set (item view bug) + } + item->setData(role, newValue); + if (reLayout) + ui.listWidget->doItemsLayout(); + emit itemChanged(ui.listWidget->currentRow(), role, newValue); +} + +QVariant ItemListEditor::getItemData(int role) const +{ + return ui.listWidget->currentItem()->data(role); +} + +void ItemListEditor::cacheReloaded() +{ + reloadIconResources(iconCache(), ui.listWidget); +} + +void ItemListEditor::updateEditor() +{ + bool currentItemEnabled = false; + + bool moveRowUpEnabled = false; + bool moveRowDownEnabled = false; + + QListWidgetItem *item = ui.listWidget->currentItem(); + if (item) { + currentItemEnabled = true; + int currentRow = ui.listWidget->currentRow(); + if (currentRow > 0) + moveRowUpEnabled = true; + if (currentRow < ui.listWidget->count() - 1) + moveRowDownEnabled = true; + } + + ui.moveListItemUpButton->setEnabled(moveRowUpEnabled); + ui.moveListItemDownButton->setEnabled(moveRowDownEnabled); + ui.deleteListItemButton->setEnabled(currentItemEnabled); + + if (item) + updateBrowser(); + else + m_propertyBrowser->clear(); +} +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/components/taskmenu/itemlisteditor.h b/src/designer/src/components/taskmenu/itemlisteditor.h new file mode 100644 index 000000000..ffacad293 --- /dev/null +++ b/src/designer/src/components/taskmenu/itemlisteditor.h @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ITEMLISTEDITOR_H +#define ITEMLISTEDITOR_H + +#include "ui_itemlisteditor.h" + +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QtProperty; +class QtVariantProperty; +class QtTreePropertyBrowser; +class QSplitter; +class QVBoxLayout; + +namespace qdesigner_internal { + +class DesignerIconCache; +class DesignerPropertyManager; +class DesignerEditorFactory; + +// Utility class that ensures a bool is true while in scope. +// Courtesy of QBoolBlocker in qobject_p.h +class BoolBlocker +{ +public: + inline BoolBlocker(bool &b):block(b), reset(b){block = true;} + inline ~BoolBlocker(){block = reset; } +private: + bool █ + bool reset; +}; + +class AbstractItemEditor: public QWidget +{ + Q_OBJECT + +public: + explicit AbstractItemEditor(QDesignerFormWindowInterface *form, QWidget *parent); + ~AbstractItemEditor(); + + DesignerIconCache *iconCache() const { return m_iconCache; } + + struct PropertyDefinition { + int role; + int type; + int (*typeFunc)(); + const char *name; + }; + +private slots: + void propertyChanged(QtProperty *property); + void resetProperty(QtProperty *property); + void cacheReloaded(); + +protected: + void setupProperties(PropertyDefinition *propDefs); + void setupObject(QWidget *object); + void setupEditor(QWidget *object, PropertyDefinition *propDefs); + void injectPropertyBrowser(QWidget *parent, QWidget *widget); + void updateBrowser(); + virtual void setItemData(int role, const QVariant &v) = 0; + virtual QVariant getItemData(int role) const = 0; + + DesignerIconCache *m_iconCache; + DesignerPropertyManager *m_propertyManager; + DesignerEditorFactory *m_editorFactory; + QSplitter *m_propertySplitter; + QtTreePropertyBrowser *m_propertyBrowser; + QList m_properties; + QList m_rootProperties; + QHash m_propertyToRole; + bool m_updatingBrowser; +}; + +class ItemListEditor: public AbstractItemEditor +{ + Q_OBJECT + +public: + explicit ItemListEditor(QDesignerFormWindowInterface *form, QWidget *parent); + + void setupEditor(QWidget *object, PropertyDefinition *propDefs); + QListWidget *listWidget() const { return ui.listWidget; } + void setNewItemText(const QString &tpl) { m_newItemText = tpl; } + QString newItemText() const { return m_newItemText; } + void setCurrentIndex(int idx); + +signals: + void indexChanged(int idx); + void itemChanged(int idx, int role, const QVariant &v); + void itemInserted(int idx); + void itemDeleted(int idx); + void itemMovedUp(int idx); + void itemMovedDown(int idx); + +private slots: + void on_newListItemButton_clicked(); + void on_deleteListItemButton_clicked(); + void on_moveListItemUpButton_clicked(); + void on_moveListItemDownButton_clicked(); + void on_listWidget_currentRowChanged(); + void on_listWidget_itemChanged(QListWidgetItem * item); + void togglePropertyBrowser(); + void cacheReloaded(); + +protected: + virtual void setItemData(int role, const QVariant &v); + virtual QVariant getItemData(int role) const; + +private: + void setPropertyBrowserVisible(bool v); + void updateEditor(); + Ui::ItemListEditor ui; + bool m_updating; + QString m_newItemText; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // ITEMLISTEDITOR_H diff --git a/src/designer/src/components/taskmenu/itemlisteditor.ui b/src/designer/src/components/taskmenu/itemlisteditor.ui new file mode 100644 index 000000000..a13703f90 --- /dev/null +++ b/src/designer/src/components/taskmenu/itemlisteditor.ui @@ -0,0 +1,156 @@ + + ********************************************************************* +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +********************************************************************* + qdesigner_internal::ItemListEditor + + + + 0 + 0 + 550 + 360 + + + + + + + + + + + 0 + + + + + true + + + Items List + + + + + + + + + New Item + + + &New + + + + + + + Delete Item + + + &Delete + + + + + + + Qt::Horizontal + + + + 16 + 10 + + + + + + + + Move Item Up + + + U + + + + + + + Move Item Down + + + D + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Properties &>> + + + + + + + + + + + + + diff --git a/src/designer/src/components/taskmenu/label_taskmenu.cpp b/src/designer/src/components/taskmenu/label_taskmenu.cpp new file mode 100644 index 000000000..5f0acb209 --- /dev/null +++ b/src/designer/src/components/taskmenu/label_taskmenu.cpp @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "label_taskmenu.h" +#include "inplace_editor.h" + +#include + +#include +#include +#include +#include + +static const char *textPropertyC = "text"; + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// -------- LabelTaskMenuInlineEditor +class LabelTaskMenuInlineEditor : public TaskMenuInlineEditor +{ +public: + LabelTaskMenuInlineEditor(QLabel *button, QObject *parent); + +protected: + virtual QRect editRectangle() const; +}; + +LabelTaskMenuInlineEditor::LabelTaskMenuInlineEditor(QLabel *w, QObject *parent) : + TaskMenuInlineEditor(w, ValidationRichText, QLatin1String(textPropertyC), parent) +{ +} + +QRect LabelTaskMenuInlineEditor::editRectangle() const +{ + QStyleOptionButton opt; + opt.init(widget()); + return opt.rect; +} + +// --------------- LabelTaskMenu + +LabelTaskMenu::LabelTaskMenu(QLabel *label, QObject *parent) + : QDesignerTaskMenu(label, parent), + m_label(label), + m_editRichTextAction(new QAction(tr("Change rich text..."), this)), + m_editPlainTextAction(new QAction(tr("Change plain text..."), this)) +{ + LabelTaskMenuInlineEditor *editor = new LabelTaskMenuInlineEditor(label, this); + connect(m_editPlainTextAction, SIGNAL(triggered()), editor, SLOT(editText())); + m_taskActions.append(m_editPlainTextAction); + + connect(m_editRichTextAction, SIGNAL(triggered()), this, SLOT(editRichText())); + m_taskActions.append(m_editRichTextAction); + + QAction *sep = new QAction(this); + sep->setSeparator(true); + m_taskActions.append(sep); +} + +QAction *LabelTaskMenu::preferredEditAction() const +{ + if (m_label->textFormat () == Qt::PlainText) return m_editPlainTextAction; + return Qt::mightBeRichText(m_label->text()) ? m_editRichTextAction : m_editPlainTextAction; +} + +QList LabelTaskMenu::taskActions() const +{ + return m_taskActions + QDesignerTaskMenu::taskActions(); +} + +void LabelTaskMenu::editRichText() +{ + changeTextProperty(QLatin1String(textPropertyC), QString(), MultiSelectionMode, m_label->textFormat()); +} + +} +QT_END_NAMESPACE diff --git a/src/designer/src/components/taskmenu/label_taskmenu.h b/src/designer/src/components/taskmenu/label_taskmenu.h new file mode 100644 index 000000000..7f3549128 --- /dev/null +++ b/src/designer/src/components/taskmenu/label_taskmenu.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LABEL_TASKMENU_H +#define LABEL_TASKMENU_H + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class LabelTaskMenu: public QDesignerTaskMenu +{ + Q_OBJECT +public: + explicit LabelTaskMenu(QLabel *button, QObject *parent = 0); + + virtual QAction *preferredEditAction() const; + virtual QList taskActions() const; + +private slots: + void editRichText(); + +private: + QLabel *m_label; + QList m_taskActions; + QAction *m_editRichTextAction; + QAction *m_editPlainTextAction; +}; + +typedef ExtensionFactory LabelTaskMenuFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // LABEL_TASKMENU_H diff --git a/src/designer/src/components/taskmenu/layouttaskmenu.cpp b/src/designer/src/components/taskmenu/layouttaskmenu.cpp new file mode 100644 index 000000000..10d5d7c54 --- /dev/null +++ b/src/designer/src/components/taskmenu/layouttaskmenu.cpp @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "layouttaskmenu.h" +#include +#include + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +// ------------ LayoutWidgetTaskMenu +LayoutWidgetTaskMenu::LayoutWidgetTaskMenu(QLayoutWidget *lw, QObject *parent) : + QObject(parent), + m_widget(lw), + m_morphMenu(new qdesigner_internal::MorphMenu(this)), + m_formLayoutMenu(new qdesigner_internal::FormLayoutMenu(this)) +{ +} + +QAction *LayoutWidgetTaskMenu::preferredEditAction() const +{ + return m_formLayoutMenu->preferredEditAction(m_widget, m_widget->formWindow()); +} + +QList LayoutWidgetTaskMenu::taskActions() const +{ + QList rc; + QDesignerFormWindowInterface *fw = m_widget->formWindow(); + m_morphMenu->populate(m_widget, fw, rc); + m_formLayoutMenu->populate(m_widget, fw, rc); + return rc; +} + +// ------------- SpacerTaskMenu +SpacerTaskMenu::SpacerTaskMenu(Spacer *, QObject *parent) : + QObject(parent) +{ +} + +QAction *SpacerTaskMenu::preferredEditAction() const +{ + return 0; +} + +QList SpacerTaskMenu::taskActions() const +{ + return QList(); +} + +QT_END_NAMESPACE + diff --git a/src/designer/src/components/taskmenu/layouttaskmenu.h b/src/designer/src/components/taskmenu/layouttaskmenu.h new file mode 100644 index 000000000..ca52596ee --- /dev/null +++ b/src/designer/src/components/taskmenu/layouttaskmenu.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LAYOUTTASKMENU_H +#define LAYOUTTASKMENU_H + +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + class FormLayoutMenu; + class MorphMenu; +} + +// Morph menu for QLayoutWidget. +class LayoutWidgetTaskMenu : public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + explicit LayoutWidgetTaskMenu(QLayoutWidget *w, QObject *parent = 0); + + virtual QAction *preferredEditAction() const; + virtual QList taskActions() const; + +private: + QLayoutWidget *m_widget; + qdesigner_internal::MorphMenu *m_morphMenu; + qdesigner_internal::FormLayoutMenu *m_formLayoutMenu; +}; + +// Empty task menu for spacers. +class SpacerTaskMenu : public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + explicit SpacerTaskMenu(Spacer *bar, QObject *parent = 0); + + virtual QAction *preferredEditAction() const; + virtual QList taskActions() const; + +}; + +typedef qdesigner_internal::ExtensionFactory LayoutWidgetTaskMenuFactory; +typedef qdesigner_internal::ExtensionFactory SpacerTaskMenuFactory; + +QT_END_NAMESPACE + +#endif // LAYOUTTASKMENU_H diff --git a/src/designer/src/components/taskmenu/lineedit_taskmenu.cpp b/src/designer/src/components/taskmenu/lineedit_taskmenu.cpp new file mode 100644 index 000000000..c00c493b1 --- /dev/null +++ b/src/designer/src/components/taskmenu/lineedit_taskmenu.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "lineedit_taskmenu.h" +#include "inplace_editor.h" + +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// -------- LineEditTaskMenuInlineEditor +class LineEditTaskMenuInlineEditor : public TaskMenuInlineEditor +{ +public: + LineEditTaskMenuInlineEditor(QLineEdit *button, QObject *parent); + +protected: + virtual QRect editRectangle() const; +}; + +LineEditTaskMenuInlineEditor::LineEditTaskMenuInlineEditor(QLineEdit *w, QObject *parent) : + TaskMenuInlineEditor(w, ValidationSingleLine, QLatin1String("text"), parent) +{ +} + +QRect LineEditTaskMenuInlineEditor::editRectangle() const +{ + QStyleOption opt; + opt.init(widget()); + return opt.rect; +} + +// --------------- LineEditTaskMenu +LineEditTaskMenu::LineEditTaskMenu(QLineEdit *lineEdit, QObject *parent) : + QDesignerTaskMenu(lineEdit, parent), + m_editTextAction(new QAction(tr("Change text..."), this)) +{ + TaskMenuInlineEditor *editor = new LineEditTaskMenuInlineEditor(lineEdit, this); + connect(m_editTextAction, SIGNAL(triggered()), editor, SLOT(editText())); + m_taskActions.append(m_editTextAction); + + QAction *sep = new QAction(this); + sep->setSeparator(true); + m_taskActions.append(sep); +} + +QAction *LineEditTaskMenu::preferredEditAction() const +{ + return m_editTextAction; +} + +QList LineEditTaskMenu::taskActions() const +{ + return m_taskActions + QDesignerTaskMenu::taskActions(); +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/taskmenu/lineedit_taskmenu.h b/src/designer/src/components/taskmenu/lineedit_taskmenu.h new file mode 100644 index 000000000..239590bb8 --- /dev/null +++ b/src/designer/src/components/taskmenu/lineedit_taskmenu.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LINEEDIT_TASKMENU_H +#define LINEEDIT_TASKMENU_H + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class LineEditTaskMenu: public QDesignerTaskMenu +{ + Q_OBJECT +public: + explicit LineEditTaskMenu(QLineEdit *button, QObject *parent = 0); + + virtual QAction *preferredEditAction() const; + virtual QList taskActions() const; + +private: + QList m_taskActions; + QAction *m_editTextAction; +}; + +typedef ExtensionFactory LineEditTaskMenuFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // LINEEDIT_TASKMENU_H diff --git a/src/designer/src/components/taskmenu/listwidget_taskmenu.cpp b/src/designer/src/components/taskmenu/listwidget_taskmenu.cpp new file mode 100644 index 000000000..bd8f6b9f8 --- /dev/null +++ b/src/designer/src/components/taskmenu/listwidget_taskmenu.cpp @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "listwidget_taskmenu.h" +#include "listwidgeteditor.h" +#include "qdesigner_utils_p.h" +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +ListWidgetTaskMenu::ListWidgetTaskMenu(QListWidget *button, QObject *parent) + : QDesignerTaskMenu(button, parent), + m_listWidget(button) +{ + m_editItemsAction = new QAction(this); + m_editItemsAction->setText(tr("Edit Items...")); + connect(m_editItemsAction, SIGNAL(triggered()), this, SLOT(editItems())); + m_taskActions.append(m_editItemsAction); + + QAction *sep = new QAction(this); + sep->setSeparator(true); + m_taskActions.append(sep); +} + +ListWidgetTaskMenu::~ListWidgetTaskMenu() +{ +} + +QAction *ListWidgetTaskMenu::preferredEditAction() const +{ + return m_editItemsAction; +} + +QList ListWidgetTaskMenu::taskActions() const +{ + return m_taskActions + QDesignerTaskMenu::taskActions(); +} + +void ListWidgetTaskMenu::editItems() +{ + m_formWindow = QDesignerFormWindowInterface::findFormWindow(m_listWidget); + if (m_formWindow.isNull()) + return; + + Q_ASSERT(m_listWidget != 0); + + ListWidgetEditor dlg(m_formWindow, m_listWidget->window()); + ListContents oldItems = dlg.fillContentsFromListWidget(m_listWidget); + if (dlg.exec() == QDialog::Accepted) { + ListContents items = dlg.contents(); + if (items != oldItems) { + ChangeListContentsCommand *cmd = new ChangeListContentsCommand(m_formWindow); + cmd->init(m_listWidget, oldItems, items); + cmd->setText(tr("Change List Contents")); + m_formWindow->commandHistory()->push(cmd); + } + } +} + +void ListWidgetTaskMenu::updateSelection() +{ + if (m_editor) + m_editor->deleteLater(); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/taskmenu/listwidget_taskmenu.h b/src/designer/src/components/taskmenu/listwidget_taskmenu.h new file mode 100644 index 000000000..e7e527a38 --- /dev/null +++ b/src/designer/src/components/taskmenu/listwidget_taskmenu.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LISTWIDGET_TASKMENU_H +#define LISTWIDGET_TASKMENU_H + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QLineEdit; +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class ListWidgetTaskMenu: public QDesignerTaskMenu +{ + Q_OBJECT +public: + explicit ListWidgetTaskMenu(QListWidget *button, QObject *parent = 0); + virtual ~ListWidgetTaskMenu(); + + virtual QAction *preferredEditAction() const; + virtual QList taskActions() const; + +private slots: + void editItems(); + void updateSelection(); + +private: + QListWidget *m_listWidget; + QPointer m_formWindow; + QPointer m_editor; + mutable QList m_taskActions; + QAction *m_editItemsAction; +}; + +typedef ExtensionFactory ListWidgetTaskMenuFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // LISTWIDGET_TASKMENU_H diff --git a/src/designer/src/components/taskmenu/listwidgeteditor.cpp b/src/designer/src/components/taskmenu/listwidgeteditor.cpp new file mode 100644 index 000000000..7c81ea47e --- /dev/null +++ b/src/designer/src/components/taskmenu/listwidgeteditor.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "listwidgeteditor.h" +#include +#include + +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +ListWidgetEditor::ListWidgetEditor(QDesignerFormWindowInterface *form, + QWidget *parent) + : QDialog(parent) +{ + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + QDialogButtonBox *buttonBox = new QDialogButtonBox; + buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok); + connect(buttonBox, SIGNAL(accepted()), SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), SLOT(reject())); + + m_itemsEditor = new ItemListEditor(form, 0); + m_itemsEditor->layout()->setMargin(0); + m_itemsEditor->setNewItemText(tr("New Item")); + + QFrame *sep = new QFrame; + sep->setFrameStyle(QFrame::HLine | QFrame::Sunken); + + QBoxLayout *box = new QVBoxLayout(this); + box->addWidget(m_itemsEditor); + box->addWidget(sep); + box->addWidget(buttonBox); + + // Numbers copied from itemlisteditor.ui + // (Automatic resizing doesn't work because ui has parent). + resize(550, 360); +} + +static AbstractItemEditor::PropertyDefinition listBoxPropList[] = { + { Qt::DisplayPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "text" }, + { Qt::DecorationPropertyRole, 0, DesignerPropertyManager::designerIconTypeId, "icon" }, + { Qt::ToolTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "toolTip" }, + { Qt::StatusTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "statusTip" }, + { Qt::WhatsThisPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "whatsThis" }, + { Qt::FontRole, QVariant::Font, 0, "font" }, + { Qt::TextAlignmentRole, 0, DesignerPropertyManager::designerAlignmentTypeId, "textAlignment" }, + { Qt::BackgroundRole, QVariant::Brush, 0, "background" }, + { Qt::ForegroundRole, QVariant::Brush, 0, "foreground" }, + { ItemFlagsShadowRole, 0, QtVariantPropertyManager::flagTypeId, "flags" }, + { Qt::CheckStateRole, 0, QtVariantPropertyManager::enumTypeId, "checkState" }, + { 0, 0, 0, 0 } +}; + +ListContents ListWidgetEditor::fillContentsFromListWidget(QListWidget *listWidget) +{ + setWindowTitle(tr("Edit List Widget")); + + ListContents retVal; + retVal.createFromListWidget(listWidget, false); + retVal.applyToListWidget(m_itemsEditor->listWidget(), m_itemsEditor->iconCache(), true); + + m_itemsEditor->setupEditor(listWidget, listBoxPropList); + + return retVal; +} + +static AbstractItemEditor::PropertyDefinition comboBoxPropList[] = { + { Qt::DisplayPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "text" }, + { Qt::DecorationPropertyRole, 0, DesignerPropertyManager::designerIconTypeId, "icon" }, + { 0, 0, 0, 0 } +}; + +ListContents ListWidgetEditor::fillContentsFromComboBox(QComboBox *comboBox) +{ + setWindowTitle(tr("Edit Combobox")); + + ListContents retVal; + retVal.createFromComboBox(comboBox); + retVal.applyToListWidget(m_itemsEditor->listWidget(), m_itemsEditor->iconCache(), true); + + m_itemsEditor->setupEditor(comboBox, comboBoxPropList); + + return retVal; +} + +ListContents ListWidgetEditor::contents() const +{ + ListContents retVal; + retVal.createFromListWidget(m_itemsEditor->listWidget(), true); + return retVal; +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/taskmenu/listwidgeteditor.h b/src/designer/src/components/taskmenu/listwidgeteditor.h new file mode 100644 index 000000000..12d0591f2 --- /dev/null +++ b/src/designer/src/components/taskmenu/listwidgeteditor.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LISTWIDGETEDITOR_H +#define LISTWIDGETEDITOR_H + +#include "itemlisteditor.h" +#include + +#include + +QT_BEGIN_NAMESPACE + +class QListWidget; +class QComboBox; +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class ListWidgetEditor: public QDialog +{ + Q_OBJECT + +public: + ListWidgetEditor(QDesignerFormWindowInterface *form, + QWidget *parent); + + ListContents fillContentsFromListWidget(QListWidget *listWidget); + ListContents fillContentsFromComboBox(QComboBox *comboBox); + ListContents contents() const; + +private: + ItemListEditor *m_itemsEditor; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // LISTWIDGETEDITOR_H diff --git a/src/designer/src/components/taskmenu/menutaskmenu.cpp b/src/designer/src/components/taskmenu/menutaskmenu.cpp new file mode 100644 index 000000000..cbcecb122 --- /dev/null +++ b/src/designer/src/components/taskmenu/menutaskmenu.cpp @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "menutaskmenu.h" + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + // ------------ MenuTaskMenu + MenuTaskMenu::MenuTaskMenu(QDesignerMenu *menu, QObject *parent) : + QObject(parent), + m_menu(menu), + m_removeAction(new QAction(tr("Remove"), this)), + m_promotionTaskMenu(new PromotionTaskMenu(menu, PromotionTaskMenu::ModeSingleWidget, this)) + { + connect(m_removeAction, SIGNAL(triggered()), this, SLOT(removeMenu())); + } + + QAction *MenuTaskMenu::preferredEditAction() const + { + return 0; + } + + QList MenuTaskMenu::taskActions() const + { + QList rc; + rc.push_back(m_removeAction); + m_promotionTaskMenu->addActions(PromotionTaskMenu::LeadingSeparator, rc); + return rc; + } + + void MenuTaskMenu::removeMenu() + { + // Are we on a menu bar or on a menu? + QWidget *pw = m_menu->parentWidget(); + if (QDesignerMenuBar *mb = qobject_cast(pw)) { + mb->deleteMenuAction(m_menu->menuAction()); + return; + } + if (QDesignerMenu *m = qobject_cast(pw)) { + m->deleteAction(m_menu->menuAction()); + } + } + + // ------------- MenuBarTaskMenu + MenuBarTaskMenu::MenuBarTaskMenu(QDesignerMenuBar *bar, QObject *parent) : + QObject(parent), + m_bar(bar) + { + } + + QAction *MenuBarTaskMenu::preferredEditAction() const + { + return 0; + } + + QList MenuBarTaskMenu::taskActions() const + { + return m_bar->contextMenuActions(); + } +} + +QT_END_NAMESPACE + diff --git a/src/designer/src/components/taskmenu/menutaskmenu.h b/src/designer/src/components/taskmenu/menutaskmenu.h new file mode 100644 index 000000000..35cb061b4 --- /dev/null +++ b/src/designer/src/components/taskmenu/menutaskmenu.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MENUTASKMENU_H +#define MENUTASKMENU_H + +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + + class PromotionTaskMenu; + +// The QMenu task menu provides promotion and a remove option. The actual +// menu context options are not forwarded since they make only sense +// when a menu is being edited/visible. + +class MenuTaskMenu : public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + explicit MenuTaskMenu(QDesignerMenu *menu, QObject *parent = 0); + + virtual QAction *preferredEditAction() const; + virtual QList taskActions() const; + +private slots: + void removeMenu(); + +private: + QDesignerMenu *m_menu; + QAction *m_removeAction; + PromotionTaskMenu *m_promotionTaskMenu; +}; + +// The QMenuBar task menu forwards the actions of QDesignerMenuBar, +// making them available in the object inspector. + +class MenuBarTaskMenu : public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + explicit MenuBarTaskMenu(QDesignerMenuBar *bar, QObject *parent = 0); + + virtual QAction *preferredEditAction() const; + virtual QList taskActions() const; + +private: + QDesignerMenuBar *m_bar; +}; + +typedef ExtensionFactory MenuTaskMenuFactory; +typedef ExtensionFactory MenuBarTaskMenuFactory; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // MENUTASKMENU_H diff --git a/src/designer/src/components/taskmenu/tablewidget_taskmenu.cpp b/src/designer/src/components/taskmenu/tablewidget_taskmenu.cpp new file mode 100644 index 000000000..e98714f62 --- /dev/null +++ b/src/designer/src/components/taskmenu/tablewidget_taskmenu.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "tablewidget_taskmenu.h" +#include "tablewidgeteditor.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +TableWidgetTaskMenu::TableWidgetTaskMenu(QTableWidget *button, QObject *parent) + : QDesignerTaskMenu(button, parent), + m_tableWidget(button), + m_editItemsAction(new QAction(tr("Edit Items..."), this)) +{ + connect(m_editItemsAction, SIGNAL(triggered()), this, SLOT(editItems())); + m_taskActions.append(m_editItemsAction); + + QAction *sep = new QAction(this); + sep->setSeparator(true); + m_taskActions.append(sep); +} + + +TableWidgetTaskMenu::~TableWidgetTaskMenu() +{ +} + +QAction *TableWidgetTaskMenu::preferredEditAction() const +{ + return m_editItemsAction; +} + +QList TableWidgetTaskMenu::taskActions() const +{ + return m_taskActions + QDesignerTaskMenu::taskActions(); +} + +void TableWidgetTaskMenu::editItems() +{ + m_formWindow = QDesignerFormWindowInterface::findFormWindow(m_tableWidget); + if (m_formWindow.isNull()) + return; + + Q_ASSERT(m_tableWidget != 0); + + TableWidgetEditorDialog dlg(m_formWindow, m_tableWidget->window()); + TableWidgetContents oldCont = dlg.fillContentsFromTableWidget(m_tableWidget); + if (dlg.exec() == QDialog::Accepted) { + TableWidgetContents newCont = dlg.contents(); + if (newCont != oldCont) { + ChangeTableContentsCommand *cmd = new ChangeTableContentsCommand(m_formWindow); + cmd->init(m_tableWidget, oldCont, newCont); + m_formWindow->commandHistory()->push(cmd); + } + } +} + +void TableWidgetTaskMenu::updateSelection() +{ + if (m_editor) + m_editor->deleteLater(); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/taskmenu/tablewidget_taskmenu.h b/src/designer/src/components/taskmenu/tablewidget_taskmenu.h new file mode 100644 index 000000000..cbf71fea6 --- /dev/null +++ b/src/designer/src/components/taskmenu/tablewidget_taskmenu.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TABLEWIDGET_TASKMENU_H +#define TABLEWIDGET_TASKMENU_H + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QLineEdit; +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class TableWidgetTaskMenu: public QDesignerTaskMenu +{ + Q_OBJECT +public: + explicit TableWidgetTaskMenu(QTableWidget *button, QObject *parent = 0); + virtual ~TableWidgetTaskMenu(); + + virtual QAction *preferredEditAction() const; + virtual QList taskActions() const; + +private slots: + void editItems(); + void updateSelection(); + +private: + QTableWidget *m_tableWidget; + QPointer m_formWindow; + QPointer m_editor; + mutable QList m_taskActions; + QAction *m_editItemsAction; +}; + +typedef ExtensionFactory TableWidgetTaskMenuFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // TABLEWIDGET_TASKMENU_H diff --git a/src/designer/src/components/taskmenu/tablewidgeteditor.cpp b/src/designer/src/components/taskmenu/tablewidgeteditor.cpp new file mode 100644 index 000000000..35f1a0e49 --- /dev/null +++ b/src/designer/src/components/taskmenu/tablewidgeteditor.cpp @@ -0,0 +1,450 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "tablewidgeteditor.h" +#include +#include +#include +#include "formwindowbase_p.h" +#include "qdesigner_utils_p.h" +#include +#include + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +TableWidgetEditor::TableWidgetEditor(QDesignerFormWindowInterface *form, QDialog *dialog) + : AbstractItemEditor(form, 0), m_updatingBrowser(false) +{ + m_columnEditor = new ItemListEditor(form, this); + m_columnEditor->setObjectName(QLatin1String("columnEditor")); + m_columnEditor->setNewItemText(tr("New Column")); + m_rowEditor = new ItemListEditor(form, this); + m_rowEditor->setObjectName(QLatin1String("rowEditor")); + m_rowEditor->setNewItemText(tr("New Row")); + ui.setupUi(dialog); + + injectPropertyBrowser(ui.itemsTab, ui.widget); + connect(ui.showPropertiesButton, SIGNAL(clicked()), + this, SLOT(togglePropertyBrowser())); + setPropertyBrowserVisible(false); + + ui.tabWidget->insertTab(0, m_columnEditor, tr("&Columns")); + ui.tabWidget->insertTab(1, m_rowEditor, tr("&Rows")); + ui.tabWidget->setCurrentIndex(0); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + ui.tableWidget->setSelectionMode(QAbstractItemView::SingleSelection); + + connect(iconCache(), SIGNAL(reloaded()), this, SLOT(cacheReloaded())); + + connect(ui.tableWidget, SIGNAL(currentCellChanged(int,int,int,int)), + this, SLOT(on_tableWidget_currentCellChanged(int,int,int,int))); + connect(ui.tableWidget, SIGNAL(itemChanged(QTableWidgetItem*)), + this, SLOT(on_tableWidget_itemChanged(QTableWidgetItem*))); + connect(m_columnEditor, SIGNAL(indexChanged(int)), + this, SLOT(on_columnEditor_indexChanged(int))); + connect(m_columnEditor, SIGNAL(itemChanged(int,int,QVariant)), + this, SLOT(on_columnEditor_itemChanged(int,int,QVariant))); + connect(m_columnEditor, SIGNAL(itemInserted(int)), + this, SLOT(on_columnEditor_itemInserted(int))); + connect(m_columnEditor, SIGNAL(itemDeleted(int)), + this, SLOT(on_columnEditor_itemDeleted(int))); + connect(m_columnEditor, SIGNAL(itemMovedUp(int)), + this, SLOT(on_columnEditor_itemMovedUp(int))); + connect(m_columnEditor, SIGNAL(itemMovedDown(int)), + this, SLOT(on_columnEditor_itemMovedDown(int))); + + connect(m_rowEditor, SIGNAL(indexChanged(int)), + this, SLOT(on_rowEditor_indexChanged(int))); + connect(m_rowEditor, SIGNAL(itemChanged(int,int,QVariant)), + this, SLOT(on_rowEditor_itemChanged(int,int,QVariant))); + connect(m_rowEditor, SIGNAL(itemInserted(int)), + this, SLOT(on_rowEditor_itemInserted(int))); + connect(m_rowEditor, SIGNAL(itemDeleted(int)), + this, SLOT(on_rowEditor_itemDeleted(int))); + connect(m_rowEditor, SIGNAL(itemMovedUp(int)), + this, SLOT(on_rowEditor_itemMovedUp(int))); + connect(m_rowEditor, SIGNAL(itemMovedDown(int)), + this, SLOT(on_rowEditor_itemMovedDown(int))); +} + +static AbstractItemEditor::PropertyDefinition tableHeaderPropList[] = { + { Qt::DisplayPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "text" }, + { Qt::DecorationPropertyRole, 0, DesignerPropertyManager::designerIconTypeId, "icon" }, + { Qt::ToolTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "toolTip" }, +// { Qt::StatusTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "statusTip" }, + { Qt::WhatsThisPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "whatsThis" }, + { Qt::FontRole, QVariant::Font, 0, "font" }, + { Qt::TextAlignmentRole, 0, DesignerPropertyManager::designerAlignmentTypeId, "textAlignment" }, + { Qt::BackgroundRole, QVariant::Color, 0, "background" }, + { Qt::ForegroundRole, QVariant::Brush, 0, "foreground" }, + { 0, 0, 0, 0 } +}; + +static AbstractItemEditor::PropertyDefinition tableItemPropList[] = { + { Qt::DisplayPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "text" }, + { Qt::DecorationPropertyRole, 0, DesignerPropertyManager::designerIconTypeId, "icon" }, + { Qt::ToolTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "toolTip" }, +// { Qt::StatusTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "statusTip" }, + { Qt::WhatsThisPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "whatsThis" }, + { Qt::FontRole, QVariant::Font, 0, "font" }, + { Qt::TextAlignmentRole, 0, DesignerPropertyManager::designerAlignmentTypeId, "textAlignment" }, + { Qt::BackgroundRole, QVariant::Brush, 0, "background" }, + { Qt::ForegroundRole, QVariant::Brush, 0, "foreground" }, + { ItemFlagsShadowRole, 0, QtVariantPropertyManager::flagTypeId, "flags" }, + { Qt::CheckStateRole, 0, QtVariantPropertyManager::enumTypeId, "checkState" }, + { 0, 0, 0, 0 } +}; + +TableWidgetContents TableWidgetEditor::fillContentsFromTableWidget(QTableWidget *tableWidget) +{ + TableWidgetContents tblCont; + tblCont.fromTableWidget(tableWidget, false); + tblCont.applyToTableWidget(ui.tableWidget, iconCache(), true); + + tblCont.m_verticalHeader.applyToListWidget(m_rowEditor->listWidget(), iconCache(), true); + m_rowEditor->setupEditor(tableWidget, tableHeaderPropList); + + tblCont.m_horizontalHeader.applyToListWidget(m_columnEditor->listWidget(), iconCache(), true); + m_columnEditor->setupEditor(tableWidget, tableHeaderPropList); + + setupEditor(tableWidget, tableItemPropList); + if (ui.tableWidget->columnCount() > 0 && ui.tableWidget->rowCount() > 0) + ui.tableWidget->setCurrentCell(0, 0); + + updateEditor(); + + return tblCont; +} + +TableWidgetContents TableWidgetEditor::contents() const +{ + TableWidgetContents retVal; + retVal.fromTableWidget(ui.tableWidget, true); + return retVal; +} + +void TableWidgetEditor::setItemData(int role, const QVariant &v) +{ + QTableWidgetItem *item = ui.tableWidget->currentItem(); + BoolBlocker block(m_updatingBrowser); + if (!item) { + item = new QTableWidgetItem; + ui.tableWidget->setItem(ui.tableWidget->currentRow(), ui.tableWidget->currentColumn(), item); + } + QVariant newValue = v; + if (role == Qt::FontRole && newValue.type() == QVariant::Font) { + QFont oldFont = ui.tableWidget->font(); + QFont newFont = qvariant_cast(newValue).resolve(oldFont); + newValue = QVariant::fromValue(newFont); + item->setData(role, QVariant()); // force the right font with the current resolve mask is set (item view bug) + } + item->setData(role, newValue); +} + +QVariant TableWidgetEditor::getItemData(int role) const +{ + QTableWidgetItem *item = ui.tableWidget->currentItem(); + if (!item) + return QVariant(); + return item->data(role); +} + +void TableWidgetEditor::on_tableWidget_currentCellChanged(int currentRow, int currentCol, int, int /* XXX remove me */) +{ + m_rowEditor->setCurrentIndex(currentRow); + m_columnEditor->setCurrentIndex(currentCol); + updateBrowser(); +} + +void TableWidgetEditor::on_tableWidget_itemChanged(QTableWidgetItem *item) +{ + if (m_updatingBrowser) + return; + + PropertySheetStringValue val = qvariant_cast(item->data(Qt::DisplayPropertyRole)); + val.setValue(item->text()); + BoolBlocker block(m_updatingBrowser); + item->setData(Qt::DisplayPropertyRole, QVariant::fromValue(val)); + + updateBrowser(); +} + +void TableWidgetEditor::on_columnEditor_indexChanged(int col) +{ + ui.tableWidget->setCurrentCell(ui.tableWidget->currentRow(), col); +} + +void TableWidgetEditor::on_columnEditor_itemChanged(int idx, int role, const QVariant &v) +{ + ui.tableWidget->horizontalHeaderItem(idx)->setData(role, v); +} + +void TableWidgetEditor::on_rowEditor_indexChanged(int col) +{ + ui.tableWidget->setCurrentCell(col, ui.tableWidget->currentColumn()); +} + +void TableWidgetEditor::on_rowEditor_itemChanged(int idx, int role, const QVariant &v) +{ + ui.tableWidget->verticalHeaderItem(idx)->setData(role, v); +} + +void TableWidgetEditor::setPropertyBrowserVisible(bool v) +{ + ui.showPropertiesButton->setText(v ? tr("Properties &>>") : tr("Properties &<<")); + m_propertyBrowser->setVisible(v); +} + +void TableWidgetEditor::togglePropertyBrowser() +{ + setPropertyBrowserVisible(!m_propertyBrowser->isVisible()); +} + +void TableWidgetEditor::updateEditor() +{ + const bool wasEnabled = ui.tabWidget->isTabEnabled(2); + const bool isEnabled = ui.tableWidget->columnCount() && ui.tableWidget->rowCount(); + ui.tabWidget->setTabEnabled(2, isEnabled); + if (!wasEnabled && isEnabled) + ui.tableWidget->setCurrentCell(0, 0); + + QMetaObject::invokeMethod(ui.tableWidget, "updateGeometries"); + ui.tableWidget->viewport()->update(); +} + +void TableWidgetEditor::moveColumnsLeft(int fromColumn, int toColumn) +{ + if (fromColumn >= toColumn) + return; + + QTableWidgetItem *lastItem = ui.tableWidget->takeHorizontalHeaderItem(toColumn); + for (int i = toColumn; i > fromColumn; i--) { + ui.tableWidget->setHorizontalHeaderItem(i, + ui.tableWidget->takeHorizontalHeaderItem(i - 1)); + } + ui.tableWidget->setHorizontalHeaderItem(fromColumn, lastItem); + + for (int i = 0; i < ui.tableWidget->rowCount(); i++) { + QTableWidgetItem *lastItem = ui.tableWidget->takeItem(i, toColumn); + for (int j = toColumn; j > fromColumn; j--) + ui.tableWidget->setItem(i, j, ui.tableWidget->takeItem(i, j - 1)); + ui.tableWidget->setItem(i, fromColumn, lastItem); + } +} + +void TableWidgetEditor::moveColumnsRight(int fromColumn, int toColumn) +{ + if (fromColumn >= toColumn) + return; + + QTableWidgetItem *lastItem = ui.tableWidget->takeHorizontalHeaderItem(fromColumn); + for (int i = fromColumn; i < toColumn; i++) { + ui.tableWidget->setHorizontalHeaderItem(i, + ui.tableWidget->takeHorizontalHeaderItem(i + 1)); + } + ui.tableWidget->setHorizontalHeaderItem(toColumn, lastItem); + + for (int i = 0; i < ui.tableWidget->rowCount(); i++) { + QTableWidgetItem *lastItem = ui.tableWidget->takeItem(i, fromColumn); + for (int j = fromColumn; j < toColumn; j++) + ui.tableWidget->setItem(i, j, ui.tableWidget->takeItem(i, j + 1)); + ui.tableWidget->setItem(i, toColumn, lastItem); + } +} + +void TableWidgetEditor::moveRowsDown(int fromRow, int toRow) +{ + if (fromRow >= toRow) + return; + + QTableWidgetItem *lastItem = ui.tableWidget->takeVerticalHeaderItem(toRow); + for (int i = toRow; i > fromRow; i--) { + ui.tableWidget->setVerticalHeaderItem(i, + ui.tableWidget->takeVerticalHeaderItem(i - 1)); + } + ui.tableWidget->setVerticalHeaderItem(fromRow, lastItem); + + for (int i = 0; i < ui.tableWidget->columnCount(); i++) { + QTableWidgetItem *lastItem = ui.tableWidget->takeItem(toRow, i); + for (int j = toRow; j > fromRow; j--) + ui.tableWidget->setItem(j, i, ui.tableWidget->takeItem(j - 1, i)); + ui.tableWidget->setItem(fromRow, i, lastItem); + } +} + +void TableWidgetEditor::moveRowsUp(int fromRow, int toRow) +{ + if (fromRow >= toRow) + return; + + QTableWidgetItem *lastItem = ui.tableWidget->takeVerticalHeaderItem(fromRow); + for (int i = fromRow; i < toRow; i++) { + ui.tableWidget->setVerticalHeaderItem(i, + ui.tableWidget->takeVerticalHeaderItem(i + 1)); + } + ui.tableWidget->setVerticalHeaderItem(toRow, lastItem); + + for (int i = 0; i < ui.tableWidget->columnCount(); i++) { + QTableWidgetItem *lastItem = ui.tableWidget->takeItem(fromRow, i); + for (int j = fromRow; j < toRow; j++) + ui.tableWidget->setItem(j, i, ui.tableWidget->takeItem(j + 1, i)); + ui.tableWidget->setItem(toRow, i, lastItem); + } +} + +void TableWidgetEditor::on_columnEditor_itemInserted(int idx) +{ + const int columnCount = ui.tableWidget->columnCount(); + ui.tableWidget->setColumnCount(columnCount + 1); + + QTableWidgetItem *newItem = new QTableWidgetItem(m_columnEditor->newItemText()); + newItem->setData(Qt::DisplayPropertyRole, QVariant::fromValue(PropertySheetStringValue(m_columnEditor->newItemText()))); + ui.tableWidget->setHorizontalHeaderItem(columnCount, newItem); + + moveColumnsLeft(idx, columnCount); + + int row = ui.tableWidget->currentRow(); + if (row >= 0) + ui.tableWidget->setCurrentCell(row, idx); + + updateEditor(); +} + +void TableWidgetEditor::on_columnEditor_itemDeleted(int idx) +{ + const int columnCount = ui.tableWidget->columnCount(); + + moveColumnsRight(idx, columnCount - 1); + ui.tableWidget->setColumnCount(columnCount - 1); + + updateEditor(); +} + +void TableWidgetEditor::on_columnEditor_itemMovedUp(int idx) +{ + moveColumnsRight(idx - 1, idx); + + ui.tableWidget->setCurrentCell(ui.tableWidget->currentRow(), idx - 1); +} + +void TableWidgetEditor::on_columnEditor_itemMovedDown(int idx) +{ + moveColumnsLeft(idx, idx + 1); + + ui.tableWidget->setCurrentCell(ui.tableWidget->currentRow(), idx + 1); +} + +void TableWidgetEditor::on_rowEditor_itemInserted(int idx) +{ + const int rowCount = ui.tableWidget->rowCount(); + ui.tableWidget->setRowCount(rowCount + 1); + + QTableWidgetItem *newItem = new QTableWidgetItem(m_rowEditor->newItemText()); + newItem->setData(Qt::DisplayPropertyRole, QVariant::fromValue(PropertySheetStringValue(m_rowEditor->newItemText()))); + ui.tableWidget->setVerticalHeaderItem(rowCount, newItem); + + moveRowsDown(idx, rowCount); + + int col = ui.tableWidget->currentColumn(); + if (col >= 0) + ui.tableWidget->setCurrentCell(idx, col); + + updateEditor(); +} + +void TableWidgetEditor::on_rowEditor_itemDeleted(int idx) +{ + const int rowCount = ui.tableWidget->rowCount(); + + moveRowsUp(idx, rowCount - 1); + ui.tableWidget->setRowCount(rowCount - 1); + + updateEditor(); +} + +void TableWidgetEditor::on_rowEditor_itemMovedUp(int idx) +{ + moveRowsUp(idx - 1, idx); + + ui.tableWidget->setCurrentCell(idx - 1, ui.tableWidget->currentColumn()); +} + +void TableWidgetEditor::on_rowEditor_itemMovedDown(int idx) +{ + moveRowsDown(idx, idx + 1); + + ui.tableWidget->setCurrentCell(idx + 1, ui.tableWidget->currentColumn()); +} + +void TableWidgetEditor::cacheReloaded() +{ + reloadIconResources(iconCache(), ui.tableWidget); +} + +TableWidgetEditorDialog::TableWidgetEditorDialog(QDesignerFormWindowInterface *form, QWidget *parent) : + QDialog(parent), m_editor(form, this) +{ + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); +} + +TableWidgetContents TableWidgetEditorDialog::fillContentsFromTableWidget(QTableWidget *tableWidget) +{ + return m_editor.fillContentsFromTableWidget(tableWidget); +} + +TableWidgetContents TableWidgetEditorDialog::contents() const +{ + return m_editor.contents(); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/components/taskmenu/tablewidgeteditor.h b/src/designer/src/components/taskmenu/tablewidgeteditor.h new file mode 100644 index 000000000..1d5ad1f57 --- /dev/null +++ b/src/designer/src/components/taskmenu/tablewidgeteditor.h @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TABLEWIDGETEDITOR_H +#define TABLEWIDGETEDITOR_H + +#include "ui_tablewidgeteditor.h" + +#include "listwidgeteditor.h" + +#include + +QT_BEGIN_NAMESPACE + +class QTableWidget; +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class FormWindowBase; +class PropertySheetIconValue; + +class TableWidgetEditor: public AbstractItemEditor +{ + Q_OBJECT +public: + explicit TableWidgetEditor(QDesignerFormWindowInterface *form, QDialog *dialog); + + TableWidgetContents fillContentsFromTableWidget(QTableWidget *tableWidget); + TableWidgetContents contents() const; + +private slots: + + void on_tableWidget_currentCellChanged(int currentRow, int currnetCol, int, int); + void on_tableWidget_itemChanged(QTableWidgetItem *item); + + void on_columnEditor_indexChanged(int idx); + void on_columnEditor_itemChanged(int idx, int role, const QVariant &v); + + void on_columnEditor_itemInserted(int idx); + void on_columnEditor_itemDeleted(int idx); + void on_columnEditor_itemMovedUp(int idx); + void on_columnEditor_itemMovedDown(int idx); + + void on_rowEditor_indexChanged(int idx); + void on_rowEditor_itemChanged(int idx, int role, const QVariant &v); + + void on_rowEditor_itemInserted(int idx); + void on_rowEditor_itemDeleted(int idx); + void on_rowEditor_itemMovedUp(int idx); + void on_rowEditor_itemMovedDown(int idx); + + void togglePropertyBrowser(); + + void cacheReloaded(); + +protected: + virtual void setItemData(int role, const QVariant &v); + virtual QVariant getItemData(int role) const; + +private: + void setPropertyBrowserVisible(bool v); + void updateEditor(); + void moveColumnsLeft(int fromColumn, int toColumn); + void moveColumnsRight(int fromColumn, int toColumn); + void moveRowsUp(int fromRow, int toRow); + void moveRowsDown(int fromRow, int toRow); + + Ui::TableWidgetEditor ui; + ItemListEditor *m_rowEditor; + ItemListEditor *m_columnEditor; + bool m_updatingBrowser; +}; + +class TableWidgetEditorDialog : public QDialog +{ + Q_OBJECT +public: + explicit TableWidgetEditorDialog(QDesignerFormWindowInterface *form, QWidget *parent); + + TableWidgetContents fillContentsFromTableWidget(QTableWidget *tableWidget); + TableWidgetContents contents() const; + +private: + TableWidgetEditor m_editor; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // TABLEWIDGETEDITOR_H diff --git a/src/designer/src/components/taskmenu/tablewidgeteditor.ui b/src/designer/src/components/taskmenu/tablewidgeteditor.ui new file mode 100644 index 000000000..33691e94d --- /dev/null +++ b/src/designer/src/components/taskmenu/tablewidgeteditor.ui @@ -0,0 +1,157 @@ + + ********************************************************************* +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +********************************************************************* + qdesigner_internal::TableWidgetEditor + + + + 0 + 0 + 550 + 360 + + + + Edit Table Widget + + + + + + 0 + + + + &Items + + + + + + + 0 + + + + + Table Items + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Properties &>> + + + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + qdesigner_internal::TableWidgetEditor + accept() + + + 431 + 351 + + + 373 + 362 + + + + + buttonBox + rejected() + qdesigner_internal::TableWidgetEditor + reject() + + + 547 + 354 + + + 562 + 362 + + + + + diff --git a/src/designer/src/components/taskmenu/taskmenu.pri b/src/designer/src/components/taskmenu/taskmenu.pri new file mode 100644 index 000000000..066b92980 --- /dev/null +++ b/src/designer/src/components/taskmenu/taskmenu.pri @@ -0,0 +1,50 @@ +INCLUDEPATH += $$PWD \ + ../propertyeditor \ + $$QT_BUILD_TREE/tools/designer/src/components/taskmenu \ + $$QT_SOURCE_TREE/tools/shared/qtpropertybrowser + +FORMS += $$PWD/itemlisteditor.ui \ + $$PWD/treewidgeteditor.ui \ + $$PWD/tablewidgeteditor.ui + +HEADERS += $$PWD/button_taskmenu.h \ + $$PWD/groupbox_taskmenu.h \ + $$PWD/label_taskmenu.h \ + $$PWD/lineedit_taskmenu.h \ + $$PWD/listwidget_taskmenu.h \ + $$PWD/treewidget_taskmenu.h \ + $$PWD/tablewidget_taskmenu.h \ + $$PWD/combobox_taskmenu.h \ + $$PWD/textedit_taskmenu.h \ + $$PWD/toolbar_taskmenu.h \ + $$PWD/containerwidget_taskmenu.h \ + $$PWD/inplace_editor.h \ + $$PWD/taskmenu_component.h \ + $$PWD/itemlisteditor.h \ + $$PWD/listwidgeteditor.h \ + $$PWD/treewidgeteditor.h \ + $$PWD/tablewidgeteditor.h \ + $$PWD/inplace_widget_helper.h \ + $$PWD/menutaskmenu.h \ + $$PWD/layouttaskmenu.h + +SOURCES += $$PWD/button_taskmenu.cpp \ + $$PWD/groupbox_taskmenu.cpp \ + $$PWD/label_taskmenu.cpp \ + $$PWD/lineedit_taskmenu.cpp \ + $$PWD/listwidget_taskmenu.cpp \ + $$PWD/treewidget_taskmenu.cpp \ + $$PWD/tablewidget_taskmenu.cpp \ + $$PWD/combobox_taskmenu.cpp \ + $$PWD/textedit_taskmenu.cpp \ + $$PWD/toolbar_taskmenu.cpp \ + $$PWD/containerwidget_taskmenu.cpp \ + $$PWD/inplace_editor.cpp \ + $$PWD/taskmenu_component.cpp \ + $$PWD/itemlisteditor.cpp \ + $$PWD/listwidgeteditor.cpp \ + $$PWD/treewidgeteditor.cpp \ + $$PWD/tablewidgeteditor.cpp \ + $$PWD/inplace_widget_helper.cpp \ + $$PWD/menutaskmenu.cpp \ + $$PWD/layouttaskmenu.cpp diff --git a/src/designer/src/components/taskmenu/taskmenu_component.cpp b/src/designer/src/components/taskmenu/taskmenu_component.cpp new file mode 100644 index 000000000..c7f395349 --- /dev/null +++ b/src/designer/src/components/taskmenu/taskmenu_component.cpp @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "taskmenu_component.h" +#include "button_taskmenu.h" +#include "groupbox_taskmenu.h" +#include "label_taskmenu.h" +#include "lineedit_taskmenu.h" +#include "listwidget_taskmenu.h" +#include "treewidget_taskmenu.h" +#include "tablewidget_taskmenu.h" +#include "containerwidget_taskmenu.h" +#include "combobox_taskmenu.h" +#include "textedit_taskmenu.h" +#include "menutaskmenu.h" +#include "toolbar_taskmenu.h" +#include "layouttaskmenu.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +TaskMenuComponent::TaskMenuComponent(QDesignerFormEditorInterface *core, QObject *parent) + : QObject(parent), + m_core(core) +{ + Q_ASSERT(m_core != 0); + + QExtensionManager *mgr = core->extensionManager(); + const QString taskMenuId = QLatin1String("QDesignerInternalTaskMenuExtension"); + + ButtonTaskMenuFactory::registerExtension(mgr, taskMenuId); + CommandLinkButtonTaskMenuFactory::registerExtension(mgr, taskMenuId); // Order! + ButtonGroupTaskMenuFactory::registerExtension(mgr, taskMenuId); + + GroupBoxTaskMenuFactory::registerExtension(mgr, taskMenuId); + LabelTaskMenuFactory::registerExtension(mgr, taskMenuId); + LineEditTaskMenuFactory::registerExtension(mgr, taskMenuId); + ListWidgetTaskMenuFactory::registerExtension(mgr, taskMenuId); + TreeWidgetTaskMenuFactory::registerExtension(mgr, taskMenuId); + TableWidgetTaskMenuFactory::registerExtension(mgr, taskMenuId); + TextEditTaskMenuFactory::registerExtension(mgr, taskMenuId); + PlainTextEditTaskMenuFactory::registerExtension(mgr, taskMenuId); + MenuTaskMenuFactory::registerExtension(mgr, taskMenuId); + MenuBarTaskMenuFactory::registerExtension(mgr, taskMenuId); + ToolBarTaskMenuFactory::registerExtension(mgr, taskMenuId); + StatusBarTaskMenuFactory::registerExtension(mgr, taskMenuId); + LayoutWidgetTaskMenuFactory::registerExtension(mgr, taskMenuId); + SpacerTaskMenuFactory::registerExtension(mgr, taskMenuId); + + mgr->registerExtensions(new ContainerWidgetTaskMenuFactory(core, mgr), taskMenuId); + mgr->registerExtensions(new ComboBoxTaskMenuFactory(taskMenuId, mgr), taskMenuId); +} + +TaskMenuComponent::~TaskMenuComponent() +{ +} + +QDesignerFormEditorInterface *TaskMenuComponent::core() const +{ + return m_core; + +} +QT_END_NAMESPACE + diff --git a/src/designer/src/components/taskmenu/taskmenu_component.h b/src/designer/src/components/taskmenu/taskmenu_component.h new file mode 100644 index 000000000..762567c84 --- /dev/null +++ b/src/designer/src/components/taskmenu/taskmenu_component.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TASKMENU_COMPONENT_H +#define TASKMENU_COMPONENT_H + +#include "taskmenu_global.h" +#include + +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +class QT_TASKMENU_EXPORT TaskMenuComponent: public QObject +{ + Q_OBJECT +public: + explicit TaskMenuComponent(QDesignerFormEditorInterface *core, QObject *parent = 0); + virtual ~TaskMenuComponent(); + + QDesignerFormEditorInterface *core() const; + +private: + QDesignerFormEditorInterface *m_core; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // TASKMENU_COMPONENT_H diff --git a/src/designer/src/components/taskmenu/taskmenu_global.h b/src/designer/src/components/taskmenu/taskmenu_global.h new file mode 100644 index 000000000..df276016c --- /dev/null +++ b/src/designer/src/components/taskmenu/taskmenu_global.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TASKMENU_GLOBAL_H +#define TASKMENU_GLOBAL_H + +#include + +#ifdef Q_OS_WIN +#ifdef QT_TASKMENU_LIBRARY +# define QT_TASKMENU_EXPORT +#else +# define QT_TASKMENU_EXPORT +#endif +#else +#define QT_TASKMENU_EXPORT +#endif + +#endif // TASKMENU_GLOBAL_H diff --git a/src/designer/src/components/taskmenu/textedit_taskmenu.cpp b/src/designer/src/components/taskmenu/textedit_taskmenu.cpp new file mode 100644 index 000000000..510a32f5f --- /dev/null +++ b/src/designer/src/components/taskmenu/textedit_taskmenu.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "textedit_taskmenu.h" + +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +TextEditTaskMenu::TextEditTaskMenu(QTextEdit *textEdit, QObject *parent) : + QDesignerTaskMenu(textEdit, parent), + m_format(Qt::RichText), + m_property(QLatin1String("html")), + m_windowTitle(tr("Edit HTML")), + m_editTextAction(new QAction(tr("Change HTML..."), this)) +{ + initialize(); +} + +TextEditTaskMenu::TextEditTaskMenu(QPlainTextEdit *textEdit, QObject *parent) : + QDesignerTaskMenu(textEdit, parent), + m_format(Qt::PlainText), + m_property(QLatin1String("plainText")), + m_windowTitle(tr("Edit Text")), + m_editTextAction(new QAction(tr("Change Plain Text..."), this)) +{ + initialize(); +} + + +void TextEditTaskMenu::initialize() +{ + connect(m_editTextAction, SIGNAL(triggered()), this, SLOT(editText())); + m_taskActions.append(m_editTextAction); + + QAction *sep = new QAction(this); + sep->setSeparator(true); + m_taskActions.append(sep); +} + +TextEditTaskMenu::~TextEditTaskMenu() +{ +} + +QAction *TextEditTaskMenu::preferredEditAction() const +{ + return m_editTextAction; +} + +QList TextEditTaskMenu::taskActions() const +{ + return m_taskActions + QDesignerTaskMenu::taskActions(); +} + +void TextEditTaskMenu::editText() +{ + changeTextProperty(m_property, m_windowTitle, MultiSelectionMode, m_format); +} + +} +QT_END_NAMESPACE diff --git a/src/designer/src/components/taskmenu/textedit_taskmenu.h b/src/designer/src/components/taskmenu/textedit_taskmenu.h new file mode 100644 index 000000000..1429f315e --- /dev/null +++ b/src/designer/src/components/taskmenu/textedit_taskmenu.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TEXTEDIT_TASKMENU_H +#define TEXTEDIT_TASKMENU_H + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class TextEditTaskMenu: public QDesignerTaskMenu +{ + Q_OBJECT +public: + explicit TextEditTaskMenu(QTextEdit *button, QObject *parent = 0); + explicit TextEditTaskMenu(QPlainTextEdit *button, QObject *parent = 0); + + virtual ~TextEditTaskMenu(); + + virtual QAction *preferredEditAction() const; + virtual QList taskActions() const; + +private slots: + void editText(); + +private: + void initialize(); + + const Qt::TextFormat m_format; + const QString m_property; + const QString m_windowTitle; + + mutable QList m_taskActions; + QAction *m_editTextAction; +}; + +typedef ExtensionFactory TextEditTaskMenuFactory; +typedef ExtensionFactory PlainTextEditTaskMenuFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // TEXTEDIT_TASKMENU_H diff --git a/src/designer/src/components/taskmenu/toolbar_taskmenu.cpp b/src/designer/src/components/taskmenu/toolbar_taskmenu.cpp new file mode 100644 index 000000000..8db233ca2 --- /dev/null +++ b/src/designer/src/components/taskmenu/toolbar_taskmenu.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "toolbar_taskmenu.h" +#include "qdesigner_toolbar_p.h" + +#include + +#include +#include + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + // ------------ ToolBarTaskMenu + ToolBarTaskMenu::ToolBarTaskMenu(QToolBar *tb, QObject *parent) : + QObject(parent), + m_toolBar(tb) + { + } + + QAction *ToolBarTaskMenu::preferredEditAction() const + { + return 0; + } + + QList ToolBarTaskMenu::taskActions() const + { + if (ToolBarEventFilter *ef = ToolBarEventFilter::eventFilterOf(m_toolBar)) + return ef->contextMenuActions(); + return QList(); + } + + // ------------ StatusBarTaskMenu + StatusBarTaskMenu::StatusBarTaskMenu(QStatusBar *sb, QObject *parent) : + QObject(parent), + m_statusBar(sb), + m_removeAction(new QAction(tr("Remove"), this)), + m_promotionTaskMenu(new PromotionTaskMenu(sb, PromotionTaskMenu::ModeSingleWidget, this)) + { + connect(m_removeAction, SIGNAL(triggered()), this, SLOT(removeStatusBar())); + } + + QAction *StatusBarTaskMenu::preferredEditAction() const + { + return 0; + } + + QList StatusBarTaskMenu::taskActions() const + { + QList rc; + rc.push_back(m_removeAction); + m_promotionTaskMenu->addActions(PromotionTaskMenu::LeadingSeparator, rc); + return rc; + } + + void StatusBarTaskMenu::removeStatusBar() + { + if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(m_statusBar)) { + DeleteStatusBarCommand *cmd = new DeleteStatusBarCommand(fw); + cmd->init(m_statusBar); + fw->commandHistory()->push(cmd); + } + } +} + +QT_END_NAMESPACE + diff --git a/src/designer/src/components/taskmenu/toolbar_taskmenu.h b/src/designer/src/components/taskmenu/toolbar_taskmenu.h new file mode 100644 index 000000000..6818e2607 --- /dev/null +++ b/src/designer/src/components/taskmenu/toolbar_taskmenu.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TOOLBAR_TASKMENU_H +#define TOOLBAR_TASKMENU_H + +#include + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + class PromotionTaskMenu; + +// ToolBarTaskMenu forwards the actions of ToolBarEventFilter +class ToolBarTaskMenu : public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + explicit ToolBarTaskMenu(QToolBar *tb, QObject *parent = 0); + + virtual QAction *preferredEditAction() const; + virtual QList taskActions() const; + +private: + QToolBar *m_toolBar; +}; + +// StatusBarTaskMenu provides promotion and deletion +class StatusBarTaskMenu : public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + explicit StatusBarTaskMenu(QStatusBar *tb, QObject *parent = 0); + + virtual QAction *preferredEditAction() const; + virtual QList taskActions() const; + +private slots: + void removeStatusBar(); + +private: + QStatusBar *m_statusBar; + QAction *m_removeAction; + PromotionTaskMenu *m_promotionTaskMenu; +}; + +typedef ExtensionFactory ToolBarTaskMenuFactory; +typedef ExtensionFactory StatusBarTaskMenuFactory; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // TOOLBAR_TASKMENU_H diff --git a/src/designer/src/components/taskmenu/treewidget_taskmenu.cpp b/src/designer/src/components/taskmenu/treewidget_taskmenu.cpp new file mode 100644 index 000000000..96210dcdb --- /dev/null +++ b/src/designer/src/components/taskmenu/treewidget_taskmenu.cpp @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "treewidget_taskmenu.h" +#include "treewidgeteditor.h" + +#include + +#include +#include +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +TreeWidgetTaskMenu::TreeWidgetTaskMenu(QTreeWidget *button, QObject *parent) + : QDesignerTaskMenu(button, parent), + m_treeWidget(button), + m_editItemsAction(new QAction(tr("Edit Items..."), this)) +{ + connect(m_editItemsAction, SIGNAL(triggered()), this, SLOT(editItems())); + m_taskActions.append(m_editItemsAction); + + QAction *sep = new QAction(this); + sep->setSeparator(true); + m_taskActions.append(sep); +} + + +TreeWidgetTaskMenu::~TreeWidgetTaskMenu() +{ +} + +QAction *TreeWidgetTaskMenu::preferredEditAction() const +{ + return m_editItemsAction; +} + +QList TreeWidgetTaskMenu::taskActions() const +{ + return m_taskActions + QDesignerTaskMenu::taskActions(); +} + +void TreeWidgetTaskMenu::editItems() +{ + m_formWindow = QDesignerFormWindowInterface::findFormWindow(m_treeWidget); + if (m_formWindow.isNull()) + return; + + Q_ASSERT(m_treeWidget != 0); + + TreeWidgetEditorDialog dlg(m_formWindow, m_treeWidget->window()); + TreeWidgetContents oldCont = dlg.fillContentsFromTreeWidget(m_treeWidget); + if (dlg.exec() == QDialog::Accepted) { + TreeWidgetContents newCont = dlg.contents(); + if (newCont != oldCont) { + ChangeTreeContentsCommand *cmd = new ChangeTreeContentsCommand(m_formWindow); + cmd->init(m_treeWidget, oldCont, newCont); + m_formWindow->commandHistory()->push(cmd); + } + } +} + +void TreeWidgetTaskMenu::updateSelection() +{ + if (m_editor) + m_editor->deleteLater(); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/taskmenu/treewidget_taskmenu.h b/src/designer/src/components/taskmenu/treewidget_taskmenu.h new file mode 100644 index 000000000..e5a9e9073 --- /dev/null +++ b/src/designer/src/components/taskmenu/treewidget_taskmenu.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TREEWIDGET_TASKMENU_H +#define TREEWIDGET_TASKMENU_H + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QLineEdit; +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class TreeWidgetTaskMenu: public QDesignerTaskMenu +{ + Q_OBJECT +public: + explicit TreeWidgetTaskMenu(QTreeWidget *button, QObject *parent = 0); + virtual ~TreeWidgetTaskMenu(); + + virtual QAction *preferredEditAction() const; + virtual QList taskActions() const; + +private slots: + void editItems(); + void updateSelection(); + +private: + QTreeWidget *m_treeWidget; + QPointer m_formWindow; + QPointer m_editor; + mutable QList m_taskActions; + QAction *m_editItemsAction; +}; + +typedef ExtensionFactory TreeWidgetTaskMenuFactory; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // TREEWIDGET_TASKMENU_H diff --git a/src/designer/src/components/taskmenu/treewidgeteditor.cpp b/src/designer/src/components/taskmenu/treewidgeteditor.cpp new file mode 100644 index 000000000..f5f6035f2 --- /dev/null +++ b/src/designer/src/components/taskmenu/treewidgeteditor.cpp @@ -0,0 +1,642 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "treewidgeteditor.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +TreeWidgetEditor::TreeWidgetEditor(QDesignerFormWindowInterface *form, QDialog *dialog) + : AbstractItemEditor(form, 0), m_updatingBrowser(false) +{ + m_columnEditor = new ItemListEditor(form, this); + m_columnEditor->setObjectName(QLatin1String("columnEditor")); + m_columnEditor->setNewItemText(tr("New Column")); + ui.setupUi(dialog); + + injectPropertyBrowser(ui.itemsTab, ui.widget); + connect(ui.showPropertiesButton, SIGNAL(clicked()), + this, SLOT(togglePropertyBrowser())); + setPropertyBrowserVisible(false); + + ui.tabWidget->insertTab(0, m_columnEditor, tr("&Columns")); + ui.tabWidget->setCurrentIndex(0); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + ui.newItemButton->setIcon(createIconSet(QString::fromUtf8("plus.png"))); + ui.newSubItemButton->setIcon(createIconSet(QString::fromUtf8("downplus.png"))); + ui.deleteItemButton->setIcon(createIconSet(QString::fromUtf8("minus.png"))); + ui.moveItemUpButton->setIcon(createIconSet(QString::fromUtf8("up.png"))); + ui.moveItemDownButton->setIcon(createIconSet(QString::fromUtf8("down.png"))); + ui.moveItemRightButton->setIcon(createIconSet(QString::fromUtf8("leveldown.png"))); + ui.moveItemLeftButton->setIcon(createIconSet(QString::fromUtf8("levelup.png"))); + + ui.treeWidget->header()->setMovable(false); + + connect(ui.newItemButton, SIGNAL(clicked()), this, SLOT(on_newItemButton_clicked())); + connect(ui.newSubItemButton, SIGNAL(clicked()), this, SLOT(on_newSubItemButton_clicked())); + connect(ui.moveItemUpButton, SIGNAL(clicked()), this, SLOT(on_moveItemUpButton_clicked())); + connect(ui.moveItemDownButton, SIGNAL(clicked()), this, SLOT(on_moveItemDownButton_clicked())); + connect(ui.moveItemRightButton, SIGNAL(clicked()), this, SLOT(on_moveItemRightButton_clicked())); + connect(ui.moveItemLeftButton, SIGNAL(clicked()), this, SLOT(on_moveItemLeftButton_clicked())); + connect(ui.treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), + this, SLOT(on_treeWidget_currentItemChanged())); + connect(ui.treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)), + this, SLOT(on_treeWidget_itemChanged(QTreeWidgetItem*,int))); + + connect(m_columnEditor, SIGNAL(indexChanged(int)), + this, SLOT(on_columnEditor_indexChanged(int))); + connect(m_columnEditor, SIGNAL(itemChanged(int,int,QVariant)), + this, SLOT(on_columnEditor_itemChanged(int,int,QVariant))); + connect(m_columnEditor, SIGNAL(itemInserted(int)), + this, SLOT(on_columnEditor_itemInserted(int))); + connect(m_columnEditor, SIGNAL(itemDeleted(int)), + this, SLOT(on_columnEditor_itemDeleted(int))); + connect(m_columnEditor, SIGNAL(itemMovedUp(int)), + this, SLOT(on_columnEditor_itemMovedUp(int))); + connect(m_columnEditor, SIGNAL(itemMovedDown(int)), + this, SLOT(on_columnEditor_itemMovedDown(int))); + + connect(iconCache(), SIGNAL(reloaded()), this, SLOT(cacheReloaded())); +} + +static AbstractItemEditor::PropertyDefinition treeHeaderPropList[] = { + { Qt::DisplayPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "text" }, + { Qt::DecorationPropertyRole, 0, DesignerPropertyManager::designerIconTypeId, "icon" }, + { Qt::ToolTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "toolTip" }, + { Qt::StatusTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "statusTip" }, + { Qt::WhatsThisPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "whatsThis" }, + { Qt::FontRole, QVariant::Font, 0, "font" }, + { Qt::TextAlignmentRole, 0, DesignerPropertyManager::designerAlignmentTypeId, "textAlignment" }, + { Qt::BackgroundRole, QVariant::Color, 0, "background" }, + { Qt::ForegroundRole, QVariant::Brush, 0, "foreground" }, + { 0, 0, 0, 0 } +}; + +static AbstractItemEditor::PropertyDefinition treeItemColumnPropList[] = { + { Qt::DisplayPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "text" }, + { Qt::DecorationPropertyRole, 0, DesignerPropertyManager::designerIconTypeId, "icon" }, + { Qt::ToolTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "toolTip" }, + { Qt::StatusTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "statusTip" }, + { Qt::WhatsThisPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "whatsThis" }, + { Qt::FontRole, QVariant::Font, 0, "font" }, + { Qt::TextAlignmentRole, 0, DesignerPropertyManager::designerAlignmentTypeId, "textAlignment" }, + { Qt::BackgroundRole, QVariant::Brush, 0, "background" }, + { Qt::ForegroundRole, QVariant::Brush, 0, "foreground" }, + { Qt::CheckStateRole, 0, QtVariantPropertyManager::enumTypeId, "checkState" }, + { 0, 0, 0, 0 } +}; + +static AbstractItemEditor::PropertyDefinition treeItemCommonPropList[] = { + { ItemFlagsShadowRole, 0, QtVariantPropertyManager::flagTypeId, "flags" }, + { 0, 0, 0, 0 } +}; + +QtVariantProperty *TreeWidgetEditor::setupPropertyGroup(const QString &title, PropertyDefinition *propDefs) +{ + setupProperties(propDefs); + QtVariantProperty *groupProp = m_propertyManager->addProperty(QtVariantPropertyManager::groupTypeId(), title); + foreach (QtVariantProperty *prop, m_rootProperties) + groupProp->addSubProperty(prop); + m_rootProperties.clear(); + return groupProp; +} + +TreeWidgetContents TreeWidgetEditor::fillContentsFromTreeWidget(QTreeWidget *treeWidget) +{ + TreeWidgetContents treeCont; + treeCont.fromTreeWidget(treeWidget, false); + treeCont.applyToTreeWidget(ui.treeWidget, iconCache(), true); + + treeCont.m_headerItem.applyToListWidget(m_columnEditor->listWidget(), iconCache(), true); + m_columnEditor->setupEditor(treeWidget, treeHeaderPropList); + + QList rootProperties; + rootProperties.append(setupPropertyGroup(tr("Per column properties"), treeItemColumnPropList)); + rootProperties.append(setupPropertyGroup(tr("Common properties"), treeItemCommonPropList)); + m_rootProperties = rootProperties; + m_propertyBrowser->setPropertiesWithoutValueMarked(true); + m_propertyBrowser->setRootIsDecorated(false); + setupObject(treeWidget); + + if (ui.treeWidget->topLevelItemCount() > 0) + ui.treeWidget->setCurrentItem(ui.treeWidget->topLevelItem(0)); + + updateEditor(); + + return treeCont; +} + +TreeWidgetContents TreeWidgetEditor::contents() const +{ + TreeWidgetContents retVal; + retVal.fromTreeWidget(ui.treeWidget, true); + return retVal; +} + +void TreeWidgetEditor::setItemData(int role, const QVariant &v) +{ + const int col = (role == ItemFlagsShadowRole) ? 0 : ui.treeWidget->currentColumn(); + QVariant newValue = v; + BoolBlocker block(m_updatingBrowser); + if (role == Qt::FontRole && newValue.type() == QVariant::Font) { + QFont oldFont = ui.treeWidget->font(); + QFont newFont = qvariant_cast(newValue).resolve(oldFont); + newValue = QVariant::fromValue(newFont); + ui.treeWidget->currentItem()->setData(col, role, QVariant()); // force the right font with the current resolve mask is set (item view bug) + } + ui.treeWidget->currentItem()->setData(col, role, newValue); +} + +QVariant TreeWidgetEditor::getItemData(int role) const +{ + const int col = (role == ItemFlagsShadowRole) ? 0 : ui.treeWidget->currentColumn(); + return ui.treeWidget->currentItem()->data(col, role); +} + +void TreeWidgetEditor::on_newItemButton_clicked() +{ + QTreeWidgetItem *curItem = ui.treeWidget->currentItem(); + QTreeWidgetItem *newItem = 0; + ui.treeWidget->blockSignals(true); + if (curItem) { + if (curItem->parent()) + newItem = new QTreeWidgetItem(curItem->parent(), curItem); + else + newItem = new QTreeWidgetItem(ui.treeWidget, curItem); + } else + newItem = new QTreeWidgetItem(ui.treeWidget); + const QString newItemText = tr("New Item"); + newItem->setText(0, newItemText); + newItem->setData(0, Qt::DisplayPropertyRole, QVariant::fromValue(PropertySheetStringValue(newItemText))); + newItem->setFlags(newItem->flags() | Qt::ItemIsEditable); + ui.treeWidget->blockSignals(false); + + ui.treeWidget->setCurrentItem(newItem, qMax(ui.treeWidget->currentColumn(), 0)); + updateEditor(); + ui.treeWidget->editItem(newItem, ui.treeWidget->currentColumn()); +} + +void TreeWidgetEditor::on_newSubItemButton_clicked() +{ + QTreeWidgetItem *curItem = ui.treeWidget->currentItem(); + if (!curItem) + return; + + ui.treeWidget->blockSignals(true); + QTreeWidgetItem *newItem = new QTreeWidgetItem(curItem); + const QString newItemText = tr("New Subitem"); + newItem->setText(0, newItemText); + newItem->setData(0, Qt::DisplayPropertyRole, QVariant::fromValue(PropertySheetStringValue(newItemText))); + newItem->setFlags(newItem->flags() | Qt::ItemIsEditable); + ui.treeWidget->blockSignals(false); + + ui.treeWidget->setCurrentItem(newItem, ui.treeWidget->currentColumn()); + updateEditor(); + ui.treeWidget->editItem(newItem, ui.treeWidget->currentColumn()); +} + +void TreeWidgetEditor::on_deleteItemButton_clicked() +{ + QTreeWidgetItem *curItem = ui.treeWidget->currentItem(); + if (!curItem) + return; + + QTreeWidgetItem *nextCurrent = 0; + if (curItem->parent()) { + int idx = curItem->parent()->indexOfChild(curItem); + if (idx == curItem->parent()->childCount() - 1) + idx--; + else + idx++; + if (idx < 0) + nextCurrent = curItem->parent(); + else + nextCurrent = curItem->parent()->child(idx); + } else { + int idx = ui.treeWidget->indexOfTopLevelItem(curItem); + if (idx == ui.treeWidget->topLevelItemCount() - 1) + idx--; + else + idx++; + if (idx >= 0) + nextCurrent = ui.treeWidget->topLevelItem(idx); + } + closeEditors(); + ui.treeWidget->blockSignals(true); + delete curItem; + ui.treeWidget->blockSignals(false); + + if (nextCurrent) + ui.treeWidget->setCurrentItem(nextCurrent, ui.treeWidget->currentColumn()); + updateEditor(); +} + +void TreeWidgetEditor::on_moveItemUpButton_clicked() +{ + QTreeWidgetItem *curItem = ui.treeWidget->currentItem(); + if (!curItem) + return; + + int idx; + if (curItem->parent()) + idx = curItem->parent()->indexOfChild(curItem); + else + idx = ui.treeWidget->indexOfTopLevelItem(curItem); + if (idx == 0) + return; + + QTreeWidgetItem *takenItem; + ui.treeWidget->blockSignals(true); + if (curItem->parent()) { + QTreeWidgetItem *parentItem = curItem->parent(); + takenItem = parentItem->takeChild(idx); + parentItem->insertChild(idx - 1, takenItem); + } else { + takenItem = ui.treeWidget->takeTopLevelItem(idx); + ui.treeWidget->insertTopLevelItem(idx - 1, takenItem); + } + ui.treeWidget->blockSignals(false); + + ui.treeWidget->setCurrentItem(takenItem, ui.treeWidget->currentColumn()); + updateEditor(); +} + +void TreeWidgetEditor::on_moveItemDownButton_clicked() +{ + QTreeWidgetItem *curItem = ui.treeWidget->currentItem(); + if (!curItem) + return; + + int idx, idxCount; + if (curItem->parent()) { + idx = curItem->parent()->indexOfChild(curItem); + idxCount = curItem->parent()->childCount(); + } else { + idx = ui.treeWidget->indexOfTopLevelItem(curItem); + idxCount = ui.treeWidget->topLevelItemCount(); + } + if (idx == idxCount - 1) + return; + + QTreeWidgetItem *takenItem; + ui.treeWidget->blockSignals(true); + if (curItem->parent()) { + QTreeWidgetItem *parentItem = curItem->parent(); + takenItem = parentItem->takeChild(idx); + parentItem->insertChild(idx + 1, takenItem); + } else { + takenItem = ui.treeWidget->takeTopLevelItem(idx); + ui.treeWidget->insertTopLevelItem(idx + 1, takenItem); + } + ui.treeWidget->blockSignals(false); + + ui.treeWidget->setCurrentItem(takenItem, ui.treeWidget->currentColumn()); + updateEditor(); +} + +void TreeWidgetEditor::on_moveItemLeftButton_clicked() +{ + QTreeWidgetItem *curItem = ui.treeWidget->currentItem(); + if (!curItem) + return; + + QTreeWidgetItem *parentItem = curItem->parent(); + if (!parentItem) + return; + + ui.treeWidget->blockSignals(true); + QTreeWidgetItem *takenItem = parentItem->takeChild(parentItem->indexOfChild(curItem)); + if (parentItem->parent()) { + int idx = parentItem->parent()->indexOfChild(parentItem); + parentItem->parent()->insertChild(idx, takenItem); + } else { + int idx = ui.treeWidget->indexOfTopLevelItem(parentItem); + ui.treeWidget->insertTopLevelItem(idx, takenItem); + } + ui.treeWidget->blockSignals(false); + + ui.treeWidget->setCurrentItem(takenItem, ui.treeWidget->currentColumn()); + updateEditor(); +} + +void TreeWidgetEditor::on_moveItemRightButton_clicked() +{ + QTreeWidgetItem *curItem = ui.treeWidget->currentItem(); + if (!curItem) + return; + + int idx, idxCount; + if (curItem->parent()) { + idx = curItem->parent()->indexOfChild(curItem); + idxCount = curItem->parent()->childCount(); + } else { + idx = ui.treeWidget->indexOfTopLevelItem(curItem); + idxCount = ui.treeWidget->topLevelItemCount(); + } + if (idx == idxCount - 1) + return; + + QTreeWidgetItem *takenItem; + ui.treeWidget->blockSignals(true); + if (curItem->parent()) { + QTreeWidgetItem *parentItem = curItem->parent()->child(idx + 1); + takenItem = curItem->parent()->takeChild(idx); + parentItem->insertChild(0, takenItem); + } else { + QTreeWidgetItem *parentItem = ui.treeWidget->topLevelItem(idx + 1); + takenItem = ui.treeWidget->takeTopLevelItem(idx); + parentItem->insertChild(0, takenItem); + } + ui.treeWidget->blockSignals(false); + + ui.treeWidget->setCurrentItem(takenItem, ui.treeWidget->currentColumn()); + updateEditor(); +} + +void TreeWidgetEditor::togglePropertyBrowser() +{ + setPropertyBrowserVisible(!m_propertyBrowser->isVisible()); +} + +void TreeWidgetEditor::setPropertyBrowserVisible(bool v) +{ + ui.showPropertiesButton->setText(v ? tr("Properties &>>") : tr("Properties &<<")); + m_propertyBrowser->setVisible(v); +} + +void TreeWidgetEditor::on_treeWidget_currentItemChanged() +{ + m_columnEditor->setCurrentIndex(ui.treeWidget->currentColumn()); + updateEditor(); +} + +void TreeWidgetEditor::on_treeWidget_itemChanged(QTreeWidgetItem *item, int column) +{ + if (m_updatingBrowser) + return; + + PropertySheetStringValue val = qvariant_cast(item->data(column, Qt::DisplayPropertyRole)); + val.setValue(item->text(column)); + BoolBlocker block(m_updatingBrowser); + item->setData(column, Qt::DisplayPropertyRole, QVariant::fromValue(val)); + + updateBrowser(); +} + +void TreeWidgetEditor::on_columnEditor_indexChanged(int idx) +{ + if (QTreeWidgetItem *item = ui.treeWidget->currentItem()) + ui.treeWidget->setCurrentItem(item, idx); +} + +void TreeWidgetEditor::on_columnEditor_itemChanged(int idx, int role, const QVariant &v) +{ + if (role == Qt::DisplayPropertyRole) + ui.treeWidget->headerItem()->setData(idx, Qt::EditRole, qvariant_cast(v).value()); + ui.treeWidget->headerItem()->setData(idx, role, v); +} + +void TreeWidgetEditor::updateEditor() +{ + QTreeWidgetItem *current = ui.treeWidget->currentItem(); + + bool itemsEnabled = false; + bool currentItemEnabled = false; + bool moveItemUpEnabled = false; + bool moveItemDownEnabled = false; + bool moveItemRightEnabled = false; + bool moveItemLeftEnabled = false; + + if (ui.treeWidget->columnCount() > 0) { + itemsEnabled = true; + if (current) { + int idx; + int idxCount; + currentItemEnabled = true; + if (current->parent()) { + moveItemLeftEnabled = true; + idx = current->parent()->indexOfChild(current); + idxCount = current->parent()->childCount(); + } else { + idx = ui.treeWidget->indexOfTopLevelItem(current); + idxCount = ui.treeWidget->topLevelItemCount(); + } + if (idx > 0) + moveItemUpEnabled = true; + if (idx < idxCount - 1) { + moveItemDownEnabled = true; + moveItemRightEnabled = true; + } + } + } + ui.tabWidget->setTabEnabled(1, itemsEnabled); + ui.newSubItemButton->setEnabled(currentItemEnabled); + ui.deleteItemButton->setEnabled(currentItemEnabled); + + ui.moveItemUpButton->setEnabled(moveItemUpEnabled); + ui.moveItemDownButton->setEnabled(moveItemDownEnabled); + ui.moveItemRightButton->setEnabled(moveItemRightEnabled); + ui.moveItemLeftButton->setEnabled(moveItemLeftEnabled); + + if (current) + updateBrowser(); + else + m_propertyBrowser->clear(); +} + +void TreeWidgetEditor::moveColumnItems(const PropertyDefinition *propList, + QTreeWidgetItem *item, int fromColumn, int toColumn, int step) +{ + BoolBlocker block(m_updatingBrowser); + + QList saveCol; + for (int j = 0; propList[j].name; j++) + saveCol.append(item->data(toColumn, propList[j].role)); + QVariant editVariant = item->data(toColumn, Qt::EditRole); + QVariant toolTipVariant = item->data(toColumn, Qt::ToolTipRole); + QVariant statusTipVariant = item->data(toColumn, Qt::StatusTipRole); + QVariant whatsThisVariant = item->data(toColumn, Qt::WhatsThisRole); + QVariant decorationVariant = item->data(toColumn, Qt::DecorationRole); + for (int i = toColumn; i != fromColumn; i += step) { + for (int j = 0; propList[j].name; j++) + item->setData(i, propList[j].role, item->data(i + step, propList[j].role)); + item->setData(i, Qt::EditRole, item->data(i + step, Qt::EditRole)); + item->setData(i, Qt::ToolTipRole, item->data(i + step, Qt::ToolTipRole)); + item->setData(i, Qt::StatusTipRole, item->data(i + step, Qt::StatusTipRole)); + item->setData(i, Qt::WhatsThisRole, item->data(i + step, Qt::WhatsThisRole)); + item->setData(i, Qt::DecorationRole, item->data(i + step, Qt::DecorationRole)); + } + for (int j = 0; propList[j].name; j++) + item->setData(fromColumn, propList[j].role, saveCol[j]); + item->setData(fromColumn, Qt::EditRole, editVariant); + item->setData(fromColumn, Qt::ToolTipRole, toolTipVariant); + item->setData(fromColumn, Qt::StatusTipRole, statusTipVariant); + item->setData(fromColumn, Qt::WhatsThisRole, whatsThisVariant); + item->setData(fromColumn, Qt::DecorationRole, decorationVariant); +} + +void TreeWidgetEditor::moveColumns(int fromColumn, int toColumn, int step) +{ + ui.treeWidget->blockSignals(true); + + moveColumnItems(treeHeaderPropList, ui.treeWidget->headerItem(), fromColumn, toColumn, step); + + QQueue pendingQueue; + for (int i = 0; i < ui.treeWidget->topLevelItemCount(); i++) + pendingQueue.enqueue(ui.treeWidget->topLevelItem(i)); + + while (!pendingQueue.isEmpty()) { + QTreeWidgetItem *item = pendingQueue.dequeue(); + for (int i = 0; i < item->childCount(); i++) + pendingQueue.enqueue(item->child(i)); + + moveColumnItems(treeItemColumnPropList, item, fromColumn, toColumn, step); + } + + ui.treeWidget->blockSignals(false); +} + +void TreeWidgetEditor::moveColumnsLeft(int fromColumn, int toColumn) +{ + if (fromColumn >= toColumn) + return; + + moveColumns(fromColumn, toColumn, -1); +} + +void TreeWidgetEditor::moveColumnsRight(int fromColumn, int toColumn) +{ + if (fromColumn >= toColumn) + return; + + moveColumns(toColumn, fromColumn, 1); +} + +void TreeWidgetEditor::on_columnEditor_itemInserted(int idx) +{ + int columnCount = ui.treeWidget->columnCount(); + ui.treeWidget->setColumnCount(columnCount + 1); + ui.treeWidget->headerItem()->setText(columnCount, m_columnEditor->newItemText()); + moveColumnsLeft(idx, columnCount); + + updateEditor(); +} + +void TreeWidgetEditor::on_columnEditor_itemDeleted(int idx) +{ + closeEditors(); + + int columnCount = ui.treeWidget->columnCount() - 1; + if (!columnCount) + ui.treeWidget->clear(); + else + moveColumnsRight(idx, columnCount); + ui.treeWidget->setColumnCount(columnCount); + + updateEditor(); +} + +void TreeWidgetEditor::on_columnEditor_itemMovedUp(int idx) +{ + moveColumnsRight(idx - 1, idx); + + ui.treeWidget->setCurrentItem(ui.treeWidget->currentItem(), idx - 1); + updateEditor(); +} + +void TreeWidgetEditor::on_columnEditor_itemMovedDown(int idx) +{ + moveColumnsLeft(idx, idx + 1); + + ui.treeWidget->setCurrentItem(ui.treeWidget->currentItem(), idx + 1); + updateEditor(); +} + +void TreeWidgetEditor::closeEditors() +{ + if (QTreeWidgetItem *cur = ui.treeWidget->currentItem() ) { + const int numCols = cur->columnCount (); + for (int i = 0; i < numCols; i++) + ui.treeWidget->closePersistentEditor (cur, i); + } +} + +void TreeWidgetEditor::cacheReloaded() +{ + reloadIconResources(iconCache(), ui.treeWidget); +} + +TreeWidgetEditorDialog::TreeWidgetEditorDialog(QDesignerFormWindowInterface *form, QWidget *parent) : + QDialog(parent), m_editor(form, this) +{ + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); +} + +TreeWidgetContents TreeWidgetEditorDialog::fillContentsFromTreeWidget(QTreeWidget *treeWidget) +{ + return m_editor.fillContentsFromTreeWidget(treeWidget); +} + +TreeWidgetContents TreeWidgetEditorDialog::contents() const +{ + return m_editor.contents(); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/components/taskmenu/treewidgeteditor.h b/src/designer/src/components/taskmenu/treewidgeteditor.h new file mode 100644 index 000000000..f502bf3e4 --- /dev/null +++ b/src/designer/src/components/taskmenu/treewidgeteditor.h @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TREEWIDGETEDITOR_H +#define TREEWIDGETEDITOR_H + +#include "ui_treewidgeteditor.h" + +#include "listwidgeteditor.h" + +#include + +QT_BEGIN_NAMESPACE + +class QTreeWidget; +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class FormWindowBase; +class PropertySheetIconValue; + +class TreeWidgetEditor: public AbstractItemEditor +{ + Q_OBJECT +public: + explicit TreeWidgetEditor(QDesignerFormWindowInterface *form, QDialog *dialog); + + TreeWidgetContents fillContentsFromTreeWidget(QTreeWidget *treeWidget); + TreeWidgetContents contents() const; + +private slots: + void on_newItemButton_clicked(); + void on_newSubItemButton_clicked(); + void on_deleteItemButton_clicked(); + void on_moveItemUpButton_clicked(); + void on_moveItemDownButton_clicked(); + void on_moveItemRightButton_clicked(); + void on_moveItemLeftButton_clicked(); + + void on_treeWidget_currentItemChanged(); + void on_treeWidget_itemChanged(QTreeWidgetItem *item, int column); + + void on_columnEditor_indexChanged(int idx); + void on_columnEditor_itemChanged(int idx, int role, const QVariant &v); + + void on_columnEditor_itemInserted(int idx); + void on_columnEditor_itemDeleted(int idx); + void on_columnEditor_itemMovedUp(int idx); + void on_columnEditor_itemMovedDown(int idx); + + void togglePropertyBrowser(); + void cacheReloaded(); + +protected: + virtual void setItemData(int role, const QVariant &v); + virtual QVariant getItemData(int role) const; + +private: + void setPropertyBrowserVisible(bool v); + QtVariantProperty *setupPropertyGroup(const QString &title, PropertyDefinition *propDefs); + void updateEditor(); + void moveColumnItems(const PropertyDefinition *propList, QTreeWidgetItem *item, int fromColumn, int toColumn, int step); + void moveColumns(int fromColumn, int toColumn, int step); + void moveColumnsLeft(int fromColumn, int toColumn); + void moveColumnsRight(int fromColumn, int toColumn); + void closeEditors(); + + Ui::TreeWidgetEditor ui; + ItemListEditor *m_columnEditor; + bool m_updatingBrowser; +}; + +class TreeWidgetEditorDialog : public QDialog +{ + Q_OBJECT +public: + explicit TreeWidgetEditorDialog(QDesignerFormWindowInterface *form, QWidget *parent); + + TreeWidgetContents fillContentsFromTreeWidget(QTreeWidget *treeWidget); + TreeWidgetContents contents() const; + +private: + TreeWidgetEditor m_editor; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // TREEWIDGETEDITOR_H diff --git a/src/designer/src/components/taskmenu/treewidgeteditor.ui b/src/designer/src/components/taskmenu/treewidgeteditor.ui new file mode 100644 index 000000000..7a71d4404 --- /dev/null +++ b/src/designer/src/components/taskmenu/treewidgeteditor.ui @@ -0,0 +1,257 @@ + + ********************************************************************* +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +********************************************************************* + qdesigner_internal::TreeWidgetEditor + + + + 0 + 0 + 700 + 360 + + + + Edit Tree Widget + + + + + + 0 + + + + &Items + + + + 9 + + + 9 + + + 9 + + + + + + 0 + + + + + Qt::WheelFocus + + + Tree Items + + + + 1 + + + + + + + + + + New Item + + + &New + + + + + + + New Subitem + + + New &Subitem + + + + + + + Delete Item + + + &Delete + + + + + + + Qt::Horizontal + + + + 28 + 23 + + + + + + + + Move Item Left (before Parent Item) + + + L + + + + + + + Move Item Right (as a First Subitem of the Next Sibling Item) + + + R + + + + + + + Move Item Up + + + U + + + + + + + Move Item Down + + + D + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Properties &>> + + + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + qdesigner_internal::TreeWidgetEditor + accept() + + + 440 + 335 + + + 373 + 362 + + + + + buttonBox + rejected() + qdesigner_internal::TreeWidgetEditor + reject() + + + 556 + 335 + + + 562 + 362 + + + + + diff --git a/src/designer/src/components/widgetbox/widgetbox.cpp b/src/designer/src/components/widgetbox/widgetbox.cpp new file mode 100644 index 000000000..c9b0d040a --- /dev/null +++ b/src/designer/src/components/widgetbox/widgetbox.cpp @@ -0,0 +1,235 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "widgetbox.h" +#include "widgetboxtreewidget.h" +#include "widgetbox_dnditem.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +WidgetBox::WidgetBox(QDesignerFormEditorInterface *core, QWidget *parent, Qt::WindowFlags flags) + : QDesignerWidgetBox(parent, flags), + m_core(core), + m_view(new WidgetBoxTreeWidget(m_core)) +{ + + QVBoxLayout *l = new QVBoxLayout(this); + l->setMargin(0); + l->setSpacing(0); + + // Prevent the filter from grabbing focus since Our view has Qt::NoFocus + FilterWidget *filterWidget = new FilterWidget(0, FilterWidget::LayoutAlignNone); + filterWidget->setRefuseFocus(true); + connect(filterWidget, SIGNAL(filterChanged(QString)), m_view, SLOT(filter(QString))); + + QToolBar *toolBar = new QToolBar(this); + toolBar->addWidget(filterWidget); + l->addWidget(toolBar); + + // View + connect(m_view, SIGNAL(pressed(QString,QString,QPoint)), + this, SLOT(handleMousePress(QString,QString,QPoint))); + l->addWidget(m_view); + + setAcceptDrops (true); +} + +WidgetBox::~WidgetBox() +{ +} + +QDesignerFormEditorInterface *WidgetBox::core() const +{ + return m_core; +} + +void WidgetBox::handleMousePress(const QString &name, const QString &xml, const QPoint &global_mouse_pos) +{ + if (QApplication::mouseButtons() != Qt::LeftButton) + return; + + DomUI *ui = xmlToUi(name, xml, true); + if (ui == 0) + return; + QList item_list; + item_list.append(new WidgetBoxDnDItem(core(), ui, global_mouse_pos)); + m_core->formWindowManager()->dragItems(item_list); +} + +int WidgetBox::categoryCount() const +{ + return m_view->categoryCount(); +} + +QDesignerWidgetBoxInterface::Category WidgetBox::category(int cat_idx) const +{ + return m_view->category(cat_idx); +} + +void WidgetBox::addCategory(const Category &cat) +{ + m_view->addCategory(cat); +} + +void WidgetBox::removeCategory(int cat_idx) +{ + m_view->removeCategory(cat_idx); +} + +int WidgetBox::widgetCount(int cat_idx) const +{ + return m_view->widgetCount(cat_idx); +} + +QDesignerWidgetBoxInterface::Widget WidgetBox::widget(int cat_idx, int wgt_idx) const +{ + return m_view->widget(cat_idx, wgt_idx); +} + +void WidgetBox::addWidget(int cat_idx, const Widget &wgt) +{ + m_view->addWidget(cat_idx, wgt); +} + +void WidgetBox::removeWidget(int cat_idx, int wgt_idx) +{ + m_view->removeWidget(cat_idx, wgt_idx); +} + +void WidgetBox::dropWidgets(const QList &item_list, const QPoint&) +{ + m_view->dropWidgets(item_list); +} + +void WidgetBox::setFileName(const QString &file_name) +{ + m_view->setFileName(file_name); +} + +QString WidgetBox::fileName() const +{ + return m_view->fileName(); +} + +bool WidgetBox::load() +{ + return m_view->load(loadMode()); +} + +bool WidgetBox::loadContents(const QString &contents) +{ + return m_view->loadContents(contents); +} + +bool WidgetBox::save() +{ + return m_view->save(); +} + +static const QDesignerMimeData *checkDragEvent(QDropEvent * event, + bool acceptEventsFromWidgetBox) +{ + const QDesignerMimeData *mimeData = qobject_cast(event->mimeData()); + if (!mimeData) { + event->ignore(); + return 0; + } + // If desired, ignore a widget box drag and drop, where widget==0. + if (!acceptEventsFromWidgetBox) { + const bool fromWidgetBox = !mimeData->items().first()->widget(); + if (fromWidgetBox) { + event->ignore(); + return 0; + } + } + + mimeData->acceptEvent(event); + return mimeData; +} + +void WidgetBox::dragEnterEvent (QDragEnterEvent * event) +{ + // We accept event originating from the widget box also here, + // because otherwise Windows will not show the DnD pixmap. + checkDragEvent(event, true); +} + +void WidgetBox::dragMoveEvent(QDragMoveEvent * event) +{ + checkDragEvent(event, true); +} + +void WidgetBox::dropEvent(QDropEvent * event) +{ + const QDesignerMimeData *mimeData = checkDragEvent(event, false); + if (!mimeData) + return; + + dropWidgets(mimeData->items(), event->pos()); + QDesignerMimeData::removeMovedWidgetsFromSourceForm(mimeData->items()); +} + +QIcon WidgetBox::iconForWidget(const QString &className, const QString &category) const +{ + Widget widgetData; + if (!findWidget(this, className, category, &widgetData)) + return QIcon(); + return m_view->iconForWidget(widgetData.iconName()); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/components/widgetbox/widgetbox.h b/src/designer/src/components/widgetbox/widgetbox.h new file mode 100644 index 000000000..a19c756aa --- /dev/null +++ b/src/designer/src/components/widgetbox/widgetbox.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WIDGETBOX_H +#define WIDGETBOX_H + +#include "widgetbox_global.h" +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + +class WidgetBoxTreeWidget; + +class QT_WIDGETBOX_EXPORT WidgetBox : public QDesignerWidgetBox +{ + Q_OBJECT +public: + explicit WidgetBox(QDesignerFormEditorInterface *core, QWidget *parent = 0, Qt::WindowFlags flags = 0); + virtual ~WidgetBox(); + + QDesignerFormEditorInterface *core() const; + + virtual int categoryCount() const; + virtual Category category(int cat_idx) const; + virtual void addCategory(const Category &cat); + virtual void removeCategory(int cat_idx); + + virtual int widgetCount(int cat_idx) const; + virtual Widget widget(int cat_idx, int wgt_idx) const; + virtual void addWidget(int cat_idx, const Widget &wgt); + virtual void removeWidget(int cat_idx, int wgt_idx); + + void dropWidgets(const QList &item_list, const QPoint &global_mouse_pos); + + virtual void setFileName(const QString &file_name); + virtual QString fileName() const; + virtual bool load(); + virtual bool save(); + + virtual bool loadContents(const QString &contents); + virtual QIcon iconForWidget(const QString &className, const QString &category = QString()) const; + +protected: + virtual void dragEnterEvent (QDragEnterEvent * event); + virtual void dragMoveEvent(QDragMoveEvent * event); + virtual void dropEvent (QDropEvent * event); + +private slots: + void handleMousePress(const QString &name, const QString &xml, const QPoint &global_mouse_pos); + +private: + QDesignerFormEditorInterface *m_core; + WidgetBoxTreeWidget *m_view; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // WIDGETBOX_H diff --git a/src/designer/src/components/widgetbox/widgetbox.pri b/src/designer/src/components/widgetbox/widgetbox.pri new file mode 100644 index 000000000..dd8ad002e --- /dev/null +++ b/src/designer/src/components/widgetbox/widgetbox.pri @@ -0,0 +1,14 @@ + +INCLUDEPATH += $$PWD + +SOURCES += $$PWD/widgetboxcategorylistview.cpp \ + $$PWD/widgetboxtreewidget.cpp \ + $$PWD/widgetbox.cpp \ + $$PWD/widgetbox_dnditem.cpp +HEADERS += $$PWD/widgetboxcategorylistview.h \ + $$PWD/widgetboxtreewidget.h \ + $$PWD/widgetbox.h \ + $$PWD/widgetbox_global.h \ + $$PWD/widgetbox_dnditem.h + +RESOURCES += $$PWD/widgetbox.qrc diff --git a/src/designer/src/components/widgetbox/widgetbox.qrc b/src/designer/src/components/widgetbox/widgetbox.qrc new file mode 100644 index 000000000..7ecf78c85 --- /dev/null +++ b/src/designer/src/components/widgetbox/widgetbox.qrc @@ -0,0 +1,5 @@ + + + widgetbox.xml + + diff --git a/src/designer/src/components/widgetbox/widgetbox.xml b/src/designer/src/components/widgetbox/widgetbox.xml new file mode 100644 index 000000000..4286e0d6c --- /dev/null +++ b/src/designer/src/components/widgetbox/widgetbox.xml @@ -0,0 +1,932 @@ + + + + + + + + + + verticalLayoutWidget + + + + 0 + 0 + 160 + 80 + + + + + + + + + + + + + horizontalLayoutWidget + + + + 0 + 0 + 160 + 80 + + + + + + + + + + + + + gridLayoutWidget + + + + 0 + 0 + 160 + 80 + + + + + + + + + + + + + formLayoutWidget + + + + 0 + 0 + 160 + 80 + + + + + + + + + + + + + + + + + Qt::Horizontal + + + horizontalSpacer + + + + 40 + 20 + + + + + + + + + + + Qt::Vertical + + + verticalSpacer + + + + 20 + 40 + + + + + + + + + + + + + + + PushButton + + + pushButton + + + + + + + + + + toolButton + + + ... + + + + + + + + + + RadioButton + + + radioButton + + + + + + + + + + CheckBox + + + checkBox + + + + + + + + + + CommandLinkButton + + + commandLinkButton + + + + + + + + + + QDialogButtonBox::Ok|QDialogButtonBox::Cancel + + + buttonBox + + + + + + + + + + + + + + listView + + + + + + + + + + treeView + + + + + + + + + + tableView + + + + + + + + + + columnView + + + + + + + + + + + + + listWidget + + + + + + + + + + treeWidget + + + + + + + + + + tableWidget + + + + + + + + + + + + + + GroupBox + + + + 0 + 0 + 120 + 80 + + + + groupBox + + + + + + + + + + scrollArea + + + true + + + + 0 + 0 + 120 + 80 + + + + + + + + + + + + + 0 + + + toolBox + + + + Page 1 + + + + + Page 2 + + + + + + + + + + + + 0 + 0 + 120 + 80 + + + + tabWidget + + + + Tab 1 + + + + + Tab 2 + + + + + + + + + + + + 0 + 0 + 120 + 80 + + + + stackedWidget + + + + + + + + + + + + QFrame::Raised + + + + 0 + 0 + 120 + 80 + + + + QFrame::StyledPanel + + + frame + + + + + + + + + + + 0 + 0 + 120 + 80 + + + + widget + + + + + + + + + + + 0 + 0 + 200 + 160 + + + + mdiArea + + + + + + + + + + + 0 + 0 + 120 + 80 + + + + dockWidget + + + + + + + + + + + + + + + + 119 + 28 + 41 + 22 + + + + comboBox + + + + + + + + + + + 119 + 28 + 41 + 22 + + + + fontComboBox + + + + + + + + + + + 0 + 1 + 113 + 20 + + + + lineEdit + + + + + + + + + + textEdit + + + + 0 + 0 + 104 + 64 + + + + + + + + + + + plainTextEdit + + + + 0 + 0 + 104 + 64 + + + + + + + + + + + + 119 + 0 + 42 + 22 + + + + spinBox + + + + + + + + + + + 119 + 0 + 62 + 22 + + + + doubleSpinBox + + + + + + + + + + + 0 + 28 + 118 + 22 + + + + timeEdit + + + + + + + + + + + 0 + 28 + 110 + 22 + + + + dateEdit + + + + + + + + + + + 0 + 28 + 194 + 22 + + + + dateTimeEdit + + + + + + + + + + + 110 + 0 + 50 + 64 + + + + dial + + + + + + + + + + Qt::Horizontal + + + + 0 + 126 + 160 + 16 + + + + horizontalScrollBar + + + + + + + + + + Qt::Vertical + + + + 0 + 126 + 16 + 160 + + + + verticalScrollBar + + + + + + + + + + Qt::Horizontal + + + + 0 + 126 + 160 + 16 + + + + horizontalSlider + + + + + + + + + + Qt::Vertical + + + + 0 + 126 + 16 + 160 + + + + verticalSlider + + + + + + + + + + + + + + + TextLabel + + + label + + + + + + + + + + textBrowser + + + + + + + + + + graphicsView + + + + + + + + + + calendarWidget + + + + + + + + + + lcdNumber + + + + + + + + + + 24 + + + + 9 + 38 + 118 + 23 + + + + progressBar + + + + + + + + + + Qt::Horizontal + + + line + + + + 9 + 67 + 118 + 3 + + + + + + + + + + + Qt::Vertical + + + line + + + + 133 + 9 + 3 + 61 + + + + + + + + diff --git a/src/designer/src/components/widgetbox/widgetbox_dnditem.cpp b/src/designer/src/components/widgetbox/widgetbox_dnditem.cpp new file mode 100644 index 000000000..c122c8411 --- /dev/null +++ b/src/designer/src/components/widgetbox/widgetbox_dnditem.cpp @@ -0,0 +1,225 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "widgetbox_dnditem.h" +#include "ui4_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { +/******************************************************************************* +** WidgetBoxResource +*/ + +static inline DeviceProfile currentDeviceProfile(const QDesignerFormEditorInterface *core) +{ + if (QDesignerFormWindowInterface *cfw = core->formWindowManager()->activeFormWindow()) + if (const FormWindowBase *fwb = qobject_cast(cfw)) + return fwb->deviceProfile(); + return DeviceProfile(); +} + +class WidgetBoxResource : public QDesignerFormBuilder +{ +public: + WidgetBoxResource(QDesignerFormEditorInterface *core); + + // protected->public + QWidget *createUI(DomUI *ui, QWidget *parents) { return QDesignerFormBuilder::create(ui, parents); } + +protected: + + virtual QWidget *create(DomWidget *ui_widget, QWidget *parents); + virtual QWidget *createWidget(const QString &widgetName, QWidget *parentWidget, const QString &name); + virtual void createCustomWidgets(DomCustomWidgets *); +}; + +WidgetBoxResource::WidgetBoxResource(QDesignerFormEditorInterface *core) : + QDesignerFormBuilder(core, DisableScripts, currentDeviceProfile(core)) +{ +} + + +QWidget *WidgetBoxResource::createWidget(const QString &widgetName, QWidget *parentWidget, const QString &name) +{ + if (widgetName == QLatin1String("Spacer")) { + Spacer *spacer = new Spacer(parentWidget); + spacer->setObjectName(name); + return spacer; + } + + return QDesignerFormBuilder::createWidget(widgetName, parentWidget, name); +} + +QWidget *WidgetBoxResource::create(DomWidget *ui_widget, QWidget *parent) +{ + QWidget *result = QDesignerFormBuilder::create(ui_widget, parent); + // It is possible to have a syntax error or something in custom + // widget XML, so, try to recover here by creating an artificial + // top level + widget. + if (!result) { + const QString msg = QApplication::translate("qdesigner_internal::WidgetBox", "Warning: Widget creation failed in the widget box. This could be caused by invalid custom widget XML."); + qdesigner_internal::designerWarning(msg); + result = new QWidget(parent); + new QWidget(result); + } + result->setFocusPolicy(Qt::NoFocus); + result->setObjectName(ui_widget->attributeName()); + return result; +} + +void WidgetBoxResource::createCustomWidgets(DomCustomWidgets *dc) +{ + // Make a promotion entry in case someone has a promoted widget + // in the scratchpad. + QSimpleResource::handleDomCustomWidgets(core(), dc); + +} + +/******************************************************************************* +** WidgetBoxResource +*/ + +static QSize geometryProp(const DomWidget *dw) +{ + const QList prop_list = dw->elementProperty(); + const QString geometry = QLatin1String("geometry"); + foreach (DomProperty *prop, prop_list) { + if (prop->attributeName() != geometry) + continue; + DomRect *dr = prop->elementRect(); + if (dr == 0) + continue; + return QSize(dr->elementWidth(), dr->elementHeight()); + } + return QSize(); +} + +static QSize domWidgetSize(const DomWidget *dw) +{ + QSize size = geometryProp(dw); + if (size.isValid()) + return size; + + foreach (const DomWidget *child, dw->elementWidget()) { + size = geometryProp(child); + if (size.isValid()) + return size; + } + + foreach (const DomLayout *dl, dw->elementLayout()) { + foreach (DomLayoutItem *item, dl->elementItem()) { + const DomWidget *child = item->elementWidget(); + if (child == 0) + continue; + size = geometryProp(child); + if (size.isValid()) + return size; + } + } + + return QSize(); +} + +static QWidget *decorationFromDomWidget(DomUI *dom_ui, QDesignerFormEditorInterface *core) +{ + WidgetBoxResource builder(core); + // We have the builder create the articial QWidget fake top level as a tooltip + // because the size algorithm works better at weird DPI settings + // if the actual widget is created as a child of a container + QWidget *fakeTopLevel = builder.createUI(dom_ui, static_cast(0)); + fakeTopLevel->setParent(0, Qt::ToolTip); // Container + // Actual widget + const DomWidget *domW = dom_ui->elementWidget()->elementWidget().front(); + QWidget *w = fakeTopLevel->findChildren().front(); + Q_ASSERT(w); + // hack begin; + // We set _q_dockDrag dynamic property which will be detected in drag enter event of form window. + // Dock drop is handled in special way (highlight goes to central widget of main window) + if (qobject_cast(w)) + fakeTopLevel->setProperty("_q_dockDrag", QVariant(true)); + // hack end; + w->setAutoFillBackground(true); // Different style for embedded + QSize size = domWidgetSize(domW); + const QSize minimumSize = w->minimumSizeHint(); + if (!size.isValid()) + size = w->sizeHint(); + if (size.width() < minimumSize.width()) + size.setWidth(minimumSize.width()); + if (size.height() < minimumSize.height()) + size.setHeight(minimumSize.height()); + // A QWidget might have size -1,-1 if no geometry property is specified in the widget box. + if (size.isEmpty()) + size = size.expandedTo(QSize(16, 16)); + w->setGeometry(QRect(QPoint(0, 0), size)); + fakeTopLevel->resize(size); + return fakeTopLevel; +} + +WidgetBoxDnDItem::WidgetBoxDnDItem(QDesignerFormEditorInterface *core, + DomUI *dom_ui, + const QPoint &global_mouse_pos) : + QDesignerDnDItem(CopyDrop) +{ + QWidget *decoration = decorationFromDomWidget(dom_ui, core); + decoration->move(global_mouse_pos - QPoint(5, 5)); + + init(dom_ui, 0, decoration, global_mouse_pos); +} +} + +QT_END_NAMESPACE diff --git a/src/designer/src/components/widgetbox/widgetbox_dnditem.h b/src/designer/src/components/widgetbox/widgetbox_dnditem.h new file mode 100644 index 000000000..010cedc03 --- /dev/null +++ b/src/designer/src/components/widgetbox/widgetbox_dnditem.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WIDGETBOX_DNDITEM_H +#define WIDGETBOX_DNDITEM_H + +#include +#include "widgetbox_global.h" + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class DomUI; + +namespace qdesigner_internal { + +class QT_WIDGETBOX_EXPORT WidgetBoxDnDItem : public QDesignerDnDItem +{ +public: + WidgetBoxDnDItem(QDesignerFormEditorInterface *core, + DomUI *dom_ui, + const QPoint &global_mouse_pos); +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // WIDGETBOX_DNDITEM_H diff --git a/src/designer/src/components/widgetbox/widgetbox_global.h b/src/designer/src/components/widgetbox/widgetbox_global.h new file mode 100644 index 000000000..0d550c748 --- /dev/null +++ b/src/designer/src/components/widgetbox/widgetbox_global.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WIDGETBOX_GLOBAL_H +#define WIDGETBOX_GLOBAL_H + +#include + +#ifdef Q_OS_WIN +#ifdef QT_WIDGETBOX_LIBRARY +# define QT_WIDGETBOX_EXPORT +#else +# define QT_WIDGETBOX_EXPORT +#endif +#else +#define QT_WIDGETBOX_EXPORT +#endif + +#endif // WIDGETBOX_GLOBAL_H diff --git a/src/designer/src/components/widgetbox/widgetboxcategorylistview.cpp b/src/designer/src/components/widgetbox/widgetboxcategorylistview.cpp new file mode 100644 index 000000000..d2a0d43c0 --- /dev/null +++ b/src/designer/src/components/widgetbox/widgetboxcategorylistview.cpp @@ -0,0 +1,510 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "widgetboxcategorylistview.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static const char *widgetElementC = "widget"; +static const char *nameAttributeC = "name"; +static const char *uiOpeningTagC = ""; +static const char *uiClosingTagC = ""; + +QT_BEGIN_NAMESPACE + +enum { FilterRole = Qt::UserRole + 11 }; + +static QString domToString(const QDomElement &elt) +{ + QString result; + QTextStream stream(&result, QIODevice::WriteOnly); + elt.save(stream, 2); + stream.flush(); + return result; +} + +static QDomDocument stringToDom(const QString &xml) +{ + QDomDocument result; + result.setContent(xml); + return result; +} + +namespace qdesigner_internal { + +// Entry of the model list + +struct WidgetBoxCategoryEntry { + WidgetBoxCategoryEntry(); + explicit WidgetBoxCategoryEntry(const QDesignerWidgetBoxInterface::Widget &widget, + const QString &filter, + const QIcon &icon, + bool editable); + + QDesignerWidgetBoxInterface::Widget widget; + QString toolTip; + QString whatsThis; + QString filter; + QIcon icon; + bool editable; +}; + + +WidgetBoxCategoryEntry::WidgetBoxCategoryEntry() : + editable(false) +{ +} + +WidgetBoxCategoryEntry::WidgetBoxCategoryEntry(const QDesignerWidgetBoxInterface::Widget &w, + const QString &filterIn, + const QIcon &i, bool e) : + widget(w), + filter(filterIn), + icon(i), + editable(e) +{ +} + +/* WidgetBoxCategoryModel, representing a list of category entries. Uses a + * QAbstractListModel since the behaviour depends on the view mode of the list + * view, it does not return text in the case of IconMode. */ + +class WidgetBoxCategoryModel : public QAbstractListModel { +public: + explicit WidgetBoxCategoryModel(QDesignerFormEditorInterface *core, QObject *parent = 0); + + // QAbstractListModel + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual bool setData(const QModelIndex & index, const QVariant & value, int role = Qt::EditRole); + virtual Qt::ItemFlags flags (const QModelIndex & index ) const; + virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()); + + // The model returns no text in icon mode, so, it also needs to know it + QListView::ViewMode viewMode() const; + void setViewMode(QListView::ViewMode vm); + + void addWidget(const QDesignerWidgetBoxInterface::Widget &widget, const QIcon &icon, bool editable); + + QDesignerWidgetBoxInterface::Widget widgetAt(const QModelIndex & index) const; + QDesignerWidgetBoxInterface::Widget widgetAt(int row) const; + + int indexOfWidget(const QString &name); + + QDesignerWidgetBoxInterface::Category category() const; + bool removeCustomWidgets(); + +private: + typedef QList WidgetBoxCategoryEntrys; + + QRegExp m_classNameRegExp; + QDesignerFormEditorInterface *m_core; + WidgetBoxCategoryEntrys m_items; + QListView::ViewMode m_viewMode; +}; + +WidgetBoxCategoryModel::WidgetBoxCategoryModel(QDesignerFormEditorInterface *core, QObject *parent) : + QAbstractListModel(parent), + m_classNameRegExp(QLatin1String("widget); + return rc; +} + +bool WidgetBoxCategoryModel::removeCustomWidgets() +{ + // Typically, we are a whole category of custom widgets, so, remove all + // and do reset. + bool changed = false; + for (WidgetBoxCategoryEntrys::iterator it = m_items.begin(); it != m_items.end(); ) + if (it->widget.type() == QDesignerWidgetBoxInterface::Widget::Custom) { + it = m_items.erase(it); + changed = true; + } else { + ++it; + } + if (changed) + reset(); + return changed; +} + +void WidgetBoxCategoryModel::addWidget(const QDesignerWidgetBoxInterface::Widget &widget, const QIcon &icon,bool editable) +{ + // build item. Filter on name + class name if it is different and not a layout. + QString filter = widget.name(); + if (!filter.contains(QLatin1String("Layout")) && m_classNameRegExp.indexIn(widget.domXml()) != -1) { + const QString className = m_classNameRegExp.cap(1); + if (!filter.contains(className)) + filter += className; + } + WidgetBoxCategoryEntry item(widget, filter, icon, editable); + const QDesignerWidgetDataBaseInterface *db = m_core->widgetDataBase(); + const int dbIndex = db->indexOfClassName(widget.name()); + if (dbIndex != -1) { + const QDesignerWidgetDataBaseItemInterface *dbItem = db->item(dbIndex); + const QString toolTip = dbItem->toolTip(); + if (!toolTip.isEmpty()) + item.toolTip = toolTip; + const QString whatsThis = dbItem->whatsThis(); + if (!whatsThis.isEmpty()) + item.whatsThis = whatsThis; + } + // insert + const int row = m_items.size(); + beginInsertRows(QModelIndex(), row, row); + m_items.push_back(item); + endInsertRows(); +} + +QVariant WidgetBoxCategoryModel::data(const QModelIndex &index, int role) const +{ + const int row = index.row(); + if (row < 0 || row >= m_items.size()) + return QVariant(); + + const WidgetBoxCategoryEntry &item = m_items.at(row); + switch (role) { + case Qt::DisplayRole: + // No text in icon mode + return QVariant(m_viewMode == QListView::ListMode ? item.widget.name() : QString()); + case Qt::DecorationRole: + return QVariant(item.icon); + case Qt::EditRole: + return QVariant(item.widget.name()); + case Qt::ToolTipRole: { + if (m_viewMode == QListView::ListMode) + return QVariant(item.toolTip); + // Icon mode tooltip should contain the class name + QString tt = item.widget.name(); + if (!item.toolTip.isEmpty()) { + tt += QLatin1Char('\n'); + tt += item.toolTip; + } + return QVariant(tt); + + } + case Qt::WhatsThisRole: + return QVariant(item.whatsThis); + case FilterRole: + return item.filter; + } + return QVariant(); +} + +bool WidgetBoxCategoryModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + const int row = index.row(); + if (role != Qt::EditRole || row < 0 || row >= m_items.size() || value.type() != QVariant::String) + return false; + // Set name and adapt Xml + WidgetBoxCategoryEntry &item = m_items[row]; + const QString newName = value.toString(); + item.widget.setName(newName); + + const QDomDocument doc = stringToDom(WidgetBoxCategoryListView::widgetDomXml(item.widget)); + QDomElement widget_elt = doc.firstChildElement(QLatin1String(widgetElementC)); + if (!widget_elt.isNull()) { + widget_elt.setAttribute(QLatin1String(nameAttributeC), newName); + item.widget.setDomXml(domToString(widget_elt)); + } + emit dataChanged(index, index); + return true; +} + +Qt::ItemFlags WidgetBoxCategoryModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags rc = Qt::ItemIsEnabled; + const int row = index.row(); + if (row >= 0 && row < m_items.size()) + if (m_items.at(row).editable) { + rc |= Qt::ItemIsSelectable; + // Can change name in list mode only + if (m_viewMode == QListView::ListMode) + rc |= Qt::ItemIsEditable; + } + return rc; +} + +int WidgetBoxCategoryModel::rowCount(const QModelIndex & /*parent*/) const +{ + return m_items.size(); +} + +bool WidgetBoxCategoryModel::removeRows(int row, int count, const QModelIndex & parent) +{ + if (row < 0 || count < 1) + return false; + const int size = m_items.size(); + const int last = row + count - 1; + if (row >= size || last >= size) + return false; + beginRemoveRows(parent, row, last); + for (int r = last; r >= row; r--) + m_items.removeAt(r); + endRemoveRows(); + return true; +} + +QDesignerWidgetBoxInterface::Widget WidgetBoxCategoryModel::widgetAt(const QModelIndex & index) const +{ + return widgetAt(index.row()); +} + +QDesignerWidgetBoxInterface::Widget WidgetBoxCategoryModel::widgetAt(int row) const +{ + if (row < 0 || row >= m_items.size()) + return QDesignerWidgetBoxInterface::Widget(); + return m_items.at(row).widget; +} + +/* WidgetSubBoxItemDelegate, ensures a valid name using a regexp validator */ + +class WidgetBoxCategoryEntryDelegate : public QItemDelegate +{ +public: + explicit WidgetBoxCategoryEntryDelegate(QWidget *parent = 0) : QItemDelegate(parent) {} + QWidget *createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const; +}; + +QWidget *WidgetBoxCategoryEntryDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + QWidget *result = QItemDelegate::createEditor(parent, option, index); + if (QLineEdit *line_edit = qobject_cast(result)) { + const QRegExp re = QRegExp(QLatin1String("[_a-zA-Z][_a-zA-Z0-9]*")); + Q_ASSERT(re.isValid()); + line_edit->setValidator(new QRegExpValidator(re, line_edit)); + } + return result; +} + +// ---------------------- WidgetBoxCategoryListView + +WidgetBoxCategoryListView::WidgetBoxCategoryListView(QDesignerFormEditorInterface *core, QWidget *parent) : + QListView(parent), + m_proxyModel(new QSortFilterProxyModel(this)), + m_model(new WidgetBoxCategoryModel(core, this)) +{ + setFocusPolicy(Qt::NoFocus); + setFrameShape(QFrame::NoFrame); + setIconSize(QSize(22, 22)); + setSpacing(1); + setTextElideMode(Qt::ElideMiddle); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setResizeMode(QListView::Adjust); + setUniformItemSizes(true); + + setItemDelegate(new WidgetBoxCategoryEntryDelegate(this)); + + connect(this, SIGNAL(pressed(QModelIndex)), this, SLOT(slotPressed(QModelIndex))); + setEditTriggers(QAbstractItemView::AnyKeyPressed); + + m_proxyModel->setSourceModel(m_model); + m_proxyModel->setFilterRole(FilterRole); + setModel(m_proxyModel); + connect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SIGNAL(scratchPadChanged())); +} + +void WidgetBoxCategoryListView::setViewMode(ViewMode vm) +{ + QListView::setViewMode(vm); + m_model->setViewMode(vm); +} + +void WidgetBoxCategoryListView::setCurrentItem(AccessMode am, int row) +{ + const QModelIndex index = am == FilteredAccess ? + m_proxyModel->index(row, 0) : + m_proxyModel->mapFromSource(m_model->index(row, 0)); + + if (index.isValid()) + setCurrentIndex(index); +} + +void WidgetBoxCategoryListView::slotPressed(const QModelIndex &index) +{ + const QDesignerWidgetBoxInterface::Widget wgt = m_model->widgetAt(m_proxyModel->mapToSource(index)); + if (wgt.isNull()) + return; + emit pressed(wgt.name(), widgetDomXml(wgt), QCursor::pos()); +} + +void WidgetBoxCategoryListView::removeCurrentItem() +{ + const QModelIndex index = currentIndex(); + if (!index.isValid() || !m_proxyModel->removeRow(index.row())) + return; + + // We check the unfiltered item count here, we don't want to get removed if the + // filtered view is empty + if (m_model->rowCount()) { + emit itemRemoved(); + } else { + emit lastItemRemoved(); + } +} + +void WidgetBoxCategoryListView::editCurrentItem() +{ + const QModelIndex index = currentIndex(); + if (index.isValid()) + edit(index); +} + +int WidgetBoxCategoryListView::count(AccessMode am) const +{ + return am == FilteredAccess ? m_proxyModel->rowCount() : m_model->rowCount(); +} + +int WidgetBoxCategoryListView::mapRowToSource(int filterRow) const +{ + const QModelIndex filterIndex = m_proxyModel->index(filterRow, 0); + return m_proxyModel->mapToSource(filterIndex).row(); +} + +QDesignerWidgetBoxInterface::Widget WidgetBoxCategoryListView::widgetAt(AccessMode am, const QModelIndex & index) const +{ + const QModelIndex unfilteredIndex = am == FilteredAccess ? m_proxyModel->mapToSource(index) : index; + return m_model->widgetAt(unfilteredIndex); +} + +QDesignerWidgetBoxInterface::Widget WidgetBoxCategoryListView::widgetAt(AccessMode am, int row) const +{ + return m_model->widgetAt(am == UnfilteredAccess ? row : mapRowToSource(row)); +} + +void WidgetBoxCategoryListView::removeRow(AccessMode am, int row) +{ + m_model->removeRow(am == UnfilteredAccess ? row : mapRowToSource(row)); +} + +bool WidgetBoxCategoryListView::containsWidget(const QString &name) +{ + return m_model->indexOfWidget(name) != -1; +} + +void WidgetBoxCategoryListView::addWidget(const QDesignerWidgetBoxInterface::Widget &widget, const QIcon &icon, bool editable) +{ + m_model->addWidget(widget, icon, editable); +} + +QString WidgetBoxCategoryListView::widgetDomXml(const QDesignerWidgetBoxInterface::Widget &widget) +{ + QString domXml = widget.domXml(); + + if (domXml.isEmpty()) { + domXml = QLatin1String(uiOpeningTagC); + domXml += QLatin1String(""); + domXml += QLatin1String(uiClosingTagC); + } + return domXml; +} + +void WidgetBoxCategoryListView::filter(const QRegExp &re) +{ + m_proxyModel->setFilterRegExp(re); +} + +QDesignerWidgetBoxInterface::Category WidgetBoxCategoryListView::category() const +{ + return m_model->category(); +} + +bool WidgetBoxCategoryListView::removeCustomWidgets() +{ + return m_model->removeCustomWidgets(); +} +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/components/widgetbox/widgetboxcategorylistview.h b/src/designer/src/components/widgetbox/widgetboxcategorylistview.h new file mode 100644 index 000000000..5e6df1149 --- /dev/null +++ b/src/designer/src/components/widgetbox/widgetboxcategorylistview.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WIDGETBOXCATEGORYLISTVIEW_H +#define WIDGETBOXCATEGORYLISTVIEW_H + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerDnDItemInterface; + +class QSortFilterProxyModel; +class QRegExp; + +namespace qdesigner_internal { + +class WidgetBoxCategoryModel; + +// List view of a category, switchable between icon and list mode. +// Provides a filtered view. +class WidgetBoxCategoryListView : public QListView +{ + Q_OBJECT +public: + // Whether to access the filtered or unfiltered view + enum AccessMode { FilteredAccess, UnfilteredAccess }; + + explicit WidgetBoxCategoryListView(QDesignerFormEditorInterface *core, QWidget *parent = 0); + void setViewMode(ViewMode vm); + + void dropWidgets(const QList &item_list); + + using QListView::contentsSize; + + // These methods operate on the filtered/unfiltered model according to accessmode + int count(AccessMode am) const; + QDesignerWidgetBoxInterface::Widget widgetAt(AccessMode am, const QModelIndex &index) const; + QDesignerWidgetBoxInterface::Widget widgetAt(AccessMode am, int row) const; + void removeRow(AccessMode am, int row); + void setCurrentItem(AccessMode am, int row); + + // These methods operate on the unfiltered model and are used for serialization + void addWidget(const QDesignerWidgetBoxInterface::Widget &widget, const QIcon &icon, bool editable); + bool containsWidget(const QString &name); + QDesignerWidgetBoxInterface::Category category() const; + bool removeCustomWidgets(); + + // Helper: Ensure a tag in the case of empty XML + static QString widgetDomXml(const QDesignerWidgetBoxInterface::Widget &widget); + +signals: + void scratchPadChanged(); + void pressed(const QString &name, const QString &xml, const QPoint &globalPos); + void itemRemoved(); + void lastItemRemoved(); + +public slots: + void filter(const QRegExp &re); + +private slots: + void slotPressed(const QModelIndex &index); + void removeCurrentItem(); + void editCurrentItem(); + +private: + int mapRowToSource(int filterRow) const; + QSortFilterProxyModel *m_proxyModel; + WidgetBoxCategoryModel *m_model; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // WIDGETBOXCATEGORYLISTVIEW_H diff --git a/src/designer/src/components/widgetbox/widgetboxtreewidget.cpp b/src/designer/src/components/widgetbox/widgetboxtreewidget.cpp new file mode 100644 index 000000000..f4b567b69 --- /dev/null +++ b/src/designer/src/components/widgetbox/widgetboxtreewidget.cpp @@ -0,0 +1,1001 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "widgetboxtreewidget.h" +#include "widgetboxcategorylistview.h" + +// shared +#include +#include +#include +#include +#include +#include + +// sdk +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static const char *widgetBoxRootElementC = "widgetbox"; +static const char *widgetElementC = "widget"; +static const char *uiElementC = "ui"; +static const char *categoryElementC = "category"; +static const char *categoryEntryElementC = "categoryentry"; +static const char *nameAttributeC = "name"; +static const char *typeAttributeC = "type"; +static const char *iconAttributeC = "icon"; +static const char *defaultTypeValueC = "default"; +static const char *customValueC = "custom"; +static const char *iconPrefixC = "__qt_icon__"; +static const char *scratchPadValueC = "scratchpad"; +static const char *qtLogoC = "qtlogo.png"; +static const char *invisibleNameC = "[invisible]"; + +enum TopLevelRole { NORMAL_ITEM, SCRATCHPAD_ITEM, CUSTOM_ITEM }; + +QT_BEGIN_NAMESPACE + +static void setTopLevelRole(TopLevelRole tlr, QTreeWidgetItem *item) +{ + item->setData(0, Qt::UserRole, QVariant(tlr)); +} + +static TopLevelRole topLevelRole(const QTreeWidgetItem *item) +{ + return static_cast(item->data(0, Qt::UserRole).toInt()); +} + +namespace qdesigner_internal { + +WidgetBoxTreeWidget::WidgetBoxTreeWidget(QDesignerFormEditorInterface *core, QWidget *parent) : + QTreeWidget(parent), + m_core(core), + m_iconMode(false), + m_scratchPadDeleteTimer(0) +{ + setFocusPolicy(Qt::NoFocus); + setIndentation(0); + setRootIsDecorated(false); + setColumnCount(1); + header()->hide(); + header()->setResizeMode(QHeaderView::Stretch); + setTextElideMode(Qt::ElideMiddle); + setVerticalScrollMode(ScrollPerPixel); + + setItemDelegate(new SheetDelegate(this, this)); + + connect(this, SIGNAL(itemPressed(QTreeWidgetItem*,int)), + this, SLOT(handleMousePress(QTreeWidgetItem*))); +} + +QIcon WidgetBoxTreeWidget::iconForWidget(QString iconName) const +{ + if (iconName.isEmpty()) + iconName = QLatin1String(qtLogoC); + + if (iconName.startsWith(QLatin1String(iconPrefixC))) { + const IconCache::const_iterator it = m_pluginIcons.constFind(iconName); + if (it != m_pluginIcons.constEnd()) + return it.value(); + } + return createIconSet(iconName); +} + +WidgetBoxCategoryListView *WidgetBoxTreeWidget::categoryViewAt(int idx) const +{ + WidgetBoxCategoryListView *rc = 0; + if (QTreeWidgetItem *cat_item = topLevelItem(idx)) + if (QTreeWidgetItem *embedItem = cat_item->child(0)) + rc = qobject_cast(itemWidget(embedItem, 0)); + Q_ASSERT(rc); + return rc; +} + +void WidgetBoxTreeWidget::saveExpandedState() const +{ + QStringList closedCategories; + if (const int numCategories = categoryCount()) { + for (int i = 0; i < numCategories; ++i) { + const QTreeWidgetItem *cat_item = topLevelItem(i); + if (!isItemExpanded(cat_item)) + closedCategories.append(cat_item->text(0)); + } + } + QDesignerSettingsInterface *settings = m_core->settingsManager(); + settings->beginGroup(QLatin1String(widgetBoxRootElementC)); + settings->setValue(QLatin1String("Closed categories"), closedCategories); + settings->setValue(QLatin1String("View mode"), m_iconMode); + settings->endGroup(); +} + +void WidgetBoxTreeWidget::restoreExpandedState() +{ + typedef QSet StringSet; + QDesignerSettingsInterface *settings = m_core->settingsManager(); + m_iconMode = settings->value(QLatin1String("WidgetBox/View mode")).toBool(); + updateViewMode(); + const StringSet closedCategories = settings->value(QLatin1String("WidgetBox/Closed categories"), QStringList()).toStringList().toSet(); + expandAll(); + if (closedCategories.empty()) + return; + + if (const int numCategories = categoryCount()) { + for (int i = 0; i < numCategories; ++i) { + QTreeWidgetItem *item = topLevelItem(i); + if (closedCategories.contains(item->text(0))) + item->setExpanded(false); + } + } +} + +WidgetBoxTreeWidget::~WidgetBoxTreeWidget() +{ + saveExpandedState(); +} + +void WidgetBoxTreeWidget::setFileName(const QString &file_name) +{ + m_file_name = file_name; +} + +QString WidgetBoxTreeWidget::fileName() const +{ + return m_file_name; +} + +bool WidgetBoxTreeWidget::save() +{ + if (fileName().isEmpty()) + return false; + + QFile file(fileName()); + if (!file.open(QIODevice::WriteOnly)) + return false; + + CategoryList cat_list; + const int count = categoryCount(); + for (int i = 0; i < count; ++i) + cat_list.append(category(i)); + + QXmlStreamWriter writer(&file); + writer.setAutoFormatting(true); + writer.setAutoFormattingIndent(1); + writer.writeStartDocument(); + writeCategories(writer, cat_list); + writer.writeEndDocument(); + + return true; +} + +void WidgetBoxTreeWidget::slotSave() +{ + save(); +} + +void WidgetBoxTreeWidget::handleMousePress(QTreeWidgetItem *item) +{ + if (item == 0) + return; + + if (QApplication::mouseButtons() != Qt::LeftButton) + return; + + if (item->parent() == 0) { + setItemExpanded(item, !isItemExpanded(item)); + return; + } +} + +int WidgetBoxTreeWidget::ensureScratchpad() +{ + const int existingIndex = indexOfScratchpad(); + if (existingIndex != -1) + return existingIndex; + + QTreeWidgetItem *scratch_item = new QTreeWidgetItem(this); + scratch_item->setText(0, tr("Scratchpad")); + setTopLevelRole(SCRATCHPAD_ITEM, scratch_item); + addCategoryView(scratch_item, false); // Scratchpad in list mode. + return categoryCount() - 1; +} + +WidgetBoxCategoryListView *WidgetBoxTreeWidget::addCategoryView(QTreeWidgetItem *parent, bool iconMode) +{ + QTreeWidgetItem *embed_item = new QTreeWidgetItem(parent); + embed_item->setFlags(Qt::ItemIsEnabled); + WidgetBoxCategoryListView *categoryView = new WidgetBoxCategoryListView(m_core, this); + categoryView->setViewMode(iconMode ? QListView::IconMode : QListView::ListMode); + connect(categoryView, SIGNAL(scratchPadChanged()), this, SLOT(slotSave())); + connect(categoryView, SIGNAL(pressed(QString,QString,QPoint)), this, SIGNAL(pressed(QString,QString,QPoint))); + connect(categoryView, SIGNAL(itemRemoved()), this, SLOT(slotScratchPadItemDeleted())); + connect(categoryView, SIGNAL(lastItemRemoved()), this, SLOT(slotLastScratchPadItemDeleted())); + setItemWidget(embed_item, 0, categoryView); + return categoryView; +} + +int WidgetBoxTreeWidget::indexOfScratchpad() const +{ + if (const int numTopLevels = topLevelItemCount()) { + for (int i = numTopLevels - 1; i >= 0; --i) { + if (topLevelRole(topLevelItem(i)) == SCRATCHPAD_ITEM) + return i; + } + } + return -1; +} + +int WidgetBoxTreeWidget::indexOfCategory(const QString &name) const +{ + const int topLevelCount = topLevelItemCount(); + for (int i = 0; i < topLevelCount; ++i) { + if (topLevelItem(i)->text(0) == name) + return i; + } + return -1; +} + +bool WidgetBoxTreeWidget::load(QDesignerWidgetBox::LoadMode loadMode) +{ + switch (loadMode) { + case QDesignerWidgetBox::LoadReplace: + clear(); + break; + case QDesignerWidgetBox::LoadCustomWidgetsOnly: + addCustomCategories(true); + updateGeometries(); + return true; + default: + break; + } + + const QString name = fileName(); + + QFile f(name); + if (!f.open(QIODevice::ReadOnly)) // Might not exist at first startup + return false; + + const QString contents = QString::fromUtf8(f.readAll()); + return loadContents(contents); +} + +bool WidgetBoxTreeWidget::loadContents(const QString &contents) +{ + QString errorMessage; + CategoryList cat_list; + if (!readCategories(m_file_name, contents, &cat_list, &errorMessage)) { + qdesigner_internal::designerWarning(errorMessage); + return false; + } + + foreach(const Category &cat, cat_list) + addCategory(cat); + + addCustomCategories(false); + // Restore which items are expanded + restoreExpandedState(); + return true; +} + +void WidgetBoxTreeWidget::addCustomCategories(bool replace) +{ + if (replace) { + // clear out all existing custom widgets + if (const int numTopLevels = topLevelItemCount()) { + for (int t = 0; t < numTopLevels ; ++t) + categoryViewAt(t)->removeCustomWidgets(); + } + } + // re-add + const CategoryList customList = loadCustomCategoryList(); + const CategoryList::const_iterator cend = customList.constEnd(); + for (CategoryList::const_iterator it = customList.constBegin(); it != cend; ++it) + addCategory(*it); +} + +static inline QString msgXmlError(const QString &fileName, const QXmlStreamReader &r) +{ + return QDesignerWidgetBox::tr("An error has been encountered at line %1 of %2: %3") + .arg(r.lineNumber()).arg(fileName, r.errorString()); +} + +bool WidgetBoxTreeWidget::readCategories(const QString &fileName, const QString &contents, + CategoryList *cats, QString *errorMessage) +{ + // Read widget box XML: + // + // + // + // + // + // ... + + QXmlStreamReader reader(contents); + + + // Entries of category with name="invisible" should be ignored + bool ignoreEntries = false; + + while (!reader.atEnd()) { + switch (reader.readNext()) { + case QXmlStreamReader::StartElement: { + const QStringRef tag = reader.name(); + if (tag == QLatin1String(widgetBoxRootElementC)) { + // + continue; + } + if (tag == QLatin1String(categoryElementC)) { + // + const QXmlStreamAttributes attributes = reader.attributes(); + const QString categoryName = attributes.value(QLatin1String(nameAttributeC)).toString(); + if (categoryName == QLatin1String(invisibleNameC)) { + ignoreEntries = true; + } else { + Category category(categoryName); + if (attributes.value(QLatin1String(typeAttributeC)) == QLatin1String(scratchPadValueC)) + category.setType(Category::Scratchpad); + cats->push_back(category); + } + continue; + } + if (tag == QLatin1String(categoryEntryElementC)) { + // + if (!ignoreEntries) { + QXmlStreamAttributes attr = reader.attributes(); + const QString widgetName = attr.value(QLatin1String(nameAttributeC)).toString(); + const QString widgetIcon = attr.value(QLatin1String(iconAttributeC)).toString(); + const WidgetBoxTreeWidget::Widget::Type widgetType = + attr.value(QLatin1String(typeAttributeC)).toString() + == QLatin1String(customValueC) ? + WidgetBoxTreeWidget::Widget::Custom : + WidgetBoxTreeWidget::Widget::Default; + + Widget w; + w.setName(widgetName); + w.setIconName(widgetIcon); + w.setType(widgetType); + if (!readWidget(&w, contents, reader)) + continue; + + cats->back().addWidget(w); + } // ignoreEntries + continue; + } + break; + } + case QXmlStreamReader::EndElement: { + const QStringRef tag = reader.name(); + if (tag == QLatin1String(widgetBoxRootElementC)) { + continue; + } + if (tag == QLatin1String(categoryElementC)) { + ignoreEntries = false; + continue; + } + if (tag == QLatin1String(categoryEntryElementC)) { + continue; + } + break; + } + default: break; + } + } + + if (reader.hasError()) { + *errorMessage = msgXmlError(fileName, reader); + return false; + } + + return true; +} + +/*! + * Read out a widget within a category. This can either be + * enclosed in a element or a (legacy) element which may + * contain nested elements. + * + * Examples: + * + * + * ... + * ... + * + * + * or + * + * + * ... + * ... + * + * + * Returns true on success, false if end was reached or an error has been encountered + * in which case the reader has its error flag set. If successful, the current item + * of the reader will be the closing element ( or ) + */ +bool WidgetBoxTreeWidget::readWidget(Widget *w, const QString &xml, QXmlStreamReader &r) +{ + qint64 startTagPosition =0, endTagPosition = 0; + + int nesting = 0; + bool endEncountered = false; + bool parsedWidgetTag = false; + QString outmostElement; + while (!endEncountered) { + const qint64 currentPosition = r.characterOffset(); + switch(r.readNext()) { + case QXmlStreamReader::StartElement: + if (nesting++ == 0) { + // First element must be or (legacy) + const QStringRef name = r.name(); + if (name == QLatin1String(uiElementC)) { + startTagPosition = currentPosition; + } else { + if (name == QLatin1String(widgetElementC)) { + startTagPosition = currentPosition; + parsedWidgetTag = true; + } else { + r.raiseError(QDesignerWidgetBox::tr("Unexpected element <%1> encountered when parsing for or ").arg(name.toString())); + return false; + } + } + } else { + // We are within looking for the first tag + if (!parsedWidgetTag && r.name() == QLatin1String(widgetElementC)) { + parsedWidgetTag = true; + } + } + break; + case QXmlStreamReader::EndElement: + // Reached end of widget? + if (--nesting == 0) { + endTagPosition = r.characterOffset(); + endEncountered = true; + } + break; + case QXmlStreamReader::EndDocument: + r.raiseError(QDesignerWidgetBox::tr("Unexpected end of file encountered when parsing widgets.")); + return false; + case QXmlStreamReader::Invalid: + return false; + default: + break; + } + } + if (!parsedWidgetTag) { + r.raiseError(QDesignerWidgetBox::tr("A widget element could not be found.")); + return false; + } + // Oddity: Startposition is 1 off + QString widgetXml = xml.mid(startTagPosition, endTagPosition - startTagPosition); + const QChar lessThan = QLatin1Char('<'); + if (!widgetXml.startsWith(lessThan)) + widgetXml.prepend(lessThan); + w->setDomXml(widgetXml); + return true; +} + +void WidgetBoxTreeWidget::writeCategories(QXmlStreamWriter &writer, const CategoryList &cat_list) const +{ + const QString widgetbox = QLatin1String(widgetBoxRootElementC); + const QString name = QLatin1String(nameAttributeC); + const QString type = QLatin1String(typeAttributeC); + const QString icon = QLatin1String(iconAttributeC); + const QString defaultType = QLatin1String(defaultTypeValueC); + const QString category = QLatin1String(categoryElementC); + const QString categoryEntry = QLatin1String(categoryEntryElementC); + const QString iconPrefix = QLatin1String(iconPrefixC); + const QString widgetTag = QLatin1String(widgetElementC); + + // + // + // + // + // + // ... + // + // + // ... + // + // ... + // + // + + writer.writeStartElement(widgetbox); + + foreach (const Category &cat, cat_list) { + writer.writeStartElement(category); + writer.writeAttribute(name, cat.name()); + if (cat.type() == Category::Scratchpad) + writer.writeAttribute(type, QLatin1String(scratchPadValueC)); + + const int widgetCount = cat.widgetCount(); + for (int i = 0; i < widgetCount; ++i) { + const Widget wgt = cat.widget(i); + if (wgt.type() == Widget::Custom) + continue; + + writer.writeStartElement(categoryEntry); + writer.writeAttribute(name, wgt.name()); + if (!wgt.iconName().startsWith(iconPrefix)) + writer.writeAttribute(icon, wgt.iconName()); + writer.writeAttribute(type, defaultType); + + const DomUI *domUI = QDesignerWidgetBox::xmlToUi(wgt.name(), WidgetBoxCategoryListView::widgetDomXml(wgt), false); + if (domUI) { + domUI->write(writer); + delete domUI; + } + + writer.writeEndElement(); // categoryEntry + } + writer.writeEndElement(); // categoryEntry + } + + writer.writeEndElement(); // widgetBox +} + +static int findCategory(const QString &name, const WidgetBoxTreeWidget::CategoryList &list) +{ + int idx = 0; + foreach (const WidgetBoxTreeWidget::Category &cat, list) { + if (cat.name() == name) + return idx; + ++idx; + } + return -1; +} + +static inline bool isValidIcon(const QIcon &icon) +{ + if (!icon.isNull()) { + const QList availableSizes = icon.availableSizes(); + if (!availableSizes.empty()) + return !availableSizes.front().isEmpty(); + } + return false; +} + +WidgetBoxTreeWidget::CategoryList WidgetBoxTreeWidget::loadCustomCategoryList() const +{ + CategoryList result; + + const QDesignerPluginManager *pm = m_core->pluginManager(); + const QDesignerPluginManager::CustomWidgetList customWidgets = pm->registeredCustomWidgets(); + if (customWidgets.empty()) + return result; + + static const QString customCatName = tr("Custom Widgets"); + + const QString invisible = QLatin1String(invisibleNameC); + const QString iconPrefix = QLatin1String(iconPrefixC); + + foreach(QDesignerCustomWidgetInterface *c, customWidgets) { + const QString dom_xml = c->domXml(); + if (dom_xml.isEmpty()) + continue; + + const QString pluginName = c->name(); + const QDesignerCustomWidgetData data = pm->customWidgetData(c); + QString displayName = data.xmlDisplayName(); + if (displayName.isEmpty()) + displayName = pluginName; + + QString cat_name = c->group(); + if (cat_name.isEmpty()) + cat_name = customCatName; + else if (cat_name == invisible) + continue; + + int idx = findCategory(cat_name, result); + if (idx == -1) { + result.append(Category(cat_name)); + idx = result.size() - 1; + } + Category &cat = result[idx]; + + const QIcon icon = c->icon(); + + QString icon_name; + if (isValidIcon(icon)) { + icon_name = iconPrefix; + icon_name += pluginName; + m_pluginIcons.insert(icon_name, icon); + } else { + icon_name = QLatin1String(qtLogoC); + } + + cat.addWidget(Widget(displayName, dom_xml, icon_name, Widget::Custom)); + } + + return result; +} + +void WidgetBoxTreeWidget::adjustSubListSize(QTreeWidgetItem *cat_item) +{ + QTreeWidgetItem *embedItem = cat_item->child(0); + if (embedItem == 0) + return; + + WidgetBoxCategoryListView *list_widget = static_cast(itemWidget(embedItem, 0)); + list_widget->setFixedWidth(header()->width()); + list_widget->doItemsLayout(); + const int height = qMax(list_widget->contentsSize().height() ,1); + list_widget->setFixedHeight(height); + embedItem->setSizeHint(0, QSize(-1, height - 1)); +} + +int WidgetBoxTreeWidget::categoryCount() const +{ + return topLevelItemCount(); +} + +WidgetBoxTreeWidget::Category WidgetBoxTreeWidget::category(int cat_idx) const +{ + if (cat_idx >= topLevelItemCount()) + return Category(); + + QTreeWidgetItem *cat_item = topLevelItem(cat_idx); + + QTreeWidgetItem *embedItem = cat_item->child(0); + WidgetBoxCategoryListView *categoryView = static_cast(itemWidget(embedItem, 0)); + + Category result = categoryView->category(); + result.setName(cat_item->text(0)); + + switch (topLevelRole(cat_item)) { + case SCRATCHPAD_ITEM: + result.setType(Category::Scratchpad); + break; + default: + result.setType(Category::Default); + break; + } + return result; +} + +void WidgetBoxTreeWidget::addCategory(const Category &cat) +{ + if (cat.widgetCount() == 0) + return; + + const bool isScratchPad = cat.type() == Category::Scratchpad; + WidgetBoxCategoryListView *categoryView; + QTreeWidgetItem *cat_item; + + if (isScratchPad) { + const int idx = ensureScratchpad(); + categoryView = categoryViewAt(idx); + cat_item = topLevelItem(idx); + } else { + const int existingIndex = indexOfCategory(cat.name()); + if (existingIndex == -1) { + cat_item = new QTreeWidgetItem(); + cat_item->setText(0, cat.name()); + setTopLevelRole(NORMAL_ITEM, cat_item); + // insert before scratchpad + const int scratchPadIndex = indexOfScratchpad(); + if (scratchPadIndex == -1) { + addTopLevelItem(cat_item); + } else { + insertTopLevelItem(scratchPadIndex, cat_item); + } + setItemExpanded(cat_item, true); + categoryView = addCategoryView(cat_item, m_iconMode); + } else { + categoryView = categoryViewAt(existingIndex); + cat_item = topLevelItem(existingIndex); + } + } + // The same categories are read from the file $HOME, avoid duplicates + const int widgetCount = cat.widgetCount(); + for (int i = 0; i < widgetCount; ++i) { + const Widget w = cat.widget(i); + if (!categoryView->containsWidget(w.name())) + categoryView->addWidget(w, iconForWidget(w.iconName()), isScratchPad); + } + adjustSubListSize(cat_item); +} + +void WidgetBoxTreeWidget::removeCategory(int cat_idx) +{ + if (cat_idx >= topLevelItemCount()) + return; + delete takeTopLevelItem(cat_idx); +} + +int WidgetBoxTreeWidget::widgetCount(int cat_idx) const +{ + if (cat_idx >= topLevelItemCount()) + return 0; + // SDK functions want unfiltered access + return categoryViewAt(cat_idx)->count(WidgetBoxCategoryListView::UnfilteredAccess); +} + +WidgetBoxTreeWidget::Widget WidgetBoxTreeWidget::widget(int cat_idx, int wgt_idx) const +{ + if (cat_idx >= topLevelItemCount()) + return Widget(); + // SDK functions want unfiltered access + WidgetBoxCategoryListView *categoryView = categoryViewAt(cat_idx); + return categoryView->widgetAt(WidgetBoxCategoryListView::UnfilteredAccess, wgt_idx); +} + +void WidgetBoxTreeWidget::addWidget(int cat_idx, const Widget &wgt) +{ + if (cat_idx >= topLevelItemCount()) + return; + + QTreeWidgetItem *cat_item = topLevelItem(cat_idx); + WidgetBoxCategoryListView *categoryView = categoryViewAt(cat_idx); + + const bool scratch = topLevelRole(cat_item) == SCRATCHPAD_ITEM; + categoryView->addWidget(wgt, iconForWidget(wgt.iconName()), scratch); + adjustSubListSize(cat_item); +} + +void WidgetBoxTreeWidget::removeWidget(int cat_idx, int wgt_idx) +{ + if (cat_idx >= topLevelItemCount()) + return; + + WidgetBoxCategoryListView *categoryView = categoryViewAt(cat_idx); + + // SDK functions want unfiltered access + const WidgetBoxCategoryListView::AccessMode am = WidgetBoxCategoryListView::UnfilteredAccess; + if (wgt_idx >= categoryView->count(am)) + return; + + categoryView->removeRow(am, wgt_idx); +} + +void WidgetBoxTreeWidget::slotScratchPadItemDeleted() +{ + const int scratch_idx = indexOfScratchpad(); + QTreeWidgetItem *scratch_item = topLevelItem(scratch_idx); + adjustSubListSize(scratch_item); + save(); +} + +void WidgetBoxTreeWidget::slotLastScratchPadItemDeleted() +{ + // Remove the scratchpad in the next idle loop + if (!m_scratchPadDeleteTimer) { + m_scratchPadDeleteTimer = new QTimer(this); + m_scratchPadDeleteTimer->setSingleShot(true); + m_scratchPadDeleteTimer->setInterval(0); + connect(m_scratchPadDeleteTimer, SIGNAL(timeout()), this, SLOT(deleteScratchpad())); + } + if (!m_scratchPadDeleteTimer->isActive()) + m_scratchPadDeleteTimer->start(); +} + +void WidgetBoxTreeWidget::deleteScratchpad() +{ + const int idx = indexOfScratchpad(); + if (idx == -1) + return; + delete takeTopLevelItem(idx); + save(); +} + + +void WidgetBoxTreeWidget::slotListMode() +{ + m_iconMode = false; + updateViewMode(); +} + +void WidgetBoxTreeWidget::slotIconMode() +{ + m_iconMode = true; + updateViewMode(); +} + +void WidgetBoxTreeWidget::updateViewMode() +{ + if (const int numTopLevels = topLevelItemCount()) { + for (int i = numTopLevels - 1; i >= 0; --i) { + QTreeWidgetItem *topLevel = topLevelItem(i); + // Scratch pad stays in list mode. + const QListView::ViewMode viewMode = m_iconMode && (topLevelRole(topLevel) != SCRATCHPAD_ITEM) ? QListView::IconMode : QListView::ListMode; + WidgetBoxCategoryListView *categoryView = categoryViewAt(i); + if (viewMode != categoryView->viewMode()) { + categoryView->setViewMode(viewMode); + adjustSubListSize(topLevelItem(i)); + } + } + } + + updateGeometries(); +} + +void WidgetBoxTreeWidget::resizeEvent(QResizeEvent *e) +{ + QTreeWidget::resizeEvent(e); + if (const int numTopLevels = topLevelItemCount()) { + for (int i = numTopLevels - 1; i >= 0; --i) + adjustSubListSize(topLevelItem(i)); + } +} + +void WidgetBoxTreeWidget::contextMenuEvent(QContextMenuEvent *e) +{ + QTreeWidgetItem *item = itemAt(e->pos()); + + const bool scratchpad_menu = item != 0 + && item->parent() != 0 + && topLevelRole(item->parent()) == SCRATCHPAD_ITEM; + + QMenu menu; + menu.addAction(tr("Expand all"), this, SLOT(expandAll())); + menu.addAction(tr("Collapse all"), this, SLOT(collapseAll())); + menu.addSeparator(); + + QAction *listModeAction = menu.addAction(tr("List View")); + QAction *iconModeAction = menu.addAction(tr("Icon View")); + listModeAction->setCheckable(true); + iconModeAction->setCheckable(true); + QActionGroup *viewModeGroup = new QActionGroup(&menu); + viewModeGroup->addAction(listModeAction); + viewModeGroup->addAction(iconModeAction); + if (m_iconMode) + iconModeAction->setChecked(true); + else + listModeAction->setChecked(true); + connect(listModeAction, SIGNAL(triggered()), SLOT(slotListMode())); + connect(iconModeAction, SIGNAL(triggered()), SLOT(slotIconMode())); + + if (scratchpad_menu) { + menu.addSeparator(); + menu.addAction(tr("Remove"), itemWidget(item, 0), SLOT(removeCurrentItem())); + if (!m_iconMode) + menu.addAction(tr("Edit name"), itemWidget(item, 0), SLOT(editCurrentItem())); + } + e->accept(); + menu.exec(mapToGlobal(e->pos())); +} + +void WidgetBoxTreeWidget::dropWidgets(const QList &item_list) +{ + QTreeWidgetItem *scratch_item = 0; + WidgetBoxCategoryListView *categoryView = 0; + bool added = false; + + foreach (QDesignerDnDItemInterface *item, item_list) { + QWidget *w = item->widget(); + if (w == 0) + continue; + + DomUI *dom_ui = item->domUi(); + if (dom_ui == 0) + continue; + + const int scratch_idx = ensureScratchpad(); + scratch_item = topLevelItem(scratch_idx); + categoryView = categoryViewAt(scratch_idx); + + // Temporarily remove the fake toplevel in-between + DomWidget *fakeTopLevel = dom_ui->takeElementWidget(); + DomWidget *firstWidget = 0; + if (fakeTopLevel && !fakeTopLevel->elementWidget().isEmpty()) { + firstWidget = fakeTopLevel->elementWidget().first(); + dom_ui->setElementWidget(firstWidget); + } else { + dom_ui->setElementWidget(fakeTopLevel); + continue; + } + + // Serialize to XML + QString xml; + { + QXmlStreamWriter writer(&xml); + writer.setAutoFormatting(true); + writer.setAutoFormattingIndent(1); + writer.writeStartDocument(); + dom_ui->write(writer); + writer.writeEndDocument(); + } + + // Insert fake toplevel again + dom_ui->takeElementWidget(); + dom_ui->setElementWidget(fakeTopLevel); + + const Widget wgt = Widget(w->objectName(), xml); + categoryView->addWidget(wgt, iconForWidget(wgt.iconName()), true); + setItemExpanded(scratch_item, true); + added = true; + } + + if (added) { + save(); + QApplication::setActiveWindow(this); + // Is the new item visible in filtered mode? + const WidgetBoxCategoryListView::AccessMode am = WidgetBoxCategoryListView::FilteredAccess; + if (const int count = categoryView->count(am)) + categoryView->setCurrentItem(am, count - 1); + categoryView->adjustSize(); // XXX + adjustSubListSize(scratch_item); + } +} + +void WidgetBoxTreeWidget::filter(const QString &f) +{ + const bool empty = f.isEmpty(); + const QRegExp re = empty ? QRegExp() : QRegExp(f, Qt::CaseInsensitive, QRegExp::FixedString); + const int numTopLevels = topLevelItemCount(); + bool changed = false; + for (int i = 0; i < numTopLevels; i++) { + QTreeWidgetItem *tl = topLevelItem(i); + WidgetBoxCategoryListView *categoryView = categoryViewAt(i); + // Anything changed? -> Enable the category + const int oldCount = categoryView->count(WidgetBoxCategoryListView::FilteredAccess); + categoryView->filter(re); + const int newCount = categoryView->count(WidgetBoxCategoryListView::FilteredAccess); + if (oldCount != newCount) { + changed = true; + const bool categoryEnabled = newCount > 0 || empty; + if (categoryEnabled) { + categoryView->adjustSize(); + adjustSubListSize(tl); + } + setRowHidden (i, QModelIndex(), !categoryEnabled); + } + } + if (changed) + updateGeometries(); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/components/widgetbox/widgetboxtreewidget.h b/src/designer/src/components/widgetbox/widgetboxtreewidget.h new file mode 100644 index 000000000..db4f7cdb1 --- /dev/null +++ b/src/designer/src/components/widgetbox/widgetboxtreewidget.h @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef WIDGETBOXTREEWIDGET_H +#define WIDGETBOXTREEWIDGET_H + +#include + +#include +#include +#include +#include +#include // Cannot forward declare them on Mac +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerDnDItemInterface; + +class QTimer; + +namespace qdesigner_internal { + +class WidgetBoxCategoryListView; + +// WidgetBoxTreeWidget: A tree of categories + +class WidgetBoxTreeWidget : public QTreeWidget +{ + Q_OBJECT + +public: + typedef QDesignerWidgetBoxInterface::Widget Widget; + typedef QDesignerWidgetBoxInterface::Category Category; + typedef QDesignerWidgetBoxInterface::CategoryList CategoryList; + + explicit WidgetBoxTreeWidget(QDesignerFormEditorInterface *core, QWidget *parent = 0); + ~WidgetBoxTreeWidget(); + + int categoryCount() const; + Category category(int cat_idx) const; + void addCategory(const Category &cat); + void removeCategory(int cat_idx); + + int widgetCount(int cat_idx) const; + Widget widget(int cat_idx, int wgt_idx) const; + void addWidget(int cat_idx, const Widget &wgt); + void removeWidget(int cat_idx, int wgt_idx); + + void dropWidgets(const QList &item_list); + + void setFileName(const QString &file_name); + QString fileName() const; + bool load(QDesignerWidgetBox::LoadMode loadMode); + bool loadContents(const QString &contents); + bool save(); + QIcon iconForWidget(QString iconName) const; + +signals: + void pressed(const QString name, const QString dom_xml, const QPoint &global_mouse_pos); + +public slots: + void filter(const QString &); + +protected: + void contextMenuEvent(QContextMenuEvent *e); + void resizeEvent(QResizeEvent *e); + +private slots: + void slotSave(); + void slotScratchPadItemDeleted(); + void slotLastScratchPadItemDeleted(); + + void handleMousePress(QTreeWidgetItem *item); + void deleteScratchpad(); + void slotListMode(); + void slotIconMode(); + +private: + WidgetBoxCategoryListView *addCategoryView(QTreeWidgetItem *parent, bool iconMode); + WidgetBoxCategoryListView *categoryViewAt(int idx) const; + void adjustSubListSize(QTreeWidgetItem *cat_item); + + static bool readCategories(const QString &fileName, const QString &xml, CategoryList *cats, QString *errorMessage); + static bool readWidget(Widget *w, const QString &xml, QXmlStreamReader &r); + + CategoryList loadCustomCategoryList() const; + void writeCategories(QXmlStreamWriter &writer, const CategoryList &cat_list) const; + + int indexOfCategory(const QString &name) const; + int indexOfScratchpad() const; + int ensureScratchpad(); + void addCustomCategories(bool replace); + + void saveExpandedState() const; + void restoreExpandedState(); + void updateViewMode(); + + QDesignerFormEditorInterface *m_core; + QString m_file_name; + typedef QHash IconCache; + mutable IconCache m_pluginIcons; + bool m_iconMode; + QTimer *m_scratchPadDeleteTimer; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // WIDGETBOXTREEWIDGET_H diff --git a/src/designer/src/designer/Info_mac.plist b/src/designer/src/designer/Info_mac.plist new file mode 100644 index 000000000..f19176fa7 --- /dev/null +++ b/src/designer/src/designer/Info_mac.plist @@ -0,0 +1,35 @@ + + + + + CFBundleIconFile + @ICON@ + CFBundlePackageType + APPL + CFBundleGetInfoString + Created by Qt/QMake + CFBundleIdentifier + com.trolltech.Designer + CFBundleSignature + ttxt + CFBundleExecutable + @EXECUTABLE@ + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + ui + + CFBundleTypeIconFile + uifile.icns + CFBundleTypeRole + Editor + LSIsAppleDefaultForType + + + + NOTE + Qt/Designer by Nokia Corporation and/or its subsidiary(-ies) + + diff --git a/src/designer/src/designer/appfontdialog.cpp b/src/designer/src/designer/appfontdialog.cpp new file mode 100644 index 000000000..00b91fa0d --- /dev/null +++ b/src/designer/src/designer/appfontdialog.cpp @@ -0,0 +1,429 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "appfontdialog.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +enum {FileNameRole = Qt::UserRole + 1, IdRole = Qt::UserRole + 2 }; +enum { debugAppFontWidget = 0 }; + +static const char fontFileKeyC[] = "fontFiles"; + +// AppFontManager: Singleton that maintains the mapping of loaded application font +// ids to the file names (which are not stored in QFontDatabase) +// and provides API for loading/unloading fonts as well for saving/restoring settings. + +class AppFontManager +{ + Q_DISABLE_COPY(AppFontManager) + AppFontManager(); +public: + static AppFontManager &instance(); + + void save(QDesignerSettingsInterface *s, const QString &prefix) const; + void restore(const QDesignerSettingsInterface *s, const QString &prefix); + + // Return id or -1 + int add(const QString &fontFile, QString *errorMessage); + + bool remove(int id, QString *errorMessage); + bool remove(const QString &fontFile, QString *errorMessage); + bool removeAt(int index, QString *errorMessage); + + // Store loaded fonts as pair of file name and Id + typedef QPair FileNameFontIdPair; + typedef QList FileNameFontIdPairs; + const FileNameFontIdPairs &fonts() const; + +private: + FileNameFontIdPairs m_fonts; +}; + +AppFontManager::AppFontManager() +{ +} + +AppFontManager &AppFontManager::instance() +{ + static AppFontManager rc; + return rc; +} + +void AppFontManager::save(QDesignerSettingsInterface *s, const QString &prefix) const +{ + // Store as list of file names + QStringList fontFiles; + const FileNameFontIdPairs::const_iterator cend = m_fonts.constEnd(); + for (FileNameFontIdPairs::const_iterator it = m_fonts.constBegin(); it != cend; ++it) + fontFiles.push_back(it->first); + + s->beginGroup(prefix); + s->setValue(QLatin1String(fontFileKeyC), fontFiles); + s->endGroup(); + + if (debugAppFontWidget) + qDebug() << "AppFontManager::saved" << fontFiles.size() << "fonts under " << prefix; +} + +void AppFontManager::restore(const QDesignerSettingsInterface *s, const QString &prefix) +{ + QString key = prefix; + key += QLatin1Char('/'); + key += QLatin1String(fontFileKeyC); + const QStringList fontFiles = s->value(key, QStringList()).toStringList(); + + if (debugAppFontWidget) + qDebug() << "AppFontManager::restoring" << fontFiles.size() << "fonts from " << prefix; + if (!fontFiles.empty()) { + QString errorMessage; + const QStringList::const_iterator cend = fontFiles.constEnd(); + for (QStringList::const_iterator it = fontFiles.constBegin(); it != cend; ++it) + if (add(*it, &errorMessage) == -1) + qWarning("%s", qPrintable(errorMessage)); + } +} + +int AppFontManager::add(const QString &fontFile, QString *errorMessage) +{ + const QFileInfo inf(fontFile); + if (!inf.isFile()) { + *errorMessage = QCoreApplication::translate("AppFontManager", "'%1' is not a file.").arg(fontFile); + return -1; + } + if (!inf.isReadable()) { + *errorMessage = QCoreApplication::translate("AppFontManager", "The font file '%1' does not have read permissions.").arg(fontFile); + return -1; + } + const QString fullPath = inf.absoluteFilePath(); + // Check if already loaded + const FileNameFontIdPairs::const_iterator cend = m_fonts.constEnd(); + for (FileNameFontIdPairs::const_iterator it = m_fonts.constBegin(); it != cend; ++it) { + if (it->first == fullPath) { + *errorMessage = QCoreApplication::translate("AppFontManager", "The font file '%1' is already loaded.").arg(fontFile); + return -1; + } + } + + const int id = QFontDatabase::addApplicationFont(fullPath); + if (id == -1) { + *errorMessage = QCoreApplication::translate("AppFontManager", "The font file '%1' could not be loaded.").arg(fontFile); + return -1; + } + + if (debugAppFontWidget) + qDebug() << "AppFontManager::add" << fontFile << id; + m_fonts.push_back(FileNameFontIdPair(fullPath, id)); + return id; +} + +bool AppFontManager::remove(int id, QString *errorMessage) +{ + const int count = m_fonts.size(); + for (int i = 0; i < count; i++) + if (m_fonts[i].second == id) + return removeAt(i, errorMessage); + + *errorMessage = QCoreApplication::translate("AppFontManager", "'%1' is not a valid font id.").arg(id); + return false; +} + +bool AppFontManager::remove(const QString &fontFile, QString *errorMessage) +{ + const int count = m_fonts.size(); + for (int i = 0; i < count; i++) + if (m_fonts[i].first == fontFile) + return removeAt(i, errorMessage); + + *errorMessage = QCoreApplication::translate("AppFontManager", "There is no loaded font matching the id '%1'.").arg(fontFile); + return false; +} + +bool AppFontManager::removeAt(int index, QString *errorMessage) +{ + Q_ASSERT(index >= 0 && index < m_fonts.size()); + + const QString fontFile = m_fonts[index].first; + const int id = m_fonts[index].second; + + if (debugAppFontWidget) + qDebug() << "AppFontManager::removeAt" << index << '(' << fontFile << id << ')'; + + if (!QFontDatabase::removeApplicationFont(id)) { + *errorMessage = QCoreApplication::translate("AppFontManager", "The font '%1' (%2) could not be unloaded.").arg(fontFile).arg(id); + return false; + } + m_fonts.removeAt(index); + return true; +} + +const AppFontManager::FileNameFontIdPairs &AppFontManager::fonts() const +{ + return m_fonts; +} + +// ------------- AppFontModel +class AppFontModel : public QStandardItemModel { + Q_DISABLE_COPY(AppFontModel) +public: + AppFontModel(QObject *parent = 0); + + void init(const AppFontManager &mgr); + void add(const QString &fontFile, int id); + int idAt(const QModelIndex &idx) const; +}; + +AppFontModel::AppFontModel(QObject * parent) : + QStandardItemModel(parent) +{ + setHorizontalHeaderLabels(QStringList(AppFontWidget::tr("Fonts"))); +} + +void AppFontModel::init(const AppFontManager &mgr) +{ + typedef AppFontManager::FileNameFontIdPairs FileNameFontIdPairs; + + const FileNameFontIdPairs &fonts = mgr.fonts(); + const FileNameFontIdPairs::const_iterator cend = fonts.constEnd(); + for (FileNameFontIdPairs::const_iterator it = fonts.constBegin(); it != cend; ++it) + add(it->first, it->second); +} + +void AppFontModel::add(const QString &fontFile, int id) +{ + const QFileInfo inf(fontFile); + // Root item with base name + QStandardItem *fileItem = new QStandardItem(inf.completeBaseName()); + const QString fullPath = inf.absoluteFilePath(); + fileItem->setData(fullPath, FileNameRole); + fileItem->setToolTip(fullPath); + fileItem->setData(id, IdRole); + fileItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); + + appendRow(fileItem); + const QStringList families = QFontDatabase::applicationFontFamilies(id); + const QStringList::const_iterator cend = families.constEnd(); + for (QStringList::const_iterator it = families.constBegin(); it != cend; ++it) { + QStandardItem *familyItem = new QStandardItem(*it); + familyItem->setToolTip(fullPath); + familyItem->setFont(QFont(*it)); + familyItem->setFlags(Qt::ItemIsEnabled); + fileItem->appendRow(familyItem); + } +} + +int AppFontModel::idAt(const QModelIndex &idx) const +{ + if (const QStandardItem *item = itemFromIndex(idx)) + return item->data(IdRole).toInt(); + return -1; +} + +// ------------- AppFontWidget +AppFontWidget::AppFontWidget(QWidget *parent) : + QGroupBox(parent), + m_view(new QTreeView), + m_addButton(new QToolButton), + m_removeButton(new QToolButton), + m_removeAllButton(new QToolButton), + m_model(new AppFontModel(this)) +{ + m_model->init(AppFontManager::instance()); + m_view->setModel(m_model); + m_view->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_view->expandAll(); + connect(m_view->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(selectionChanged(QItemSelection,QItemSelection))); + + m_addButton->setToolTip(tr("Add font files")); + m_addButton->setIcon(qdesigner_internal::createIconSet(QString::fromUtf8("plus.png"))); + connect(m_addButton, SIGNAL(clicked()), this, SLOT(addFiles())); + + m_removeButton->setEnabled(false); + m_removeButton->setToolTip(tr("Remove current font file")); + m_removeButton->setIcon(qdesigner_internal::createIconSet(QString::fromUtf8("minus.png"))); + connect(m_removeButton, SIGNAL(clicked()), this, SLOT(slotRemoveFiles())); + + m_removeAllButton->setToolTip(tr("Remove all font files")); + m_removeAllButton->setIcon(qdesigner_internal::createIconSet(QString::fromUtf8("editdelete.png"))); + connect(m_removeAllButton, SIGNAL(clicked()), this, SLOT(slotRemoveAll())); + + QHBoxLayout *hLayout = new QHBoxLayout; + hLayout->addWidget(m_addButton); + hLayout->addWidget(m_removeButton); + hLayout->addWidget(m_removeAllButton); + hLayout->addItem(new QSpacerItem(0, 0,QSizePolicy::MinimumExpanding)); + + QVBoxLayout *vLayout = new QVBoxLayout; + vLayout->addWidget(m_view); + vLayout->addLayout(hLayout); + setLayout(vLayout); +} + +void AppFontWidget::addFiles() +{ + const QStringList files = + QFileDialog::getOpenFileNames(this, tr("Add Font Files"), QString(), + tr("Font files (*.ttf)")); + if (files.empty()) + return; + + QString errorMessage; + + AppFontManager &fmgr = AppFontManager::instance(); + const QStringList::const_iterator cend = files.constEnd(); + for (QStringList::const_iterator it = files.constBegin(); it != cend; ++it) { + const int id = fmgr.add(*it, &errorMessage); + if (id != -1) { + m_model->add(*it, id); + } else { + QMessageBox::critical(this, tr("Error Adding Fonts"), errorMessage); + } + } + m_view->expandAll(); +} + +static void removeFonts(const QModelIndexList &selectedIndexes, AppFontModel *model, QWidget *dialogParent) +{ + if (selectedIndexes.empty()) + return; + + // Reverse sort top level rows and remove + AppFontManager &fmgr = AppFontManager::instance(); + QVector rows; + rows.reserve(selectedIndexes.size()); + + QString errorMessage; + const QModelIndexList::const_iterator cend = selectedIndexes.constEnd(); + for (QModelIndexList::const_iterator it = selectedIndexes.constBegin(); it != cend; ++it) { + const int id = model->idAt(*it); + if (id != -1) { + if (fmgr.remove(id, &errorMessage)) { + rows.push_back(it->row()); + } else { + QMessageBox::critical(dialogParent, AppFontWidget::tr("Error Removing Fonts"), errorMessage); + } + } + } + + qStableSort(rows.begin(), rows.end()); + for (int i = rows.size() - 1; i >= 0; i--) + model->removeRow(rows[i]); +} + +void AppFontWidget::slotRemoveFiles() +{ + removeFonts(m_view->selectionModel()->selectedIndexes(), m_model, this); +} + +void AppFontWidget::slotRemoveAll() +{ + const int count = m_model->rowCount(); + if (!count) + return; + + const QMessageBox::StandardButton answer = + QMessageBox::question(this, tr("Remove Fonts"), tr("Would you like to remove all fonts?"), + QMessageBox::Yes|QMessageBox::No, QMessageBox::No); + if (answer == QMessageBox::No) + return; + + QModelIndexList topLevels; + for (int i = 0; i < count; i++) + topLevels.push_back(m_model->index(i, 0)); + removeFonts(topLevels, m_model, this); +} + +void AppFontWidget::selectionChanged(const QItemSelection &selected, const QItemSelection & /*deselected*/) +{ + m_removeButton->setEnabled(!selected.indexes().empty()); +} + +void AppFontWidget::save(QDesignerSettingsInterface *s, const QString &prefix) +{ + AppFontManager::instance().save(s, prefix); +} + +void AppFontWidget::restore(const QDesignerSettingsInterface *s, const QString &prefix) +{ + AppFontManager::instance().restore(s, prefix); +} + +// ------------ AppFontDialog +AppFontDialog::AppFontDialog(QWidget *parent) : + QDialog(parent), + m_appFontWidget(new AppFontWidget) +{ + setAttribute(Qt::WA_DeleteOnClose, true); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + setWindowTitle(tr("Additional Fonts")); + setModal(false); + QVBoxLayout *vl = new QVBoxLayout; + vl->addWidget(m_appFontWidget); + + QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Close); + QDialog::connect(bb, SIGNAL(rejected()), this, SLOT(reject())); + vl->addWidget(bb); + setLayout(vl); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/appfontdialog.h b/src/designer/src/designer/appfontdialog.h new file mode 100644 index 000000000..a373217ac --- /dev/null +++ b/src/designer/src/designer/appfontdialog.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_APPFONTWIDGET_H +#define QDESIGNER_APPFONTWIDGET_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class AppFontModel; + +class QTreeView; +class QToolButton; +class QItemSelection; +class QDesignerSettingsInterface; + +// AppFontWidget: Manages application fonts which the user can load and +// provides API for saving/restoring them. + +class AppFontWidget : public QGroupBox +{ + Q_DISABLE_COPY(AppFontWidget) + Q_OBJECT +public: + explicit AppFontWidget(QWidget *parent = 0); + + QStringList fontFiles() const; + + static void save(QDesignerSettingsInterface *s, const QString &prefix); + static void restore(const QDesignerSettingsInterface *s, const QString &prefix); + +private slots: + void addFiles(); + void slotRemoveFiles(); + void slotRemoveAll(); + void selectionChanged(const QItemSelection & selected, const QItemSelection & deselected); + +private: + QTreeView *m_view; + QToolButton *m_addButton; + QToolButton *m_removeButton; + QToolButton *m_removeAllButton; + AppFontModel *m_model; +}; + +// AppFontDialog: Non modal dialog for AppFontWidget which has Qt::WA_DeleteOnClose set. + +class AppFontDialog : public QDialog +{ + Q_DISABLE_COPY(AppFontDialog) + Q_OBJECT +public: + explicit AppFontDialog(QWidget *parent = 0); + +private: + AppFontWidget *m_appFontWidget; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_APPFONTWIDGET_H diff --git a/src/designer/src/designer/assistantclient.cpp b/src/designer/src/designer/assistantclient.cpp new file mode 100644 index 000000000..0433c5c51 --- /dev/null +++ b/src/designer/src/designer/assistantclient.cpp @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "assistantclient.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +enum { debugAssistantClient = 0 }; + +AssistantClient::AssistantClient() : + m_process(0) +{ +} + +AssistantClient::~AssistantClient() +{ + if (isRunning()) { + m_process->terminate(); + m_process->waitForFinished(); + } + delete m_process; +} + +bool AssistantClient::showPage(const QString &path, QString *errorMessage) +{ + QString cmd = QLatin1String("SetSource "); + cmd += path; + return sendCommand(cmd, errorMessage); +} + +bool AssistantClient::activateIdentifier(const QString &identifier, QString *errorMessage) +{ + QString cmd = QLatin1String("ActivateIdentifier "); + cmd += identifier; + return sendCommand(cmd, errorMessage); +} + +bool AssistantClient::activateKeyword(const QString &keyword, QString *errorMessage) +{ + QString cmd = QLatin1String("ActivateKeyword "); + cmd += keyword; + return sendCommand(cmd, errorMessage); +} + +bool AssistantClient::sendCommand(const QString &cmd, QString *errorMessage) +{ + if (debugAssistantClient) + qDebug() << "sendCommand " << cmd; + if (!ensureRunning(errorMessage)) + return false; + if (!m_process->isWritable() || m_process->bytesToWrite() > 0) { + *errorMessage = QCoreApplication::translate("AssistantClient", "Unable to send request: Assistant is not responding."); + return false; + } + QTextStream str(m_process); + str << cmd << QLatin1Char('\n') << endl; + return true; +} + +bool AssistantClient::isRunning() const +{ + return m_process && m_process->state() != QProcess::NotRunning; +} + +QString AssistantClient::binary() +{ + QString app = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QDir::separator(); +#if !defined(Q_OS_MAC) + app += QLatin1String("assistant"); +#else + app += QLatin1String("Assistant.app/Contents/MacOS/Assistant"); +#endif + +#if defined(Q_OS_WIN) + app += QLatin1String(".exe"); +#endif + + return app; +} + +bool AssistantClient::ensureRunning(QString *errorMessage) +{ + if (isRunning()) + return true; + + if (!m_process) + m_process = new QProcess; + + const QString app = binary(); + if (!QFileInfo(app).isFile()) { + *errorMessage = QCoreApplication::translate("AssistantClient", "The binary '%1' does not exist.").arg(app); + return false; + } + if (debugAssistantClient) + qDebug() << "Running " << app; + // run + QStringList args(QLatin1String("-enableRemoteControl")); + m_process->start(app, args); + if (!m_process->waitForStarted()) { + *errorMessage = QCoreApplication::translate("AssistantClient", "Unable to launch assistant (%1).").arg(app); + return false; + } + return true; +} + +QString AssistantClient::documentUrl(const QString &prefix, int qtVersion) +{ + if (qtVersion == 0) + qtVersion = QT_VERSION; + QString rc; + QTextStream(&rc) << QLatin1String("qthelp://com.trolltech.") << prefix << QLatin1Char('.') + << (qtVersion >> 16) << ((qtVersion >> 8) & 0xFF) << (qtVersion & 0xFF) + << QLatin1String("/qdoc/"); + return rc; +} + +QString AssistantClient::designerManualUrl(int qtVersion) +{ + return documentUrl(QLatin1String("designer"), qtVersion); +} + +QString AssistantClient::qtReferenceManualUrl(int qtVersion) +{ + return documentUrl(QLatin1String("qt"), qtVersion); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/assistantclient.h b/src/designer/src/designer/assistantclient.h new file mode 100644 index 000000000..67257d191 --- /dev/null +++ b/src/designer/src/designer/assistantclient.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ASSISTANTCLIENT_H +#define ASSISTANTCLIENT_H + +#include + +QT_BEGIN_NAMESPACE + +class QProcess; +class QString; + +class AssistantClient +{ + AssistantClient(const AssistantClient &); + AssistantClient &operator=(const AssistantClient &); + +public: + AssistantClient(); + ~AssistantClient(); + + bool showPage(const QString &path, QString *errorMessage); + bool activateIdentifier(const QString &identifier, QString *errorMessage); + bool activateKeyword(const QString &keyword, QString *errorMessage); + + bool isRunning() const; + + static QString documentUrl(const QString &prefix, int qtVersion = 0); + // Root of the Qt Designer documentation + static QString designerManualUrl(int qtVersion = 0); + // Root of the Qt Reference documentation + static QString qtReferenceManualUrl(int qtVersion = 0); + +private: + static QString binary(); + bool sendCommand(const QString &cmd, QString *errorMessage); + bool ensureRunning(QString *errorMessage); + + QProcess *m_process; +}; + +QT_END_NAMESPACE + +#endif // ASSISTANTCLIENT_H diff --git a/src/designer/src/designer/designer.icns b/src/designer/src/designer/designer.icns new file mode 100644 index 000000000..9940214fc Binary files /dev/null and b/src/designer/src/designer/designer.icns differ diff --git a/src/designer/src/designer/designer.ico b/src/designer/src/designer/designer.ico new file mode 100644 index 000000000..ef667333d Binary files /dev/null and b/src/designer/src/designer/designer.ico differ diff --git a/src/designer/src/designer/designer.pro b/src/designer/src/designer/designer.pro new file mode 100644 index 000000000..8564e96cb --- /dev/null +++ b/src/designer/src/designer/designer.pro @@ -0,0 +1,90 @@ + +DESTDIR = ../../../../bin +QT += xml network +contains(QT_CONFIG, script): QT += script +build_all:!build_pass { + CONFIG -= build_all + CONFIG += release +} + +INCLUDEPATH += \ + ../lib/sdk \ + ../lib/extension \ + ../lib/shared \ + ../lib/uilib \ + extra + +QMAKE_LIBDIR += ../../lib ../../../../lib +LIBS += -lQtDesignerComponents -lQtDesigner + +RESOURCES += designer.qrc + +contains(CONFIG, static) { + DEFINES += QT_DESIGNER_STATIC +} + +TARGET = designer + +include(../../../shared/fontpanel/fontpanel.pri) +include(../../../shared/qttoolbardialog/qttoolbardialog.pri) + +HEADERS += \ + qdesigner.h \ + qdesigner_toolwindow.h \ + qdesigner_formwindow.h \ + qdesigner_workbench.h \ + qdesigner_settings.h \ + qdesigner_actions.h \ + qdesigner_server.h \ + qdesigner_appearanceoptions.h \ + saveformastemplate.h \ + newform.h \ + versiondialog.h \ + designer_enums.h \ + appfontdialog.h \ + preferencesdialog.h \ + assistantclient.h \ + mainwindow.h + +SOURCES += main.cpp \ + qdesigner.cpp \ + qdesigner_toolwindow.cpp \ + qdesigner_formwindow.cpp \ + qdesigner_workbench.cpp \ + qdesigner_settings.cpp \ + qdesigner_server.cpp \ + qdesigner_actions.cpp \ + qdesigner_appearanceoptions.cpp \ + saveformastemplate.cpp \ + newform.cpp \ + versiondialog.cpp \ + appfontdialog.cpp \ + preferencesdialog.cpp \ + assistantclient.cpp \ + mainwindow.cpp + +PRECOMPILED_HEADER=qdesigner_pch.h + +FORMS += saveformastemplate.ui \ + preferencesdialog.ui \ + qdesigner_appearanceoptions.ui + +win32 { + RC_FILE = designer.rc +} + +mac { + ICON = designer.icns + QMAKE_INFO_PLIST = Info_mac.plist + TARGET = Designer + FILETYPES.files = uifile.icns + FILETYPES.path = Contents/Resources + QMAKE_BUNDLE_DATA += FILETYPES +} + +target.path=$$[QT_INSTALL_BINS] +INSTALLS += target + +include(../sharedcomponents.pri) + +unix:!mac:LIBS += -lm diff --git a/src/designer/src/designer/designer.qrc b/src/designer/src/designer/designer.qrc new file mode 100644 index 000000000..fac8120d0 --- /dev/null +++ b/src/designer/src/designer/designer.qrc @@ -0,0 +1,5 @@ + + + images/designer.png + + diff --git a/src/designer/src/designer/designer.rc b/src/designer/src/designer/designer.rc new file mode 100644 index 000000000..9c396b555 --- /dev/null +++ b/src/designer/src/designer/designer.rc @@ -0,0 +1,32 @@ +#include "winver.h" + +IDI_ICON1 ICON DISCARDABLE "designer.ico" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGS 0x0L + FILEFLAGSMASK 0x3fL + FILEOS 0x00040004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "CompanyName", "Nokia Corporation and/or its subsidiary(-ies)" + VALUE "FileDescription", "Qt Designer" + VALUE "FileVersion", "1.0.0.0" + VALUE "LegalCopyright", "Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)." + VALUE "InternalName", "designer" + VALUE "OriginalFilename", "designer.exe" + VALUE "ProductName", "Qt Designer" + VALUE "ProductVersion", "1.0.0.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END diff --git a/src/designer/src/designer/designer_enums.h b/src/designer/src/designer/designer_enums.h new file mode 100644 index 000000000..ca115c37a --- /dev/null +++ b/src/designer/src/designer/designer_enums.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DESIGNERENUMS_H +#define DESIGNERENUMS_H + +enum UIMode +{ + NeutralMode, + TopLevelMode, + DockedMode +}; + +#endif // DESIGNERENUMS_H diff --git a/src/designer/src/designer/images/designer.png b/src/designer/src/designer/images/designer.png new file mode 100644 index 000000000..0988fcee3 Binary files /dev/null and b/src/designer/src/designer/images/designer.png differ diff --git a/src/designer/src/designer/images/mdi.png b/src/designer/src/designer/images/mdi.png new file mode 100644 index 000000000..5012ab304 Binary files /dev/null and b/src/designer/src/designer/images/mdi.png differ diff --git a/src/designer/src/designer/images/sdi.png b/src/designer/src/designer/images/sdi.png new file mode 100644 index 000000000..7fff6e8b6 Binary files /dev/null and b/src/designer/src/designer/images/sdi.png differ diff --git a/src/designer/src/designer/images/workbench.png b/src/designer/src/designer/images/workbench.png new file mode 100644 index 000000000..06716a44f Binary files /dev/null and b/src/designer/src/designer/images/workbench.png differ diff --git a/src/designer/src/designer/main.cpp b/src/designer/src/designer/main.cpp new file mode 100644 index 000000000..8a5b5c044 --- /dev/null +++ b/src/designer/src/designer/main.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner.h" +#include +#include + +#include + +QT_USE_NAMESPACE + +int main(int argc, char *argv[]) +{ + Q_INIT_RESOURCE(designer); + + QDesigner app(argc, argv); + app.setQuitOnLastWindowClosed(false); + + return app.exec(); +} diff --git a/src/designer/src/designer/mainwindow.cpp b/src/designer/src/designer/mainwindow.cpp new file mode 100644 index 000000000..67e1a4053 --- /dev/null +++ b/src/designer/src/designer/mainwindow.cpp @@ -0,0 +1,419 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "mainwindow.h" +#include "qdesigner.h" +#include "qdesigner_actions.h" +#include "qdesigner_workbench.h" +#include "qdesigner_formwindow.h" +#include "qdesigner_toolwindow.h" +#include "qdesigner_settings.h" +#include "qttoolbardialog.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static const char *uriListMimeFormatC = "text/uri-list"; + +QT_BEGIN_NAMESPACE + +typedef QList ActionList; + +// Helpers for creating toolbars and menu + +static void addActionsToToolBar(const ActionList &actions, QToolBar *t) +{ + const ActionList::const_iterator cend = actions.constEnd(); + for (ActionList::const_iterator it = actions.constBegin(); it != cend; ++it) { + QAction *action = *it; + if (action->property(QDesignerActions::defaultToolbarPropertyName).toBool()) + t->addAction(action); + } +} +static QToolBar *createToolBar(const QString &title, const QString &objectName, const ActionList &actions) +{ + QToolBar *rc = new QToolBar; + rc->setObjectName(objectName); + rc->setWindowTitle(title); + addActionsToToolBar(actions, rc); + return rc; +} + +// ---------------- MainWindowBase + +MainWindowBase::MainWindowBase(QWidget *parent, Qt::WindowFlags flags) : + QMainWindow(parent, flags), + m_policy(AcceptCloseEvents) +{ +#ifndef Q_WS_MAC + setWindowIcon(qDesigner->windowIcon()); +#endif +} + +void MainWindowBase::closeEvent(QCloseEvent *e) +{ + switch (m_policy) { + case AcceptCloseEvents: + QMainWindow::closeEvent(e); + break; + case EmitCloseEventSignal: + emit closeEventReceived(e); + break; + } +} + +QList MainWindowBase::createToolBars(const QDesignerActions *actions, bool singleToolBar) +{ + // Note that whenever you want to add a new tool bar here, you also have to update the default + // action groups added to the toolbar manager in the mainwindow constructor + QList rc; + if (singleToolBar) { + //: Not currently used (main tool bar) + QToolBar *main = createToolBar(tr("Main"), QLatin1String("mainToolBar"), actions->fileActions()->actions()); + addActionsToToolBar(actions->editActions()->actions(), main); + addActionsToToolBar(actions->toolActions()->actions(), main); + addActionsToToolBar(actions->formActions()->actions(), main); + rc.push_back(main); + } else { + rc.push_back(createToolBar(tr("File"), QLatin1String("fileToolBar"), actions->fileActions()->actions())); + rc.push_back(createToolBar(tr("Edit"), QLatin1String("editToolBar"), actions->editActions()->actions())); + rc.push_back(createToolBar(tr("Tools"), QLatin1String("toolsToolBar"), actions->toolActions()->actions())); + rc.push_back(createToolBar(tr("Form"), QLatin1String("formToolBar"), actions->formActions()->actions())); + } + return rc; +} + +QString MainWindowBase::mainWindowTitle() +{ + return tr("Qt Designer"); +} + +// Use the minor Qt version as settings versions to avoid conflicts +int MainWindowBase::settingsVersion() +{ + const int version = QT_VERSION; + return (version & 0x00FF00) >> 8; +} + +// ----------------- DockedMdiArea + +DockedMdiArea::DockedMdiArea(const QString &extension, QWidget *parent) : + QMdiArea(parent), + m_extension(extension) +{ + setAcceptDrops(true); + setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); +} + +QStringList DockedMdiArea::uiFiles(const QMimeData *d) const +{ + // Extract dropped UI files from Mime data. + QStringList rc; + if (!d->hasFormat(QLatin1String(uriListMimeFormatC))) + return rc; + const QList urls = d->urls(); + if (urls.empty()) + return rc; + const QList::const_iterator cend = urls.constEnd(); + for (QList::const_iterator it = urls.constBegin(); it != cend; ++it) { + const QString fileName = it->toLocalFile(); + if (!fileName.isEmpty() && fileName.endsWith(m_extension)) + rc.push_back(fileName); + } + return rc; +} + +bool DockedMdiArea::event(QEvent *event) +{ + // Listen for desktop file manager drop and emit a signal once a file is + // dropped. + switch (event->type()) { + case QEvent::DragEnter: { + QDragEnterEvent *e = static_cast(event); + if (!uiFiles(e->mimeData()).empty()) { + e->acceptProposedAction(); + return true; + } + } + break; + case QEvent::Drop: { + QDropEvent *e = static_cast(event); + const QStringList files = uiFiles(e->mimeData()); + const QStringList::const_iterator cend = files.constEnd(); + for (QStringList::const_iterator it = files.constBegin(); it != cend; ++it) { + emit fileDropped(*it); + } + e->acceptProposedAction(); + return true; + } + break; + default: + break; + } + return QMdiArea::event(event); +} + +// ------------- ToolBarManager: + +static void addActionsToToolBarManager(const ActionList &al, const QString &title, QtToolBarManager *tbm) +{ + const ActionList::const_iterator cend = al.constEnd(); + for (ActionList::const_iterator it = al.constBegin(); it != cend; ++it) + tbm->addAction(*it, title); +} + +ToolBarManager::ToolBarManager(QMainWindow *configureableMainWindow, + QWidget *parent, + QMenu *toolBarMenu, + const QDesignerActions *actions, + const QList &toolbars, + const QList &toolWindows) : + QObject(parent), + m_configureableMainWindow(configureableMainWindow), + m_parent(parent), + m_toolBarMenu(toolBarMenu), + m_manager(new QtToolBarManager(this)), + m_configureAction(new QAction(tr("Configure Toolbars..."), this)), + m_toolbars(toolbars) +{ + m_configureAction->setMenuRole(QAction::NoRole); + m_configureAction->setObjectName(QLatin1String("__qt_configure_tool_bars_action")); + connect(m_configureAction, SIGNAL(triggered()), this, SLOT(configureToolBars())); + + m_manager->setMainWindow(configureableMainWindow); + + foreach(QToolBar *tb, m_toolbars) { + const QString title = tb->windowTitle(); + m_manager->addToolBar(tb, title); + addActionsToToolBarManager(tb->actions(), title, m_manager); + } + + addActionsToToolBarManager(actions->windowActions()->actions(), tr("Window"), m_manager); + addActionsToToolBarManager(actions->helpActions()->actions(), tr("Help"), m_manager); + + // Filter out the device profile preview actions which have int data(). + ActionList previewActions = actions->styleActions()->actions(); + ActionList::iterator it = previewActions.begin(); + for ( ; (*it)->isSeparator() || (*it)->data().type() == QVariant::Int; ++it) ; + previewActions.erase(previewActions.begin(), it); + addActionsToToolBarManager(previewActions, tr("Style"), m_manager); + + const QString dockTitle = tr("Dock views"); + foreach (QDesignerToolWindow *tw, toolWindows) { + if (QAction *action = tw->action()) + m_manager->addAction(action, dockTitle); + } + + QString category(tr("File")); + foreach(QAction *action, actions->fileActions()->actions()) + m_manager->addAction(action, category); + + category = tr("Edit"); + foreach(QAction *action, actions->editActions()->actions()) + m_manager->addAction(action, category); + + category = tr("Tools"); + foreach(QAction *action, actions->toolActions()->actions()) + m_manager->addAction(action, category); + + category = tr("Form"); + foreach(QAction *action, actions->formActions()->actions()) + m_manager->addAction(action, category); + + m_manager->addAction(m_configureAction, tr("Toolbars")); + updateToolBarMenu(); +} + +// sort function for sorting tool bars alphabetically by title [non-static since called from template] + +bool toolBarTitleLessThan(const QToolBar *t1, const QToolBar *t2) +{ + return t1->windowTitle() < t2->windowTitle(); +} + +void ToolBarManager::updateToolBarMenu() +{ + // Sort tool bars alphabetically by title + qStableSort(m_toolbars.begin(), m_toolbars.end(), toolBarTitleLessThan); + // add to menu + m_toolBarMenu->clear(); + foreach (QToolBar *tb, m_toolbars) + m_toolBarMenu->addAction(tb->toggleViewAction()); + m_toolBarMenu->addAction(m_configureAction); +} + +void ToolBarManager::configureToolBars() +{ + QtToolBarDialog dlg(m_parent); + dlg.setWindowFlags(dlg.windowFlags() & ~Qt::WindowContextHelpButtonHint); + dlg.setToolBarManager(m_manager); + dlg.exec(); + updateToolBarMenu(); +} + +QByteArray ToolBarManager::saveState(int version) const +{ + return m_manager->saveState(version); +} + +bool ToolBarManager::restoreState(const QByteArray &state, int version) +{ + return m_manager->restoreState(state, version); +} + +// ---------- DockedMainWindow + +DockedMainWindow::DockedMainWindow(QDesignerWorkbench *wb, + QMenu *toolBarMenu, + const QList &toolWindows) : + m_toolBarManager(0) +{ + setObjectName(QLatin1String("MDIWindow")); + setWindowTitle(mainWindowTitle()); + + const QList toolbars = createToolBars(wb->actionManager(), false); + foreach (QToolBar *tb, toolbars) + addToolBar(tb); + DockedMdiArea *dma = new DockedMdiArea(wb->actionManager()->uiExtension()); + connect(dma, SIGNAL(fileDropped(QString)), + this, SIGNAL(fileDropped(QString))); + connect(dma, SIGNAL(subWindowActivated(QMdiSubWindow*)), + this, SLOT(slotSubWindowActivated(QMdiSubWindow*))); + setCentralWidget(dma); + + QStatusBar *sb = statusBar(); + Q_UNUSED(sb) + + m_toolBarManager = new ToolBarManager(this, this, toolBarMenu, wb->actionManager(), toolbars, toolWindows); +} + +QMdiArea *DockedMainWindow::mdiArea() const +{ + return static_cast(centralWidget()); +} + +void DockedMainWindow::slotSubWindowActivated(QMdiSubWindow* subWindow) +{ + if (subWindow) { + QWidget *widget = subWindow->widget(); + if (QDesignerFormWindow *fw = qobject_cast(widget)) { + emit formWindowActivated(fw); + mdiArea()->setActiveSubWindow(subWindow); + } + } +} + +// Create a MDI subwindow for the form. +QMdiSubWindow *DockedMainWindow::createMdiSubWindow(QWidget *fw, Qt::WindowFlags f, const QKeySequence &designerCloseActionShortCut) +{ + QMdiSubWindow *rc = mdiArea()->addSubWindow(fw, f); + // Make action shortcuts respond only if focused to avoid conflicts with + // designer menu actions + if (designerCloseActionShortCut == QKeySequence(QKeySequence::Close)) { + const ActionList systemMenuActions = rc->systemMenu()->actions(); + if (!systemMenuActions.empty()) { + const ActionList::const_iterator cend = systemMenuActions.constEnd(); + for (ActionList::const_iterator it = systemMenuActions.constBegin(); it != cend; ++it) { + if ( (*it)->shortcut() == designerCloseActionShortCut) { + (*it)->setShortcutContext(Qt::WidgetShortcut); + break; + } + } + } + } + return rc; +} + +DockedMainWindow::DockWidgetList DockedMainWindow::addToolWindows(const DesignerToolWindowList &tls) +{ + DockWidgetList rc; + foreach (QDesignerToolWindow *tw, tls) { + QDockWidget *dockWidget = new QDockWidget; + dockWidget->setObjectName(tw->objectName() + QLatin1String("_dock")); + dockWidget->setWindowTitle(tw->windowTitle()); + addDockWidget(tw->dockWidgetAreaHint(), dockWidget); + dockWidget->setWidget(tw); + rc.push_back(dockWidget); + } + return rc; +} + +// Settings consist of MainWindow state and tool bar manager state +void DockedMainWindow::restoreSettings(const QDesignerSettings &s, const DockWidgetList &dws, const QRect &desktopArea) +{ + const int version = settingsVersion(); + m_toolBarManager->restoreState(s.toolBarsState(DockedMode), version); + + // If there are no old geometry settings, show the window maximized + s.restoreGeometry(this, QRect(desktopArea.topLeft(), QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX))); + + const QByteArray mainWindowState = s.mainWindowState(DockedMode); + const bool restored = !mainWindowState.isEmpty() && restoreState(mainWindowState, version); + if (!restored) { + // Default: Tabify less relevant windows bottom/right. + tabifyDockWidget(dws.at(QDesignerToolWindow::SignalSlotEditor), + dws.at(QDesignerToolWindow::ActionEditor)); + tabifyDockWidget(dws.at(QDesignerToolWindow::ActionEditor), + dws.at(QDesignerToolWindow::ResourceEditor)); + } +} + +void DockedMainWindow::saveSettings(QDesignerSettings &s) const +{ + const int version = settingsVersion(); + s.setToolBarsState(DockedMode, m_toolBarManager->saveState(version)); + s.saveGeometryFor(this); + s.setMainWindowState(DockedMode, saveState(version)); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/mainwindow.h b/src/designer/src/designer/mainwindow.h new file mode 100644 index 000000000..e39e57203 --- /dev/null +++ b/src/designer/src/designer/mainwindow.h @@ -0,0 +1,187 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerActions; +class QDesignerWorkbench; +class QDesignerToolWindow; +class QDesignerFormWindow; +class QDesignerSettings; + +class QtToolBarManager; +class QToolBar; +class QMdiArea; +class QMenu; +class QByteArray; +class QMimeData; + +/* A main window that has a configureable policy on handling close events. If + * enabled, it can forward the close event to external handlers. + * Base class for windows that can switch roles between tool windows + * and main windows. */ + +class MainWindowBase: public QMainWindow +{ + Q_DISABLE_COPY(MainWindowBase) + Q_OBJECT +protected: + explicit MainWindowBase(QWidget *parent = 0, Qt::WindowFlags flags = Qt::Window); + +public: + enum CloseEventPolicy { + /* Always accept close events */ + AcceptCloseEvents, + /* Emit a signal with the event, have it handled elsewhere */ + EmitCloseEventSignal }; + + CloseEventPolicy closeEventPolicy() const { return m_policy; } + void setCloseEventPolicy(CloseEventPolicy pol) { m_policy = pol; } + + static QList createToolBars(const QDesignerActions *actions, bool singleToolBar); + static QString mainWindowTitle(); + + // Use the minor Qt version as settings versions to avoid conflicts + static int settingsVersion(); + +signals: + void closeEventReceived(QCloseEvent *e); + +protected: + virtual void closeEvent(QCloseEvent *e); +private: + CloseEventPolicy m_policy; +}; + +/* An MdiArea that listens for desktop file manager file drop events and emits + * a signal to open a dropped file. */ +class DockedMdiArea : public QMdiArea +{ + Q_DISABLE_COPY(DockedMdiArea) + Q_OBJECT +public: + explicit DockedMdiArea(const QString &extension, QWidget *parent = 0); + +signals: + void fileDropped(const QString &); + +protected: + bool event (QEvent *event); + +private: + QStringList uiFiles(const QMimeData *d) const; + + const QString m_extension; +}; + +// Convenience class that manages a QtToolBarManager and an action to trigger +// it on a mainwindow. +class ToolBarManager : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(ToolBarManager) +public: + explicit ToolBarManager(QMainWindow *configureableMainWindow, + QWidget *parent, + QMenu *toolBarMenu, + const QDesignerActions *actions, + const QList &toolbars, + const QList &toolWindows); + + QByteArray saveState(int version = 0) const; + bool restoreState(const QByteArray &state, int version = 0); + +private slots: + void configureToolBars(); + void updateToolBarMenu(); + +private: + QMainWindow *m_configureableMainWindow; + QWidget *m_parent; + QMenu *m_toolBarMenu; + QtToolBarManager *m_manager; + QAction *m_configureAction; + QList m_toolbars; +}; + +/* Main window to be used for docked mode */ +class DockedMainWindow : public MainWindowBase { + Q_OBJECT + Q_DISABLE_COPY(DockedMainWindow) +public: + typedef QList DesignerToolWindowList; + typedef QList DockWidgetList; + + explicit DockedMainWindow(QDesignerWorkbench *wb, + QMenu *toolBarMenu, + const DesignerToolWindowList &toolWindows); + + // Create a MDI subwindow for the form. + QMdiSubWindow *createMdiSubWindow(QWidget *fw, Qt::WindowFlags f, const QKeySequence &designerCloseActionShortCut); + + QMdiArea *mdiArea() const; + + DockWidgetList addToolWindows(const DesignerToolWindowList &toolWindows); + + void restoreSettings(const QDesignerSettings &s, const DockWidgetList &dws, const QRect &desktopArea); + void saveSettings(QDesignerSettings &) const; + +signals: + void fileDropped(const QString &); + void formWindowActivated(QDesignerFormWindow *); + +private slots: + void slotSubWindowActivated(QMdiSubWindow*); + +private: + ToolBarManager *m_toolBarManager; +}; + +QT_END_NAMESPACE + +#endif // MAINWINDOW_H diff --git a/src/designer/src/designer/newform.cpp b/src/designer/src/designer/newform.cpp new file mode 100644 index 000000000..34461f52a --- /dev/null +++ b/src/designer/src/designer/newform.cpp @@ -0,0 +1,227 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "newform.h" +#include "qdesigner_workbench.h" +#include "qdesigner_actions.h" +#include "qdesigner_formwindow.h" +#include "qdesigner_settings.h" + +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +NewForm::NewForm(QDesignerWorkbench *workbench, QWidget *parentWidget, const QString &fileName) + : QDialog(parentWidget, +#ifdef Q_WS_MAC + Qt::Tool | +#endif + Qt::WindowTitleHint | Qt::WindowSystemMenuHint), + m_fileName(fileName), + m_newFormWidget(QDesignerNewFormWidgetInterface::createNewFormWidget(workbench->core())), + m_workbench(workbench), + m_chkShowOnStartup(new QCheckBox(tr("Show this Dialog on Startup"))), + m_createButton(new QPushButton(QApplication::translate("NewForm", "C&reate", 0, QApplication::UnicodeUTF8))), + m_recentButton(new QPushButton(QApplication::translate("NewForm", "Recent", 0, QApplication::UnicodeUTF8))), + m_buttonBox(0) +{ + setWindowTitle(tr("New Form")); + QDesignerSettings settings(m_workbench->core()); + + QVBoxLayout *vBoxLayout = new QVBoxLayout; + + connect(m_newFormWidget, SIGNAL(templateActivated()), this, SLOT(slotTemplateActivated())); + connect(m_newFormWidget, SIGNAL(currentTemplateChanged(bool)), this, SLOT(slotCurrentTemplateChanged(bool))); + vBoxLayout->addWidget(m_newFormWidget); + + QFrame *horizontalLine = new QFrame; + horizontalLine->setFrameShape(QFrame::HLine); + horizontalLine->setFrameShadow(QFrame::Sunken); + vBoxLayout->addWidget(horizontalLine); + + m_chkShowOnStartup->setChecked(settings.showNewFormOnStartup()); + vBoxLayout->addWidget(m_chkShowOnStartup); + + m_buttonBox = createButtonBox(); + vBoxLayout->addWidget(m_buttonBox); + setLayout(vBoxLayout); + + resize(500, 400); + slotCurrentTemplateChanged(m_newFormWidget->hasCurrentTemplate()); +} + +QDialogButtonBox *NewForm::createButtonBox() +{ + // Dialog buttons with 'recent files' + QDialogButtonBox *buttonBox = new QDialogButtonBox; + buttonBox->addButton(QApplication::translate("NewForm", "&Close", 0, + QApplication::UnicodeUTF8), QDialogButtonBox::RejectRole); + buttonBox->addButton(m_createButton, QDialogButtonBox::AcceptRole); + buttonBox->addButton(QApplication::translate("NewForm", "&Open...", 0, + QApplication::UnicodeUTF8), QDialogButtonBox::ActionRole); + buttonBox->addButton(m_recentButton, QDialogButtonBox::ActionRole); + QDesignerActions *da = m_workbench->actionManager(); + QMenu *recentFilesMenu = new QMenu(tr("&Recent Forms"), m_recentButton); + // Pop the "Recent Files" stuff in here. + const QList recentActions = da->recentFilesActions()->actions(); + if (!recentActions.empty()) { + const QList::const_iterator acend = recentActions.constEnd(); + for (QList::const_iterator it = recentActions.constBegin(); it != acend; ++it) { + recentFilesMenu->addAction(*it); + connect(*it, SIGNAL(triggered()), this, SLOT(recentFileChosen())); + } + } + m_recentButton->setMenu(recentFilesMenu); + connect(buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(slotButtonBoxClicked(QAbstractButton*))); + return buttonBox; +} + +NewForm::~NewForm() +{ + QDesignerSettings settings (m_workbench->core()); + settings.setShowNewFormOnStartup(m_chkShowOnStartup->isChecked()); +} + +void NewForm::recentFileChosen() +{ + QAction *action = qobject_cast(sender()); + if (!action) + return; + if (action->objectName() == QLatin1String("__qt_action_clear_menu_")) + return; + close(); +} + +void NewForm::slotCurrentTemplateChanged(bool templateSelected) +{ + if (templateSelected) { + m_createButton->setEnabled(true); + m_createButton->setDefault(true); + } else { + m_createButton->setEnabled(false); + } +} + +void NewForm::slotTemplateActivated() +{ + m_createButton->animateClick(0); +} + +void NewForm::slotButtonBoxClicked(QAbstractButton *btn) +{ + switch (m_buttonBox->buttonRole(btn)) { + case QDialogButtonBox::RejectRole: + reject(); + break; + case QDialogButtonBox::ActionRole: + if (btn != m_recentButton) { + m_fileName.clear(); + if (m_workbench->actionManager()->openForm(this)) + accept(); + } + break; + case QDialogButtonBox::AcceptRole: { + QString errorMessage; + if (openTemplate(&errorMessage)) { + accept(); + } else { + QMessageBox::warning(this, tr("Read error"), errorMessage); + } + } + break; + default: + break; + } +} + +bool NewForm::openTemplate(QString *ptrToErrorMessage) +{ + const QString contents = m_newFormWidget->currentTemplate(ptrToErrorMessage); + if (contents.isEmpty()) + return false; + // Write to temporary file and open + QString tempPattern = QDir::tempPath(); + if (!tempPattern.endsWith(QDir::separator())) // platform-dependant + tempPattern += QDir::separator(); + tempPattern += QLatin1String("XXXXXX.ui"); + QTemporaryFile tempFormFile(tempPattern); + + tempFormFile.setAutoRemove(true); + if (!tempFormFile.open()) { + *ptrToErrorMessage = tr("A temporary form file could not be created in %1.").arg(QDir::tempPath()); + return false; + } + const QString tempFormFileName = tempFormFile.fileName(); + tempFormFile.write(contents.toUtf8()); + if (!tempFormFile.flush()) { + *ptrToErrorMessage = tr("The temporary form file %1 could not be written.").arg(tempFormFileName); + return false; + } + tempFormFile.close(); + return m_workbench->openTemplate(tempFormFileName, m_fileName, ptrToErrorMessage); +} + +QImage NewForm::grabForm(QDesignerFormEditorInterface *core, + QIODevice &file, + const QString &workingDir, + const qdesigner_internal::DeviceProfile &dp) +{ + return qdesigner_internal::NewFormWidget::grabForm(core, file, workingDir, dp); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/newform.h b/src/designer/src/designer/newform.h new file mode 100644 index 000000000..ad51118b9 --- /dev/null +++ b/src/designer/src/designer/newform.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef NEWFORM_H +#define NEWFORM_H + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + class DeviceProfile; +} + +class QDesignerFormEditorInterface; +class QDesignerNewFormWidgetInterface; +class QDesignerWorkbench; + +class QCheckBox; +class QAbstractButton; +class QPushButton; +class QDialogButtonBox; +class QImage; +class QIODevice; + +class NewForm: public QDialog +{ + Q_OBJECT + Q_DISABLE_COPY(NewForm) + +public: + NewForm(QDesignerWorkbench *workbench, + QWidget *parentWidget, + // Use that file name instead of a temporary one + const QString &fileName = QString()); + + virtual ~NewForm(); + + // Convenience for implementing file dialogs with preview + static QImage grabForm(QDesignerFormEditorInterface *core, + QIODevice &file, + const QString &workingDir, + const qdesigner_internal::DeviceProfile &dp); + +private slots: + void slotButtonBoxClicked(QAbstractButton *btn); + void recentFileChosen(); + void slotCurrentTemplateChanged(bool templateSelected); + void slotTemplateActivated(); + +private: + QDialogButtonBox *createButtonBox(); + bool openTemplate(QString *ptrToErrorMessage); + + QString m_fileName; + QDesignerNewFormWidgetInterface *m_newFormWidget; + QDesignerWorkbench *m_workbench; + QCheckBox *m_chkShowOnStartup; + QPushButton *m_createButton; + QPushButton *m_recentButton; + QDialogButtonBox *m_buttonBox; +}; + +QT_END_NAMESPACE + +#endif // NEWFORM_H diff --git a/src/designer/src/designer/preferencesdialog.cpp b/src/designer/src/designer/preferencesdialog.cpp new file mode 100644 index 000000000..a27e366a5 --- /dev/null +++ b/src/designer/src/designer/preferencesdialog.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "preferencesdialog.h" +#include "ui_preferencesdialog.h" +#include "qdesigner_appearanceoptions.h" + +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +PreferencesDialog::PreferencesDialog(QDesignerFormEditorInterface *core, QWidget *parentWidget) : + QDialog(parentWidget), + m_ui(new Ui::PreferencesDialog()), + m_core(core) +{ + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + m_ui->setupUi(this); + + m_optionsPages = core->optionsPages(); + + m_ui->m_optionTabWidget->clear(); + foreach (QDesignerOptionsPageInterface *optionsPage, m_optionsPages) { + QWidget *page = optionsPage->createPage(this); + m_ui->m_optionTabWidget->addTab(page, optionsPage->name()); + if (QDesignerAppearanceOptionsWidget *appearanceWidget = qobject_cast(page)) + connect(appearanceWidget, SIGNAL(uiModeChanged(bool)), this, SLOT(slotUiModeChanged(bool))); + } + + connect(m_ui->m_dialogButtonBox, SIGNAL(rejected()), this, SLOT(slotRejected())); + connect(m_ui->m_dialogButtonBox, SIGNAL(accepted()), this, SLOT(slotAccepted())); + connect(applyButton(), SIGNAL(clicked()), this, SLOT(slotApply())); +} + +PreferencesDialog::~PreferencesDialog() +{ + delete m_ui; +} + +QPushButton *PreferencesDialog::applyButton() const +{ + return m_ui->m_dialogButtonBox->button(QDialogButtonBox::Apply); +} + +void PreferencesDialog::slotApply() +{ + foreach (QDesignerOptionsPageInterface *optionsPage, m_optionsPages) + optionsPage->apply(); +} + +void PreferencesDialog::slotAccepted() +{ + slotApply(); + closeOptionPages(); + accept(); +} + +void PreferencesDialog::slotRejected() +{ + closeOptionPages(); + reject(); +} + +void PreferencesDialog::slotUiModeChanged(bool modified) +{ + // Cannot "apply" a ui mode change (destroy the dialogs parent) + applyButton()->setEnabled(!modified); +} + +void PreferencesDialog::closeOptionPages() +{ + foreach (QDesignerOptionsPageInterface *optionsPage, m_optionsPages) + optionsPage->finish(); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/preferencesdialog.h b/src/designer/src/designer/preferencesdialog.h new file mode 100644 index 000000000..5ffd7d365 --- /dev/null +++ b/src/designer/src/designer/preferencesdialog.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PREFERENCESDIALOG_H +#define PREFERENCESDIALOG_H + +#include + +QT_BEGIN_NAMESPACE + +class QPushButton; +class QDesignerFormEditorInterface; +class QDesignerOptionsPageInterface; + +namespace Ui { + class PreferencesDialog; +} + +class PreferencesDialog: public QDialog +{ + Q_OBJECT +public: + explicit PreferencesDialog(QDesignerFormEditorInterface *core, QWidget *parentWidget = 0); + ~PreferencesDialog(); + + +private slots: + void slotAccepted(); + void slotRejected(); + void slotApply(); + void slotUiModeChanged(bool modified); + +private: + QPushButton *applyButton() const; + void closeOptionPages(); + + Ui::PreferencesDialog *m_ui; + QDesignerFormEditorInterface *m_core; + QList m_optionsPages; +}; + +QT_END_NAMESPACE + +#endif // PREFERENCESDIALOG_H diff --git a/src/designer/src/designer/preferencesdialog.ui b/src/designer/src/designer/preferencesdialog.ui new file mode 100644 index 000000000..28d14bb83 --- /dev/null +++ b/src/designer/src/designer/preferencesdialog.ui @@ -0,0 +1,91 @@ + + + PreferencesDialog + + + + 0 + 0 + 474 + 304 + + + + + 0 + 0 + + + + Preferences + + + true + + + + + + + 0 + 0 + + + + 0 + + + + Tab 1 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Apply|QDialogButtonBox::Ok + + + + + + + + + m_dialogButtonBox + accepted() + PreferencesDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + m_dialogButtonBox + rejected() + PreferencesDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/designer/src/designer/qdesigner.cpp b/src/designer/src/designer/qdesigner.cpp new file mode 100644 index 000000000..1e838c197 --- /dev/null +++ b/src/designer/src/designer/qdesigner.cpp @@ -0,0 +1,320 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// designer +#include "qdesigner.h" +#include "qdesigner_actions.h" +#include "qdesigner_server.h" +#include "qdesigner_settings.h" +#include "qdesigner_workbench.h" +#include "mainwindow.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +static const char *designerApplicationName = "Designer"; +static const char *designerWarningPrefix = "Designer: "; + +static void designerMessageHandler(QtMsgType type, const char *msg) +{ + // Only Designer warnings are displayed as box + QDesigner *designerApp = qDesigner; + if (type != QtWarningMsg || !designerApp || qstrncmp(designerWarningPrefix, msg, qstrlen(designerWarningPrefix))) { + qInstallMsgHandler(0); + qt_message_output(type, msg); + qInstallMsgHandler (designerMessageHandler); + return; + } + designerApp->showErrorMessage(msg); +} + +QDesigner::QDesigner(int &argc, char **argv) + : QApplication(argc, argv), + m_server(0), + m_client(0), + m_workbench(0), m_suppressNewFormShow(false) +{ + setOrganizationName(QLatin1String("Trolltech")); + setApplicationName(QLatin1String(designerApplicationName)); + QDesignerComponents::initializeResources(); + +#ifndef Q_WS_MAC + setWindowIcon(QIcon(QLatin1String(":/trolltech/designer/images/designer.png"))); +#endif + initialize(); +} + +QDesigner::~QDesigner() +{ + if (m_workbench) + delete m_workbench; + if (m_server) + delete m_server; + if (m_client) + delete m_client; +} + +void QDesigner::showErrorMessage(const char *message) +{ + // strip the prefix + const QString qMessage = QString::fromUtf8(message + qstrlen(designerWarningPrefix)); + // If there is no main window yet, just store the message. + // The QErrorMessage would otherwise be hidden by the main window. + if (m_mainWindow) { + showErrorMessageBox(qMessage); + } else { + qInstallMsgHandler(0); + qt_message_output(QtWarningMsg, message); // just in case we crash + qInstallMsgHandler (designerMessageHandler); + m_initializationErrors += qMessage; + m_initializationErrors += QLatin1Char('\n'); + } +} + +void QDesigner::showErrorMessageBox(const QString &msg) +{ + // Manually suppress consecutive messages. + // This happens if for example sth is wrong with custom widget creation. + // The same warning will be displayed by Widget box D&D and form Drop + // while trying to create instance. + if (m_errorMessageDialog && m_lastErrorMessage == msg) + return; + + if (!m_errorMessageDialog) { + m_lastErrorMessage.clear(); + m_errorMessageDialog = new QErrorMessage(m_mainWindow); + const QString title = QCoreApplication::translate("QDesigner", "%1 - warning").arg(QLatin1String(designerApplicationName)); + m_errorMessageDialog->setWindowTitle(title); + m_errorMessageDialog->setMinimumSize(QSize(600, 250)); + m_errorMessageDialog->setWindowFlags(m_errorMessageDialog->windowFlags() & ~Qt::WindowContextHelpButtonHint); + } + m_errorMessageDialog->showMessage(msg); + m_lastErrorMessage = msg; +} + +QDesignerWorkbench *QDesigner::workbench() const +{ + return m_workbench; +} + +QDesignerServer *QDesigner::server() const +{ + return m_server; +} + +bool QDesigner::parseCommandLineArgs(QStringList &fileNames, QString &resourceDir) +{ + const QStringList args = arguments(); + const QStringList::const_iterator acend = args.constEnd(); + QStringList::const_iterator it = args.constBegin(); + for (++it; it != acend; ++it) { + const QString &argument = *it; + do { + // Arguments + if (!argument.startsWith(QLatin1Char('-'))) { + if (!fileNames.contains(argument)) + fileNames.append(argument); + break; + } + // Options + if (argument == QLatin1String("-server")) { + m_server = new QDesignerServer(); + printf("%d\n", m_server->serverPort()); + fflush(stdout); + break; + } + if (argument == QLatin1String("-client")) { + bool ok = true; + if (++it == acend) { + qWarning("** WARNING The option -client requires an argument"); + return false; + } + const quint16 port = it->toUShort(&ok); + if (ok) { + m_client = new QDesignerClient(port, this); + } else { + qWarning("** WARNING Non-numeric argument specified for -client"); + return false; + } + break; + } + if (argument == QLatin1String("-resourcedir")) { + if (++it == acend) { + qWarning("** WARNING The option -resourcedir requires an argument"); + return false; + } + resourceDir = QFile::decodeName(it->toLocal8Bit()); + break; + } + if (argument == QLatin1String("-enableinternaldynamicproperties")) { + QDesignerPropertySheet::setInternalDynamicPropertiesEnabled(true); + break; + } + const QString msg = QString::fromUtf8("** WARNING Unknown option %1").arg(argument); + qWarning("%s", qPrintable(msg)); + } while (false); + } + return true; +} + +void QDesigner::initialize() +{ + // initialize the sub components + QStringList files; + QString resourceDir = QLibraryInfo::location(QLibraryInfo::TranslationsPath); + parseCommandLineArgs(files, resourceDir); + + QTranslator *translator = new QTranslator(this); + QTranslator *qtTranslator = new QTranslator(this); + + const QString localSysName = QLocale::system().name(); + QString translatorFileName = QLatin1String("designer_"); + translatorFileName += localSysName; + translator->load(translatorFileName, resourceDir); + + translatorFileName = QLatin1String("qt_"); + translatorFileName += localSysName; + qtTranslator->load(translatorFileName, resourceDir); + installTranslator(translator); + installTranslator(qtTranslator); + + if (QLibraryInfo::licensedProducts() == QLatin1String("Console")) { + QMessageBox::information(0, tr("Qt Designer"), + tr("This application cannot be used for the Console edition of Qt")); + QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection); + return; + } + + m_workbench = new QDesignerWorkbench(); + + emit initialized(); + qInstallMsgHandler(designerMessageHandler); // Warn when loading faulty forms + + m_suppressNewFormShow = m_workbench->readInBackup(); + + if (!files.empty()) { + const QStringList::const_iterator cend = files.constEnd(); + for (QStringList::const_iterator it = files.constBegin(); it != cend; ++it) { + // Ensure absolute paths for recent file list to be unique + QString fileName = *it; + const QFileInfo fi(fileName); + if (fi.exists() && fi.isRelative()) + fileName = fi.absoluteFilePath(); + m_workbench->readInForm(fileName); + } + } + if ( m_workbench->formWindowCount()) + m_suppressNewFormShow = true; + + // Show up error box with parent now if something went wrong + if (m_initializationErrors.isEmpty()) { + if (!m_suppressNewFormShow && QDesignerSettings(m_workbench->core()).showNewFormOnStartup()) + QTimer::singleShot(100, this, SLOT(callCreateForm())); // won't show anything if suppressed + } else { + showErrorMessageBox(m_initializationErrors); + m_initializationErrors.clear(); + } +} + +bool QDesigner::event(QEvent *ev) +{ + bool eaten; + switch (ev->type()) { + case QEvent::FileOpen: + // Set it true first since, if it's a Qt 3 form, the messagebox from convert will fire the timer. + m_suppressNewFormShow = true; + if (!m_workbench->readInForm(static_cast(ev)->file())) + m_suppressNewFormShow = false; + eaten = true; + break; + case QEvent::Close: { + QCloseEvent *closeEvent = static_cast(ev); + closeEvent->setAccepted(m_workbench->handleClose()); + if (closeEvent->isAccepted()) { + // We're going down, make sure that we don't get our settings saved twice. + if (m_mainWindow) + m_mainWindow->setCloseEventPolicy(MainWindowBase::AcceptCloseEvents); + eaten = QApplication::event(ev); + } + eaten = true; + break; + } + default: + eaten = QApplication::event(ev); + break; + } + return eaten; +} + +void QDesigner::setMainWindow(MainWindowBase *tw) +{ + m_mainWindow = tw; +} + +MainWindowBase *QDesigner::mainWindow() const +{ + return m_mainWindow; +} + +void QDesigner::callCreateForm() +{ + if (!m_suppressNewFormShow) + m_workbench->actionManager()->createForm(); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/qdesigner.h b/src/designer/src/designer/qdesigner.h new file mode 100644 index 000000000..ff45edffd --- /dev/null +++ b/src/designer/src/designer/qdesigner.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_H +#define QDESIGNER_H + +#include +#include + +QT_BEGIN_NAMESPACE + +#define qDesigner \ + (static_cast(QCoreApplication::instance())) + +class QDesignerWorkbench; +class QDesignerToolWindow; +class MainWindowBase; +class QDesignerServer; +class QDesignerClient; +class QErrorMessage; + +class QDesigner: public QApplication +{ + Q_OBJECT +public: + QDesigner(int &argc, char **argv); + virtual ~QDesigner(); + + QDesignerWorkbench *workbench() const; + QDesignerServer *server() const; + MainWindowBase *mainWindow() const; + void setMainWindow(MainWindowBase *tw); + +protected: + bool event(QEvent *ev); + +signals: + void initialized(); + +public slots: + void showErrorMessage(const char *message); + +private slots: + void initialize(); + void callCreateForm(); + +private: + bool parseCommandLineArgs(QStringList &fileNames, QString &resourceDir); + void showErrorMessageBox(const QString &); + + QDesignerServer *m_server; + QDesignerClient *m_client; + QDesignerWorkbench *m_workbench; + QPointer m_mainWindow; + QPointer m_errorMessageDialog; + + QString m_initializationErrors; + QString m_lastErrorMessage; + bool m_suppressNewFormShow; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_H diff --git a/src/designer/src/designer/qdesigner_actions.cpp b/src/designer/src/designer/qdesigner_actions.cpp new file mode 100644 index 000000000..a84e0732d --- /dev/null +++ b/src/designer/src/designer/qdesigner_actions.cpp @@ -0,0 +1,1437 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_actions.h" +#include "designer_enums.h" +#include "qdesigner.h" +#include "qdesigner_workbench.h" +#include "qdesigner_formwindow.h" +#include "newform.h" +#include "versiondialog.h" +#include "saveformastemplate.h" +#include "qdesigner_toolwindow.h" +#include "preferencesdialog.h" +#include "appfontdialog.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include "qdesigner_integration_p.h" + +// sdk +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +const char *QDesignerActions::defaultToolbarPropertyName = "__qt_defaultToolBarAction"; + +//#ifdef Q_WS_MAC +# define NONMODAL_PREVIEW +//#endif + +static QAction *createSeparator(QObject *parent) { + QAction * rc = new QAction(parent); + rc->setSeparator(true); + return rc; +} + +static QActionGroup *createActionGroup(QObject *parent, bool exclusive = false) { + QActionGroup * rc = new QActionGroup(parent); + rc->setExclusive(exclusive); + return rc; +} + +static inline QString savedMessage(const QString &fileName) +{ + return QDesignerActions::tr("Saved %1.").arg(fileName); +} + +// Prompt for a file and make sure an extension is added +// unless the user explicitly specifies another one. + +static QString getSaveFileNameWithExtension(QWidget *parent, const QString &title, QString dir, const QString &filter, const QString &extension) +{ + const QChar dot = QLatin1Char('.'); + + QString saveFile; + while (true) { + saveFile = QFileDialog::getSaveFileName(parent, title, dir, filter, 0, QFileDialog::DontConfirmOverwrite); + if (saveFile.isEmpty()) + return saveFile; + + const QFileInfo fInfo(saveFile); + if (fInfo.suffix().isEmpty() && !fInfo.fileName().endsWith(dot)) { + saveFile += dot; + saveFile += extension; + } + + const QFileInfo fi(saveFile); + if (!fi.exists()) + break; + + const QString prompt = QDesignerActions::tr("%1 already exists.\nDo you want to replace it?").arg(fi.fileName()); + if (QMessageBox::warning(parent, title, prompt, QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) + break; + + dir = saveFile; + } + return saveFile; +} + +QDesignerActions::QDesignerActions(QDesignerWorkbench *workbench) + : QObject(workbench), + m_workbench(workbench), + m_core(workbench->core()), + m_settings(workbench->core()), + m_backupTimer(new QTimer(this)), + m_fileActions(createActionGroup(this)), + m_recentFilesActions(createActionGroup(this)), + m_editActions(createActionGroup(this)), + m_formActions(createActionGroup(this)), + m_settingsActions(createActionGroup(this)), + m_windowActions(createActionGroup(this)), + m_toolActions(createActionGroup(this, true)), + m_helpActions(0), + m_styleActions(0), + m_editWidgetsAction(new QAction(tr("Edit Widgets"), this)), + m_newFormAction(new QAction(qdesigner_internal::createIconSet(QLatin1String("filenew.png")), tr("&New..."), this)), + m_openFormAction(new QAction(qdesigner_internal::createIconSet(QLatin1String("fileopen.png")), tr("&Open..."), this)), + m_saveFormAction(new QAction(qdesigner_internal::createIconSet(QLatin1String("filesave.png")), tr("&Save"), this)), + m_saveFormAsAction(new QAction(tr("Save &As..."), this)), + m_saveAllFormsAction(new QAction(tr("Save A&ll"), this)), + m_saveFormAsTemplateAction(new QAction(tr("Save As &Template..."), this)), + m_closeFormAction(new QAction(tr("&Close"), this)), + m_savePreviewImageAction(new QAction(tr("Save &Image..."), this)), + m_printPreviewAction(new QAction(tr("&Print..."), this)), + m_quitAction(new QAction(tr("&Quit"), this)), + m_previewFormAction(0), + m_viewCodeAction(new QAction(tr("View &Code..."), this)), + m_minimizeAction(new QAction(tr("&Minimize"), this)), + m_bringAllToFrontSeparator(createSeparator(this)), + m_bringAllToFrontAction(new QAction(tr("Bring All to Front"), this)), + m_windowListSeparatorAction(createSeparator(this)), + m_preferencesAction(new QAction(tr("Preferences..."), this)), + m_appFontAction(new QAction(tr("Additional Fonts..."), this)), + m_appFontDialog(0), +#ifndef QT_NO_PRINTER + m_printer(0), +#endif + m_previewManager(0) +{ +#ifdef Q_WS_X11 + m_newFormAction->setIcon(QIcon::fromTheme("document-new", m_newFormAction->icon())); + m_openFormAction->setIcon(QIcon::fromTheme("document-open", m_openFormAction->icon())); + m_saveFormAction->setIcon(QIcon::fromTheme("document-save", m_saveFormAction->icon())); + m_saveFormAsAction->setIcon(QIcon::fromTheme("document-save-as", m_saveFormAsAction->icon())); + m_printPreviewAction->setIcon(QIcon::fromTheme("document-print", m_printPreviewAction->icon())); + m_closeFormAction->setIcon(QIcon::fromTheme("window-close", m_closeFormAction->icon())); + m_quitAction->setIcon(QIcon::fromTheme("application-exit", m_quitAction->icon())); +#endif + + Q_ASSERT(m_core != 0); + qdesigner_internal::QDesignerFormWindowManager *ifwm = qobject_cast(m_core->formWindowManager()); + Q_ASSERT(ifwm); + m_previewManager = ifwm->previewManager(); + m_previewFormAction = ifwm->actionDefaultPreview(); + m_styleActions = ifwm->actionGroupPreviewInStyle(); + connect(ifwm, SIGNAL(formWindowSettingsChanged(QDesignerFormWindowInterface*)), + this, SLOT(formWindowSettingsChanged(QDesignerFormWindowInterface*))); + + m_editWidgetsAction->setObjectName(QLatin1String("__qt_edit_widgets_action")); + m_newFormAction->setObjectName(QLatin1String("__qt_new_form_action")); + m_openFormAction->setObjectName(QLatin1String("__qt_open_form_action")); + m_saveFormAction->setObjectName(QLatin1String("__qt_save_form_action")); + m_saveFormAsAction->setObjectName(QLatin1String("__qt_save_form_as_action")); + m_saveAllFormsAction->setObjectName(QLatin1String("__qt_save_all_forms_action")); + m_saveFormAsTemplateAction->setObjectName(QLatin1String("__qt_save_form_as_template_action")); + m_closeFormAction->setObjectName(QLatin1String("__qt_close_form_action")); + m_quitAction->setObjectName(QLatin1String("__qt_quit_action")); + m_previewFormAction->setObjectName(QLatin1String("__qt_preview_form_action")); + m_viewCodeAction->setObjectName(QLatin1String("__qt_preview_code_action")); + m_minimizeAction->setObjectName(QLatin1String("__qt_minimize_action")); + m_bringAllToFrontAction->setObjectName(QLatin1String("__qt_bring_all_to_front_action")); + m_preferencesAction->setObjectName(QLatin1String("__qt_preferences_action")); + + m_helpActions = createHelpActions(); + + m_newFormAction->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + m_openFormAction->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + m_saveFormAction->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + + QDesignerFormWindowManagerInterface *formWindowManager = m_core->formWindowManager(); + Q_ASSERT(formWindowManager != 0); + +// +// file actions +// + m_newFormAction->setShortcut(QKeySequence::New); + connect(m_newFormAction, SIGNAL(triggered()), this, SLOT(createForm())); + m_fileActions->addAction(m_newFormAction); + + m_openFormAction->setShortcut(QKeySequence::Open); + connect(m_openFormAction, SIGNAL(triggered()), this, SLOT(slotOpenForm())); + m_fileActions->addAction(m_openFormAction); + + m_fileActions->addAction(createRecentFilesMenu()); + m_fileActions->addAction(createSeparator(this)); + + m_saveFormAction->setShortcut(QKeySequence::Save); + connect(m_saveFormAction, SIGNAL(triggered()), this, SLOT(saveForm())); + m_fileActions->addAction(m_saveFormAction); + + connect(m_saveFormAsAction, SIGNAL(triggered()), this, SLOT(saveFormAs())); + m_fileActions->addAction(m_saveFormAsAction); + +#ifdef Q_OS_MAC + m_saveAllFormsAction->setShortcut(tr("ALT+CTRL+S")); +#else + m_saveAllFormsAction->setShortcut(tr("CTRL+SHIFT+S")); // Commonly "Save As" on Mac +#endif + connect(m_saveAllFormsAction, SIGNAL(triggered()), this, SLOT(saveAllForms())); + m_fileActions->addAction(m_saveAllFormsAction); + + connect(m_saveFormAsTemplateAction, SIGNAL(triggered()), this, SLOT(saveFormAsTemplate())); + m_fileActions->addAction(m_saveFormAsTemplateAction); + + m_fileActions->addAction(createSeparator(this)); + + m_printPreviewAction->setShortcut(QKeySequence::Print); + connect(m_printPreviewAction, SIGNAL(triggered()), this, SLOT(printPreviewImage())); + m_fileActions->addAction(m_printPreviewAction); + m_printPreviewAction->setObjectName(QLatin1String("__qt_print_action")); + + connect(m_savePreviewImageAction, SIGNAL(triggered()), this, SLOT(savePreviewImage())); + m_savePreviewImageAction->setObjectName(QLatin1String("__qt_saveimage_action")); + m_fileActions->addAction(m_savePreviewImageAction); + m_fileActions->addAction(createSeparator(this)); + + m_closeFormAction->setShortcut(QKeySequence::Close); + connect(m_closeFormAction, SIGNAL(triggered()), this, SLOT(closeForm())); + m_fileActions->addAction(m_closeFormAction); + updateCloseAction(); + + m_fileActions->addAction(createSeparator(this)); + + m_quitAction->setShortcuts(QKeySequence::Quit); + m_quitAction->setMenuRole(QAction::QuitRole); + connect(m_quitAction, SIGNAL(triggered()), this, SLOT(shutdown())); + m_fileActions->addAction(m_quitAction); + +// +// edit actions +// + QAction *undoAction = formWindowManager->actionUndo(); + undoAction->setObjectName(QLatin1String("__qt_undo_action")); + undoAction->setShortcut(QKeySequence::Undo); + m_editActions->addAction(undoAction); + + QAction *redoAction = formWindowManager->actionRedo(); + redoAction->setObjectName(QLatin1String("__qt_redo_action")); + redoAction->setShortcut(QKeySequence::Redo); + m_editActions->addAction(redoAction); + + m_editActions->addAction(createSeparator(this)); + + m_editActions->addAction(formWindowManager->actionCut()); + m_editActions->addAction(formWindowManager->actionCopy()); + m_editActions->addAction(formWindowManager->actionPaste()); + m_editActions->addAction(formWindowManager->actionDelete()); + + m_editActions->addAction(formWindowManager->actionSelectAll()); + + m_editActions->addAction(createSeparator(this)); + + m_editActions->addAction(formWindowManager->actionLower()); + m_editActions->addAction(formWindowManager->actionRaise()); + + formWindowManager->actionLower()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionRaise()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + +// +// edit mode actions +// + + m_editWidgetsAction->setCheckable(true); + QList shortcuts; + shortcuts.append(QKeySequence(Qt::Key_F3)); +#if QT_VERSION >= 0x040900 // "ESC" switching to edit mode: Activate once item delegates handle shortcut overrides for ESC. + shortcuts.append(QKeySequence(Qt::Key_Escape)); +#endif + m_editWidgetsAction->setShortcuts(shortcuts); + QIcon fallback(m_core->resourceLocation() + QLatin1String("/widgettool.png")); + m_editWidgetsAction->setIcon(QIcon::fromTheme("designer-edit-widget", fallback)); + connect(m_editWidgetsAction, SIGNAL(triggered()), this, SLOT(editWidgetsSlot())); + m_editWidgetsAction->setChecked(true); + m_editWidgetsAction->setEnabled(false); + m_editWidgetsAction->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + m_toolActions->addAction(m_editWidgetsAction); + + connect(formWindowManager, SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)), + this, SLOT(activeFormWindowChanged(QDesignerFormWindowInterface*))); + + QList builtinPlugins = QPluginLoader::staticInstances(); + builtinPlugins += m_core->pluginManager()->instances(); + foreach (QObject *plugin, builtinPlugins) { + if (QDesignerFormEditorPluginInterface *formEditorPlugin = qobject_cast(plugin)) { + if (QAction *action = formEditorPlugin->action()) { + m_toolActions->addAction(action); + action->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + action->setCheckable(true); + } + } + } + + connect(m_preferencesAction, SIGNAL(triggered()), this, SLOT(showPreferencesDialog())); + m_preferencesAction->setMenuRole(QAction::PreferencesRole); + m_settingsActions->addAction(m_preferencesAction); + + connect(m_appFontAction, SIGNAL(triggered()), this, SLOT(showAppFontDialog())); + m_appFontAction->setMenuRole(QAction::PreferencesRole); + m_settingsActions->addAction(m_appFontAction); +// +// form actions +// + + m_formActions->addAction(formWindowManager->actionHorizontalLayout()); + m_formActions->addAction(formWindowManager->actionVerticalLayout()); + m_formActions->addAction(formWindowManager->actionSplitHorizontal()); + m_formActions->addAction(formWindowManager->actionSplitVertical()); + m_formActions->addAction(formWindowManager->actionGridLayout()); + m_formActions->addAction(formWindowManager->actionFormLayout()); + m_formActions->addAction(formWindowManager->actionBreakLayout()); + m_formActions->addAction(formWindowManager->actionAdjustSize()); + m_formActions->addAction(formWindowManager->actionSimplifyLayout()); + m_formActions->addAction(createSeparator(this)); + + formWindowManager->actionHorizontalLayout()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionVerticalLayout()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionSplitHorizontal()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionSplitVertical()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionGridLayout()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionFormLayout()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionBreakLayout()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + formWindowManager->actionAdjustSize()->setProperty(QDesignerActions::defaultToolbarPropertyName, true); + + m_previewFormAction->setShortcut(tr("CTRL+R")); + m_formActions->addAction(m_previewFormAction); + connect(m_previewManager, SIGNAL(firstPreviewOpened()), this, SLOT(updateCloseAction())); + connect(m_previewManager, SIGNAL(lastPreviewClosed()), this, SLOT(updateCloseAction())); + + connect(m_viewCodeAction, SIGNAL(triggered()), this, SLOT(viewCode())); + // Preview code only in Cpp + if (qt_extension(m_core->extensionManager(), m_core) == 0) + m_formActions->addAction(m_viewCodeAction); + + m_formActions->addAction(createSeparator(this)); + + m_formActions->addAction(ifwm->actionShowFormWindowSettingsDialog()); +// +// window actions +// + m_minimizeAction->setEnabled(false); + m_minimizeAction->setCheckable(true); + m_minimizeAction->setShortcut(tr("CTRL+M")); + connect(m_minimizeAction, SIGNAL(triggered()), m_workbench, SLOT(toggleFormMinimizationState())); + m_windowActions->addAction(m_minimizeAction); + + m_windowActions->addAction(m_bringAllToFrontSeparator); + connect(m_bringAllToFrontAction, SIGNAL(triggered()), m_workbench, SLOT(bringAllToFront())); + m_windowActions->addAction(m_bringAllToFrontAction); + m_windowActions->addAction(m_windowListSeparatorAction); + + setWindowListSeparatorVisible(false); + +// +// connections +// + fixActionContext(); + activeFormWindowChanged(core()->formWindowManager()->activeFormWindow()); + + m_backupTimer->start(180000); // 3min + connect(m_backupTimer, SIGNAL(timeout()), this, SLOT(backupForms())); + + // Enable application font action + connect(formWindowManager, SIGNAL(formWindowAdded(QDesignerFormWindowInterface*)), this, SLOT(formWindowCountChanged())); + connect(formWindowManager, SIGNAL(formWindowRemoved(QDesignerFormWindowInterface*)), this, SLOT(formWindowCountChanged())); + formWindowCountChanged(); +} + +QActionGroup *QDesignerActions::createHelpActions() +{ + QActionGroup *helpActions = createActionGroup(this); + +#ifndef QT_JAMBI_BUILD + QAction *mainHelpAction = new QAction(tr("Qt Designer &Help"), this); + mainHelpAction->setObjectName(QLatin1String("__qt_designer_help_action")); + connect(mainHelpAction, SIGNAL(triggered()), this, SLOT(showDesignerHelp())); + mainHelpAction->setShortcut(Qt::CTRL + Qt::Key_Question); + helpActions->addAction(mainHelpAction); + + helpActions->addAction(createSeparator(this)); + QAction *widgetHelp = new QAction(tr("Current Widget Help"), this); + widgetHelp->setObjectName(QLatin1String("__qt_current_widget_help_action")); + widgetHelp->setShortcut(Qt::Key_F1); + connect(widgetHelp, SIGNAL(triggered()), this, SLOT(showWidgetSpecificHelp())); + helpActions->addAction(widgetHelp); + + helpActions->addAction(createSeparator(this)); + QAction *whatsNewAction = new QAction(tr("What's New in Qt Designer?"), this); + whatsNewAction->setObjectName(QLatin1String("__qt_whats_new_in_qt_designer_action")); + connect(whatsNewAction, SIGNAL(triggered()), this, SLOT(showWhatsNew())); + helpActions->addAction(whatsNewAction); +#endif + + helpActions->addAction(createSeparator(this)); + QAction *aboutPluginsAction = new QAction(tr("About Plugins"), this); + aboutPluginsAction->setObjectName(QLatin1String("__qt_about_plugins_action")); + aboutPluginsAction->setMenuRole(QAction::ApplicationSpecificRole); + connect(aboutPluginsAction, SIGNAL(triggered()), m_core->formWindowManager(), SLOT(aboutPlugins())); + helpActions->addAction(aboutPluginsAction); + + QAction *aboutDesignerAction = new QAction(tr("About Qt Designer"), this); + aboutDesignerAction->setMenuRole(QAction::AboutRole); + aboutDesignerAction->setObjectName(QLatin1String("__qt_about_designer_action")); + connect(aboutDesignerAction, SIGNAL(triggered()), this, SLOT(aboutDesigner())); + helpActions->addAction(aboutDesignerAction); + + QAction *aboutQtAction = new QAction(tr("About Qt"), this); + aboutQtAction->setMenuRole(QAction::AboutQtRole); + aboutQtAction->setObjectName(QLatin1String("__qt_about_qt_action")); + connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt())); + helpActions->addAction(aboutQtAction); + return helpActions; +} + +QDesignerActions::~QDesignerActions() +{ +#ifndef QT_NO_PRINTER + delete m_printer; +#endif +} + +QString QDesignerActions::uiExtension() const +{ + QDesignerLanguageExtension *lang + = qt_extension(m_core->extensionManager(), m_core); + if (lang) + return lang->uiExtension(); + return QLatin1String("ui"); +} + +QAction *QDesignerActions::createRecentFilesMenu() +{ + QMenu *menu = new QMenu; + QAction *act; + // Need to insert this into the QAction. + for (int i = 0; i < MaxRecentFiles; ++i) { + act = new QAction(this); + act->setVisible(false); + connect(act, SIGNAL(triggered()), this, SLOT(openRecentForm())); + m_recentFilesActions->addAction(act); + menu->addAction(act); + } + updateRecentFileActions(); + menu->addSeparator(); + act = new QAction(QIcon::fromTheme("edit-clear"), tr("Clear &Menu"), this); + act->setObjectName(QLatin1String("__qt_action_clear_menu_")); + connect(act, SIGNAL(triggered()), this, SLOT(clearRecentFiles())); + m_recentFilesActions->addAction(act); + menu->addAction(act); + + act = new QAction(QIcon::fromTheme("document-open-recent"), tr("&Recent Forms"), this); + act->setMenu(menu); + return act; +} + +QActionGroup *QDesignerActions::toolActions() const +{ return m_toolActions; } + +QDesignerWorkbench *QDesignerActions::workbench() const +{ return m_workbench; } + +QDesignerFormEditorInterface *QDesignerActions::core() const +{ return m_core; } + +QActionGroup *QDesignerActions::fileActions() const +{ return m_fileActions; } + +QActionGroup *QDesignerActions::editActions() const +{ return m_editActions; } + +QActionGroup *QDesignerActions::formActions() const +{ return m_formActions; } + +QActionGroup *QDesignerActions::settingsActions() const +{ return m_settingsActions; } + +QActionGroup *QDesignerActions::windowActions() const +{ return m_windowActions; } + +QActionGroup *QDesignerActions::helpActions() const +{ return m_helpActions; } + +QActionGroup *QDesignerActions::styleActions() const +{ return m_styleActions; } + +QAction *QDesignerActions::previewFormAction() const +{ return m_previewFormAction; } + +QAction *QDesignerActions::viewCodeAction() const +{ return m_viewCodeAction; } + + +void QDesignerActions::editWidgetsSlot() +{ + QDesignerFormWindowManagerInterface *formWindowManager = core()->formWindowManager(); + for (int i=0; iformWindowCount(); ++i) { + QDesignerFormWindowInterface *formWindow = formWindowManager->formWindow(i); + formWindow->editWidgets(); + } +} + +void QDesignerActions::createForm() +{ + showNewFormDialog(QString()); +} + +void QDesignerActions::showNewFormDialog(const QString &fileName) +{ + closePreview(); + NewForm *dlg = new NewForm(workbench(), workbench()->core()->topLevel(), fileName); + + dlg->setAttribute(Qt::WA_DeleteOnClose); + dlg->setAttribute(Qt::WA_ShowModal); + + dlg->setGeometry(fixDialogRect(dlg->rect())); + dlg->exec(); +} + +void QDesignerActions::slotOpenForm() +{ + openForm(core()->topLevel()); +} + +bool QDesignerActions::openForm(QWidget *parent) +{ + closePreview(); + const QString extension = uiExtension(); + const QStringList fileNames = QFileDialog::getOpenFileNames(parent, tr("Open Form"), + m_openDirectory, tr("Designer UI files (*.%1);;All Files (*)").arg(extension), 0, QFileDialog::DontUseSheet); + + if (fileNames.isEmpty()) + return false; + + bool atLeastOne = false; + foreach (const QString &fileName, fileNames) { + if (readInForm(fileName) && !atLeastOne) + atLeastOne = true; + } + + return atLeastOne; +} + +bool QDesignerActions::saveFormAs(QDesignerFormWindowInterface *fw) +{ + const QString extension = uiExtension(); + + QString dir = fw->fileName(); + if (dir.isEmpty()) { + do { + // Build untitled name + if (!m_saveDirectory.isEmpty()) { + dir = m_saveDirectory; + break; + } + if (!m_openDirectory.isEmpty()) { + dir = m_openDirectory; + break; + } + dir = QDir::current().absolutePath(); + } while (false); + dir += QDir::separator(); + dir += QLatin1String("untitled."); + dir += extension; + } + + const QString saveFile = getSaveFileNameWithExtension(fw, tr("Save Form As"), dir, tr("Designer UI files (*.%1);;All Files (*)").arg(extension), extension); + if (saveFile.isEmpty()) + return false; + + fw->setFileName(saveFile); + return writeOutForm(fw, saveFile); +} + +void QDesignerActions::saveForm() +{ + if (QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow()) { + if (saveForm(fw)) + showStatusBarMessage(savedMessage(QFileInfo(fw->fileName()).fileName())); + } +} + +void QDesignerActions::saveAllForms() +{ + QString fileNames; + QDesignerFormWindowManagerInterface *formWindowManager = core()->formWindowManager(); + if (const int totalWindows = formWindowManager->formWindowCount()) { + const QString separator = QLatin1String(", "); + for (int i = 0; i < totalWindows; ++i) { + QDesignerFormWindowInterface *fw = formWindowManager->formWindow(i); + if (fw && fw->isDirty()) { + formWindowManager->setActiveFormWindow(fw); + if (saveForm(fw)) { + if (!fileNames.isEmpty()) + fileNames += separator; + fileNames += QFileInfo(fw->fileName()).fileName(); + } else { + break; + } + } + } + } + + if (!fileNames.isEmpty()) { + showStatusBarMessage(savedMessage(fileNames)); + } +} + +bool QDesignerActions::saveForm(QDesignerFormWindowInterface *fw) +{ + bool ret; + if (fw->fileName().isEmpty()) + ret = saveFormAs(fw); + else + ret = writeOutForm(fw, fw->fileName()); + return ret; +} + +void QDesignerActions::closeForm() +{ + if (m_previewManager->previewCount()) { + closePreview(); + return; + } + + if (QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow()) + if (QWidget *parent = fw->parentWidget()) { + if (QMdiSubWindow *mdiSubWindow = qobject_cast(parent->parentWidget())) { + mdiSubWindow->close(); + } else { + parent->close(); + } + } +} + +void QDesignerActions::saveFormAs() +{ + if (QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow()) { + if (saveFormAs(fw)) + showStatusBarMessage(savedMessage(fw->fileName())); + } +} + +void QDesignerActions::saveFormAsTemplate() +{ + if (QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow()) { + SaveFormAsTemplate dlg(core(), fw, fw->window()); + dlg.exec(); + } +} + +void QDesignerActions::notImplementedYet() +{ + QMessageBox::information(core()->topLevel(), tr("Designer"), tr("Feature not implemented yet!")); +} + +void QDesignerActions::closePreview() +{ + m_previewManager->closeAllPreviews(); +} + +void QDesignerActions::viewCode() +{ + QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow(); + if (!fw) + return; + QString errorMessage; + if (!qdesigner_internal::CodeDialog::showCodeDialog(fw, fw, &errorMessage)) + QMessageBox::warning(fw, tr("Code generation failed"), errorMessage); +} + +void QDesignerActions::fixActionContext() +{ + QList actions; + actions += m_fileActions->actions(); + actions += m_editActions->actions(); + actions += m_toolActions->actions(); + actions += m_formActions->actions(); + actions += m_windowActions->actions(); + actions += m_helpActions->actions(); + + foreach (QAction *a, actions) { + a->setShortcutContext(Qt::ApplicationShortcut); + } +} + +bool QDesignerActions::readInForm(const QString &fileName) +{ + QString fn = fileName; + + // First make sure that we don't have this one open already. + QDesignerFormWindowManagerInterface *formWindowManager = core()->formWindowManager(); + const int totalWindows = formWindowManager->formWindowCount(); + for (int i = 0; i < totalWindows; ++i) { + QDesignerFormWindowInterface *w = formWindowManager->formWindow(i); + if (w->fileName() == fn) { + w->raise(); + formWindowManager->setActiveFormWindow(w); + addRecentFile(fn); + return true; + } + } + + // Otherwise load it. + do { + QString errorMessage; + if (workbench()->openForm(fn, &errorMessage)) { + addRecentFile(fn); + m_openDirectory = QFileInfo(fn).absolutePath(); + return true; + } else { + // prompt to reload + QMessageBox box(QMessageBox::Warning, tr("Read error"), + tr("%1\nDo you want to update the file location or generate a new form?").arg(errorMessage), + QMessageBox::Cancel, core()->topLevel()); + + QPushButton *updateButton = box.addButton(tr("&Update"), QMessageBox::ActionRole); + QPushButton *newButton = box.addButton(tr("&New Form"), QMessageBox::ActionRole); + box.exec(); + if (box.clickedButton() == box.button(QMessageBox::Cancel)) + return false; + + if (box.clickedButton() == updateButton) { + const QString extension = uiExtension(); + fn = QFileDialog::getOpenFileName(core()->topLevel(), + tr("Open Form"), m_openDirectory, + tr("Designer UI files (*.%1);;All Files (*)").arg(extension), 0, QFileDialog::DontUseSheet); + + if (fn.isEmpty()) + return false; + } else if (box.clickedButton() == newButton) { + // If the file does not exist, but its directory, is valid, open the template with the editor file name set to it. + // (called from command line). + QString newFormFileName; + const QFileInfo fInfo(fn); + if (!fInfo.exists()) { + // Normalize file name + const QString directory = fInfo.absolutePath(); + if (QDir(directory).exists()) { + newFormFileName = directory; + newFormFileName += QLatin1Char('/'); + newFormFileName += fInfo.fileName(); + } + } + showNewFormDialog(newFormFileName); + return false; + } + } + } while (true); + return true; +} + +static QString createBackup(const QString &fileName) +{ + const QString suffix = QLatin1String(".bak"); + QString backupFile = fileName + suffix; + QFileInfo fi(backupFile); + int i = 0; + while (fi.exists()) { + backupFile = fileName + suffix + QString::number(++i); + fi.setFile(backupFile); + } + + if (QFile::copy(fileName, backupFile)) + return backupFile; + return QString(); +} + +static void removeBackup(const QString &backupFile) +{ + if (!backupFile.isEmpty()) + QFile::remove(backupFile); +} + +bool QDesignerActions::writeOutForm(QDesignerFormWindowInterface *fw, const QString &saveFile) +{ + Q_ASSERT(fw && !saveFile.isEmpty()); + + QString backupFile; + QFileInfo fi(saveFile); + if (fi.exists()) + backupFile = createBackup(saveFile); + + QString contents = fw->contents(); + if (qdesigner_internal::FormWindowBase *fwb = qobject_cast(fw)) { + if (fwb->lineTerminatorMode() == qdesigner_internal::FormWindowBase::CRLFLineTerminator) + contents.replace(QLatin1Char('\n'), QLatin1String("\r\n")); + } + const QByteArray utf8Array = contents.toUtf8(); + m_workbench->updateBackup(fw); + + QFile f(saveFile); + while (!f.open(QFile::WriteOnly)) { + QMessageBox box(QMessageBox::Warning, + tr("Save Form?"), + tr("Could not open file"), + QMessageBox::NoButton, fw); + + box.setWindowModality(Qt::WindowModal); + box.setInformativeText(tr("The file %1 could not be opened." + "\nReason: %2" + "\nWould you like to retry or select a different file?") + .arg(f.fileName()).arg(f.errorString())); + QPushButton *retryButton = box.addButton(QMessageBox::Retry); + retryButton->setDefault(true); + QPushButton *switchButton = box.addButton(tr("Select New File"), QMessageBox::AcceptRole); + QPushButton *cancelButton = box.addButton(QMessageBox::Cancel); + box.exec(); + + if (box.clickedButton() == cancelButton) { + removeBackup(backupFile); + return false; + } else if (box.clickedButton() == switchButton) { + QString extension = uiExtension(); + const QString fileName = QFileDialog::getSaveFileName(fw, tr("Save Form As"), + QDir::current().absolutePath(), + QLatin1String("*.") + extension); + if (fileName.isEmpty()) { + removeBackup(backupFile); + return false; + } + if (f.fileName() != fileName) { + removeBackup(backupFile); + fi.setFile(fileName); + backupFile.clear(); + if (fi.exists()) + backupFile = createBackup(fileName); + } + f.setFileName(fileName); + fw->setFileName(fileName); + } + // loop back around... + } + while (f.write(utf8Array, utf8Array.size()) != utf8Array.size()) { + QMessageBox box(QMessageBox::Warning, tr("Save Form?"), + tr("Could not write file"), + QMessageBox::Retry|QMessageBox::Cancel, fw); + box.setWindowModality(Qt::WindowModal); + box.setInformativeText(tr("It was not possible to write the entire file %1 to disk." + "\nReason:%2\nWould you like to retry?") + .arg(f.fileName()).arg(f.errorString())); + box.setDefaultButton(QMessageBox::Retry); + switch (box.exec()) { + case QMessageBox::Retry: + f.resize(0); + break; + default: + return false; + } + } + f.close(); + removeBackup(backupFile); + addRecentFile(saveFile); + m_saveDirectory = QFileInfo(f).absolutePath(); + + fw->setDirty(false); + fw->parentWidget()->setWindowModified(false); + return true; +} + +void QDesignerActions::shutdown() +{ + // Follow the idea from the Mac, i.e. send the Application a close event + // and if it's accepted, quit. + QCloseEvent ev; + QApplication::sendEvent(qDesigner, &ev); + if (ev.isAccepted()) + qDesigner->quit(); +} + +void QDesignerActions::activeFormWindowChanged(QDesignerFormWindowInterface *formWindow) +{ + const bool enable = formWindow != 0; + m_saveFormAction->setEnabled(enable); + m_saveFormAsAction->setEnabled(enable); + m_saveAllFormsAction->setEnabled(enable); + m_saveFormAsTemplateAction->setEnabled(enable); + m_closeFormAction->setEnabled(enable); + m_savePreviewImageAction->setEnabled(enable); + m_printPreviewAction->setEnabled(enable); + + m_editWidgetsAction->setEnabled(enable); + + m_previewFormAction->setEnabled(enable); + m_viewCodeAction->setEnabled(enable); + m_styleActions->setEnabled(enable); +} + +void QDesignerActions::formWindowSettingsChanged(QDesignerFormWindowInterface *fw) +{ + if (QDesignerFormWindow *window = m_workbench->findFormWindow(fw)) + window->updateChanged(); +} + +void QDesignerActions::updateRecentFileActions() +{ + QStringList files = m_settings.recentFilesList(); + const int originalSize = files.size(); + int numRecentFiles = qMin(files.size(), int(MaxRecentFiles)); + const QList recentFilesActs = m_recentFilesActions->actions(); + + for (int i = 0; i < numRecentFiles; ++i) { + const QFileInfo fi(files[i]); + // If the file doesn't exist anymore, just remove it from the list so + // people don't get confused. + if (!fi.exists()) { + files.removeAt(i); + --i; + numRecentFiles = qMin(files.size(), int(MaxRecentFiles)); + continue; + } + const QString text = fi.fileName(); + recentFilesActs[i]->setText(text); + recentFilesActs[i]->setIconText(files[i]); + recentFilesActs[i]->setVisible(true); + } + + for (int j = numRecentFiles; j < MaxRecentFiles; ++j) + recentFilesActs[j]->setVisible(false); + + // If there's been a change, right it back + if (originalSize != files.size()) + m_settings.setRecentFilesList(files); +} + +void QDesignerActions::openRecentForm() +{ + if (const QAction *action = qobject_cast(sender())) { + if (!readInForm(action->iconText())) + updateRecentFileActions(); // File doesn't exist, remove it from settings + } +} + +void QDesignerActions::clearRecentFiles() +{ + m_settings.setRecentFilesList(QStringList()); + updateRecentFileActions(); +} + +QActionGroup *QDesignerActions::recentFilesActions() const +{ + return m_recentFilesActions; +} + +void QDesignerActions::addRecentFile(const QString &fileName) +{ + QStringList files = m_settings.recentFilesList(); + files.removeAll(fileName); + files.prepend(fileName); + while (files.size() > MaxRecentFiles) + files.removeLast(); + + m_settings.setRecentFilesList(files); + updateRecentFileActions(); +} + +QAction *QDesignerActions::openFormAction() const +{ + return m_openFormAction; +} + +QAction *QDesignerActions::closeFormAction() const +{ + return m_closeFormAction; +} + +QAction *QDesignerActions::minimizeAction() const +{ + return m_minimizeAction; +} + +void QDesignerActions::showDesignerHelp() +{ + QString url = AssistantClient::designerManualUrl(); + url += QLatin1String("designer-manual.html"); + showHelp(url); +} + +void QDesignerActions::showWhatsNew() +{ + QString url = AssistantClient::qtReferenceManualUrl(); + url += QLatin1String("qt4-designer.html"); + showHelp(url); +} + +void QDesignerActions::helpRequested(const QString &manual, const QString &document) +{ + QString url = AssistantClient::documentUrl(manual); + url += document; + showHelp(url); +} + +void QDesignerActions::showHelp(const QString &url) +{ + QString errorMessage; + if (!m_assistantClient.showPage(url, &errorMessage)) + QMessageBox::warning(core()->topLevel(), tr("Assistant"), errorMessage); +} + +void QDesignerActions::aboutDesigner() +{ + VersionDialog mb(core()->topLevel()); + mb.setWindowTitle(tr("About Qt Designer")); + if (mb.exec()) { + QMessageBox messageBox(QMessageBox::Information, QLatin1String("Easter Egg"), + QLatin1String("Easter Egg"), QMessageBox::Ok, core()->topLevel()); + messageBox.setInformativeText(QLatin1String("The Easter Egg has been removed.")); + messageBox.exec(); + } +} + +QAction *QDesignerActions::editWidgets() const +{ + return m_editWidgetsAction; +} + +void QDesignerActions::showWidgetSpecificHelp() +{ + QString helpId; + if (const qdesigner_internal::QDesignerIntegration *integration = qobject_cast(core()->integration())) + helpId = integration->contextHelpId(); + + if (helpId.isEmpty()) { + showDesignerHelp(); + return; + } + + QString errorMessage; + const bool rc = m_assistantClient.activateIdentifier(helpId, &errorMessage); + if (!rc) + QMessageBox::warning(core()->topLevel(), tr("Assistant"), errorMessage); +} + +void QDesignerActions::updateCloseAction() +{ + if (m_previewManager->previewCount()) { + m_closeFormAction->setText(tr("&Close Preview")); + } else { + m_closeFormAction->setText(tr("&Close")); + } +} + +void QDesignerActions::backupForms() +{ + const int count = m_workbench->formWindowCount(); + if (!count || !ensureBackupDirectories()) + return; + + + QStringList tmpFiles; + QMap backupMap; + QDir backupDir(m_backupPath); + const bool warningsEnabled = qdesigner_internal::QSimpleResource::setWarningsEnabled(false); + for (int i = 0; i < count; ++i) { + QDesignerFormWindow *fw = m_workbench->formWindow(i); + QDesignerFormWindowInterface *fwi = fw->editor(); + + QString formBackupName; + QTextStream(&formBackupName) << m_backupPath << QDir::separator() + << QLatin1String("backup") << i << QLatin1String(".bak"); + + QString fwn = QDir::convertSeparators(fwi->fileName()); + if (fwn.isEmpty()) + fwn = fw->windowTitle(); + + backupMap.insert(fwn, formBackupName); + + QFile file(formBackupName.replace(m_backupPath, m_backupTmpPath)); + if (file.open(QFile::WriteOnly)){ + QString contents = fixResourceFileBackupPath(fwi, backupDir); + if (qdesigner_internal::FormWindowBase *fwb = qobject_cast(fwi)) { + if (fwb->lineTerminatorMode() == qdesigner_internal::FormWindowBase::CRLFLineTerminator) + contents.replace(QLatin1Char('\n'), QLatin1String("\r\n")); + } + const QByteArray utf8Array = contents.toUtf8(); + if (file.write(utf8Array, utf8Array.size()) != utf8Array.size()) { + backupMap.remove(fwn); + qdesigner_internal::designerWarning(tr("The backup file %1 could not be written.").arg(file.fileName())); + } else + tmpFiles.append(formBackupName); + + file.close(); + } + } + qdesigner_internal::QSimpleResource::setWarningsEnabled(warningsEnabled); + if(!tmpFiles.isEmpty()) { + const QStringList backupFiles = backupDir.entryList(QDir::Files); + if(!backupFiles.isEmpty()) { + QStringListIterator it(backupFiles); + while (it.hasNext()) + backupDir.remove(it.next()); + } + + QStringListIterator it(tmpFiles); + while (it.hasNext()) { + const QString tmpName = it.next(); + QString name(tmpName); + name.replace(m_backupTmpPath, m_backupPath); + QFile tmpFile(tmpName); + if (!tmpFile.copy(name)) + qdesigner_internal::designerWarning(tr("The backup file %1 could not be written.").arg(name)); + tmpFile.remove(); + } + + m_settings.setBackup(backupMap); + } +} + +QString QDesignerActions::fixResourceFileBackupPath(QDesignerFormWindowInterface *fwi, const QDir& backupDir) +{ + const QString content = fwi->contents(); + QDomDocument domDoc(QLatin1String("backup")); + if(!domDoc.setContent(content)) + return content; + + const QDomNodeList list = domDoc.elementsByTagName(QLatin1String("resources")); + if (list.isEmpty()) + return content; + + for (int i = 0; i < list.count(); i++) { + const QDomNode node = list.at(i); + if (!node.isNull()) { + const QDomElement element = node.toElement(); + if(!element.isNull() && element.tagName() == QLatin1String("resources")) { + QDomNode childNode = element.firstChild(); + while (!childNode.isNull()) { + QDomElement childElement = childNode.toElement(); + if(!childElement.isNull() && childElement.tagName() == QLatin1String("include")) { + const QString attr = childElement.attribute(QLatin1String("location")); + const QString path = fwi->absoluteDir().absoluteFilePath(attr); + childElement.setAttribute(QLatin1String("location"), backupDir.relativeFilePath(path)); + } + childNode = childNode.nextSibling(); + } + } + } + } + + + return domDoc.toString(); +} + +QRect QDesignerActions::fixDialogRect(const QRect &rect) const +{ + QRect frameGeometry; + const QRect availableGeometry = QApplication::desktop()->availableGeometry(core()->topLevel()); + + if (workbench()->mode() == DockedMode) { + frameGeometry = core()->topLevel()->frameGeometry(); + } else + frameGeometry = availableGeometry; + + QRect dlgRect = rect; + dlgRect.moveCenter(frameGeometry.center()); + + // make sure that parts of the dialog are not outside of screen + dlgRect.moveBottom(qMin(dlgRect.bottom(), availableGeometry.bottom())); + dlgRect.moveRight(qMin(dlgRect.right(), availableGeometry.right())); + dlgRect.moveLeft(qMax(dlgRect.left(), availableGeometry.left())); + dlgRect.moveTop(qMax(dlgRect.top(), availableGeometry.top())); + + return dlgRect; +} + +void QDesignerActions::showStatusBarMessage(const QString &message) const +{ + if (workbench()->mode() == DockedMode) { + QStatusBar *bar = qDesigner->mainWindow()->statusBar(); + if (bar && !bar->isHidden()) + bar->showMessage(message, 3000); + } +} + +void QDesignerActions::setBringAllToFrontVisible(bool visible) +{ + m_bringAllToFrontSeparator->setVisible(visible); + m_bringAllToFrontAction->setVisible(visible); +} + +void QDesignerActions::setWindowListSeparatorVisible(bool visible) +{ + m_windowListSeparatorAction->setVisible(visible); +} + +bool QDesignerActions::ensureBackupDirectories() { + + if (m_backupPath.isEmpty()) { + // create names + m_backupPath = QDir::homePath(); + m_backupPath += QDir::separator(); + m_backupPath += QLatin1String(".designer"); + m_backupPath += QDir::separator(); + m_backupPath += QLatin1String("backup"); + m_backupPath = QDir::convertSeparators(m_backupPath ); + + m_backupTmpPath = m_backupPath; + m_backupTmpPath += QDir::separator(); + m_backupTmpPath += QLatin1String("tmp"); + m_backupTmpPath = QDir::convertSeparators(m_backupTmpPath); + } + + // ensure directories + const QDir backupDir(m_backupPath); + const QDir backupTmpDir(m_backupTmpPath); + + if (!backupDir.exists()) { + if (!backupDir.mkpath(m_backupPath)) { + qdesigner_internal::designerWarning(tr("The backup directory %1 could not be created.").arg(m_backupPath)); + return false; + } + } + if (!backupTmpDir.exists()) { + if (!backupTmpDir.mkpath(m_backupTmpPath)) { + qdesigner_internal::designerWarning(tr("The temporary backup directory %1 could not be created.").arg(m_backupTmpPath)); + return false; + } + } + return true; +} + +void QDesignerActions::showPreferencesDialog() +{ + PreferencesDialog preferencesDialog(workbench()->core(), m_core->topLevel()); + preferencesDialog.exec(); +} + +void QDesignerActions::showAppFontDialog() +{ + if (!m_appFontDialog) // Might get deleted when switching ui modes + m_appFontDialog = new AppFontDialog(core()->topLevel()); + m_appFontDialog->show(); + m_appFontDialog->raise(); +} + +QPixmap QDesignerActions::createPreviewPixmap(QDesignerFormWindowInterface *fw) +{ + const QCursor oldCursor = core()->topLevel()->cursor(); + core()->topLevel()->setCursor(Qt::WaitCursor); + + QString errorMessage; + const QPixmap pixmap = m_previewManager->createPreviewPixmap(fw, QString(), &errorMessage); + core()->topLevel()->setCursor(oldCursor); + if (pixmap.isNull()) { + QMessageBox::warning(fw, tr("Preview failed"), errorMessage); + } + return pixmap; +} + +qdesigner_internal::PreviewConfiguration QDesignerActions::previewConfiguration() +{ + qdesigner_internal::PreviewConfiguration pc; + QDesignerSharedSettings settings(core()); + if (settings.isCustomPreviewConfigurationEnabled()) + pc = settings.customPreviewConfiguration(); + return pc; +} + +void QDesignerActions::savePreviewImage() +{ + const char *format = "png"; + + QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow(); + if (!fw) + return; + + QImage image; + const QString extension = QString::fromAscii(format); + const QString filter = tr("Image files (*.%1)").arg(extension); + + QString suggestion = fw->fileName(); + if (!suggestion.isEmpty()) { + suggestion = QFileInfo(suggestion).baseName(); + suggestion += QLatin1Char('.'); + suggestion += extension; + } + do { + const QString fileName = getSaveFileNameWithExtension(fw, tr("Save Image"), suggestion, filter, extension); + if (fileName.isEmpty()) + break; + + if (image.isNull()) { + const QPixmap pixmap = createPreviewPixmap(fw); + if (pixmap.isNull()) + break; + + image = pixmap.toImage(); + } + + if (image.save(fileName, format)) { + showStatusBarMessage(tr("Saved image %1.").arg(QFileInfo(fileName).fileName())); + break; + } + + QMessageBox box(QMessageBox::Warning, tr("Save Image"), + tr("The file %1 could not be written.").arg( fileName), + QMessageBox::Retry|QMessageBox::Cancel, fw); + if (box.exec() == QMessageBox::Cancel) + break; + } while (true); +} + +void QDesignerActions::formWindowCountChanged() +{ + const bool enabled = m_core->formWindowManager()->formWindowCount() == 0; + /* Disable the application font action if there are form windows open + * as the reordering of the fonts sets font properties to 'changed' + * and overloaded fonts are not updated. */ + static const QString disabledTip = tr("Please close all forms to enable the loading of additional fonts."); + m_appFontAction->setEnabled(enabled); + m_appFontAction->setStatusTip(enabled ? QString() : disabledTip); +} + +void QDesignerActions::printPreviewImage() +{ +#ifndef QT_NO_PRINTER + QDesignerFormWindowInterface *fw = core()->formWindowManager()->activeFormWindow(); + if (!fw) + return; + + if (!m_printer) + m_printer = new QPrinter(QPrinter::HighResolution); + + m_printer->setFullPage(false); + + // Grab the image to be able to a suggest suitable orientation + const QPixmap pixmap = createPreviewPixmap(fw); + if (pixmap.isNull()) + return; + + const QSizeF pixmapSize = pixmap.size(); + m_printer->setOrientation( pixmapSize.width() > pixmapSize.height() ? QPrinter::Landscape : QPrinter::Portrait); + + // Printer parameters + QPrintDialog dialog(m_printer, fw); + if (!dialog.exec()) + return; + + const QCursor oldCursor = core()->topLevel()->cursor(); + core()->topLevel()->setCursor(Qt::WaitCursor); + // Estimate of required scaling to make form look the same on screen and printer. + const double suggestedScaling = static_cast(m_printer->physicalDpiX()) / static_cast(fw->physicalDpiX()); + + QPainter painter(m_printer); + painter.setRenderHint(QPainter::SmoothPixmapTransform); + + // Clamp to page + const QRectF page = painter.viewport(); + const double maxScaling = qMin(page.size().width() / pixmapSize.width(), page.size().height() / pixmapSize.height()); + const double scaling = qMin(suggestedScaling, maxScaling); + + const double xOffset = page.left() + qMax(0.0, (page.size().width() - scaling * pixmapSize.width()) / 2.0); + const double yOffset = page.top() + qMax(0.0, (page.size().height() - scaling * pixmapSize.height()) / 2.0); + + // Draw. + painter.translate(xOffset, yOffset); + painter.scale(scaling, scaling); + painter.drawPixmap(0, 0, pixmap); + core()->topLevel()->setCursor(oldCursor); + + showStatusBarMessage(tr("Printed %1.").arg(QFileInfo(fw->fileName()).fileName())); +#endif +} + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/qdesigner_actions.h b/src/designer/src/designer/qdesigner_actions.h new file mode 100644 index 000000000..910901bcb --- /dev/null +++ b/src/designer/src/designer/qdesigner_actions.h @@ -0,0 +1,231 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_ACTIONS_H +#define QDESIGNER_ACTIONS_H + +#include "assistantclient.h" +#include "qdesigner_settings.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerWorkbench; + +class QDir; +class QTimer; +class QAction; +class QActionGroup; +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; +class AppFontDialog; + +class QRect; +class QWidget; +class QPixmap; +class QMenu; + +namespace qdesigner_internal { + class PreviewConfiguration; + class PreviewManager; +} + +class QDesignerActions: public QObject +{ + Q_OBJECT +public: + explicit QDesignerActions(QDesignerWorkbench *mainWindow); + virtual ~QDesignerActions(); + + QDesignerWorkbench *workbench() const; + QDesignerFormEditorInterface *core() const; + + bool saveForm(QDesignerFormWindowInterface *fw); + bool readInForm(const QString &fileName); + bool writeOutForm(QDesignerFormWindowInterface *formWindow, const QString &fileName); + + QActionGroup *fileActions() const; + QActionGroup *recentFilesActions() const; + QActionGroup *editActions() const; + QActionGroup *formActions() const; + QActionGroup *settingsActions() const; + QActionGroup *windowActions() const; + QActionGroup *toolActions() const; + QActionGroup *helpActions() const; + QActionGroup *uiMode() const; + QActionGroup *styleActions() const; + // file actions + QAction *openFormAction() const; + QAction *closeFormAction() const; + // window actions + QAction *minimizeAction() const; + // edit mode actions + QAction *editWidgets() const; + // form actions + QAction *previewFormAction() const; + QAction *viewCodeAction() const; + + void setBringAllToFrontVisible(bool visible); + void setWindowListSeparatorVisible(bool visible); + + bool openForm(QWidget *parent); + + QString uiExtension() const; + + // Boolean dynamic property set on actions to + // show them in the default toolbar layout + static const char *defaultToolbarPropertyName; + +public slots: + void activeFormWindowChanged(QDesignerFormWindowInterface *formWindow); + void createForm(); + void slotOpenForm(); + void helpRequested(const QString &manual, const QString &document); + +signals: + void useBigIcons(bool); + +private slots: + void saveForm(); + void saveFormAs(); + void saveAllForms(); + void saveFormAsTemplate(); + void viewCode(); + void notImplementedYet(); + void shutdown(); + void editWidgetsSlot(); + void openRecentForm(); + void clearRecentFiles(); + void closeForm(); + void showDesignerHelp(); + void showWhatsNew(); + void aboutDesigner(); + void showWidgetSpecificHelp(); + void backupForms(); + void showNewFormDialog(const QString &fileName); + void showPreferencesDialog(); + void showAppFontDialog(); + void savePreviewImage(); + void printPreviewImage(); + void updateCloseAction(); + void formWindowCountChanged(); + void formWindowSettingsChanged(QDesignerFormWindowInterface *fw); + +private: + QAction *createRecentFilesMenu(); + bool saveFormAs(QDesignerFormWindowInterface *fw); + void fixActionContext(); + void updateRecentFileActions(); + void addRecentFile(const QString &fileName); + void showHelp(const QString &help); + void closePreview(); + QRect fixDialogRect(const QRect &rect) const; + QString fixResourceFileBackupPath(QDesignerFormWindowInterface *fwi, const QDir& backupDir); + void showStatusBarMessage(const QString &message) const; + QActionGroup *createHelpActions(); + bool ensureBackupDirectories(); + QPixmap createPreviewPixmap(QDesignerFormWindowInterface *fw); + qdesigner_internal::PreviewConfiguration previewConfiguration(); + + enum { MaxRecentFiles = 10 }; + QDesignerWorkbench *m_workbench; + QDesignerFormEditorInterface *m_core; + QDesignerSettings m_settings; + AssistantClient m_assistantClient; + QString m_openDirectory; + QString m_saveDirectory; + + + QString m_backupPath; + QString m_backupTmpPath; + + QTimer* m_backupTimer; + + QActionGroup *m_fileActions; + QActionGroup *m_recentFilesActions; + QActionGroup *m_editActions; + QActionGroup *m_formActions; + QActionGroup *m_settingsActions; + QActionGroup *m_windowActions; + QActionGroup *m_toolActions; + QActionGroup *m_helpActions; + QActionGroup *m_styleActions; + + QAction *m_editWidgetsAction; + + QAction *m_newFormAction; + QAction *m_openFormAction; + QAction *m_saveFormAction; + QAction *m_saveFormAsAction; + QAction *m_saveAllFormsAction; + QAction *m_saveFormAsTemplateAction; + QAction *m_closeFormAction; + QAction *m_savePreviewImageAction; + QAction *m_printPreviewAction; + + QAction *m_quitAction; + + QAction *m_previewFormAction; + QAction *m_viewCodeAction; + + QAction *m_minimizeAction; + QAction *m_bringAllToFrontSeparator; + QAction *m_bringAllToFrontAction; + QAction *m_windowListSeparatorAction; + + QAction *m_preferencesAction; + QAction *m_appFontAction; + + QPointer m_appFontDialog; + +#ifndef QT_NO_PRINTER + QPrinter *m_printer; +#endif + + qdesigner_internal::PreviewManager *m_previewManager; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_ACTIONS_H diff --git a/src/designer/src/designer/qdesigner_appearanceoptions.cpp b/src/designer/src/designer/qdesigner_appearanceoptions.cpp new file mode 100644 index 000000000..f5b3f3d6d --- /dev/null +++ b/src/designer/src/designer/qdesigner_appearanceoptions.cpp @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_appearanceoptions.h" +#include "ui_qdesigner_appearanceoptions.h" + +#include "qdesigner_settings.h" +#include "qdesigner_toolwindow.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +// ---------------- AppearanceOptions +AppearanceOptions::AppearanceOptions() : + uiMode(DockedMode) +{ +} + +bool AppearanceOptions::equals(const AppearanceOptions &rhs) const +{ + return uiMode == rhs.uiMode && toolWindowFontSettings == rhs.toolWindowFontSettings; +} + +void AppearanceOptions::toSettings(QDesignerSettings &settings) const +{ + settings.setUiMode(uiMode); + settings.setToolWindowFont(toolWindowFontSettings); +} + +void AppearanceOptions::fromSettings(const QDesignerSettings &settings) +{ + uiMode = settings.uiMode(); + toolWindowFontSettings = settings.toolWindowFont(); +} + +// ---------------- QDesignerAppearanceOptionsWidget +QDesignerAppearanceOptionsWidget::QDesignerAppearanceOptionsWidget(QWidget *parent) : + QWidget(parent), + m_ui(new Ui::AppearanceOptionsWidget), + m_initialUIMode(NeutralMode) +{ + m_ui->setupUi(this); + + m_ui->m_uiModeCombo->addItem(tr("Docked Window"), QVariant(DockedMode)); + m_ui->m_uiModeCombo->addItem(tr("Multiple Top-Level Windows"), QVariant(TopLevelMode)); + connect(m_ui->m_uiModeCombo, SIGNAL(currentIndexChanged(int)), + this, SLOT(slotUiModeComboChanged())); + + m_ui->m_fontPanel->setCheckable(true); + m_ui->m_fontPanel->setTitle(tr("Toolwindow Font")); + +} + +QDesignerAppearanceOptionsWidget::~QDesignerAppearanceOptionsWidget() +{ + delete m_ui; +} + +UIMode QDesignerAppearanceOptionsWidget::uiMode() const +{ + return static_cast(m_ui->m_uiModeCombo->itemData(m_ui->m_uiModeCombo->currentIndex()).toInt()); +} + +AppearanceOptions QDesignerAppearanceOptionsWidget::appearanceOptions() const +{ + AppearanceOptions rc; + rc.uiMode = uiMode(); + rc.toolWindowFontSettings.m_font = m_ui->m_fontPanel->selectedFont(); + rc.toolWindowFontSettings.m_useFont = m_ui->m_fontPanel->isChecked(); + rc.toolWindowFontSettings.m_writingSystem = m_ui->m_fontPanel->writingSystem(); + return rc; +} + +void QDesignerAppearanceOptionsWidget::setAppearanceOptions(const AppearanceOptions &ao) +{ + m_initialUIMode = ao.uiMode; + m_ui->m_uiModeCombo->setCurrentIndex(m_ui->m_uiModeCombo->findData(QVariant(ao.uiMode))); + m_ui->m_fontPanel->setWritingSystem(ao.toolWindowFontSettings.m_writingSystem); + m_ui->m_fontPanel->setSelectedFont(ao.toolWindowFontSettings.m_font); + m_ui->m_fontPanel->setChecked(ao.toolWindowFontSettings.m_useFont); +} + +void QDesignerAppearanceOptionsWidget::slotUiModeComboChanged() +{ + emit uiModeChanged(m_initialUIMode != uiMode()); +} + +// ----------- QDesignerAppearanceOptionsPage +QDesignerAppearanceOptionsPage::QDesignerAppearanceOptionsPage(QDesignerFormEditorInterface *core) : + m_core(core) +{ +} + +QString QDesignerAppearanceOptionsPage::name() const +{ + //: Tab in preferences dialog + return QCoreApplication::translate("QDesignerAppearanceOptionsPage", "Appearance"); +} + +QWidget *QDesignerAppearanceOptionsPage::createPage(QWidget *parent) +{ + m_widget = new QDesignerAppearanceOptionsWidget(parent); + m_initialOptions.fromSettings(QDesignerSettings(m_core)); + m_widget->setAppearanceOptions(m_initialOptions); + return m_widget; +} + +void QDesignerAppearanceOptionsPage::apply() +{ + if (m_widget) { + const AppearanceOptions newOptions = m_widget->appearanceOptions(); + if (newOptions != m_initialOptions) { + QDesignerSettings settings(m_core); + newOptions.toSettings(settings); + QTimer::singleShot(0, this, SIGNAL(settingsChangedDelayed())); + m_initialOptions = newOptions; + } + } +} + +void QDesignerAppearanceOptionsPage::finish() +{ +} + +QT_END_NAMESPACE + diff --git a/src/designer/src/designer/qdesigner_appearanceoptions.h b/src/designer/src/designer/qdesigner_appearanceoptions.h new file mode 100644 index 000000000..a6e4f9a49 --- /dev/null +++ b/src/designer/src/designer/qdesigner_appearanceoptions.h @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_APPEARANCEOPTIONS_H +#define QDESIGNER_APPEARANCEOPTIONS_H + +#include "designer_enums.h" +#include "qdesigner_toolwindow.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerSettings; + +namespace Ui { + class AppearanceOptionsWidget; +} + +/* AppearanceOptions data */ +struct AppearanceOptions { + AppearanceOptions(); + bool equals(const AppearanceOptions&) const; + void toSettings(QDesignerSettings &) const; + void fromSettings(const QDesignerSettings &); + + UIMode uiMode; + ToolWindowFontSettings toolWindowFontSettings; +}; + +inline bool operator==(const AppearanceOptions &ao1, const AppearanceOptions &ao2) +{ + return ao1.equals(ao2); +} + +inline bool operator!=(const AppearanceOptions &ao1, const AppearanceOptions &ao2) +{ + return !ao1.equals(ao2); +} + +/* QDesignerAppearanceOptionsWidget: Let the user edit AppearanceOptions */ +class QDesignerAppearanceOptionsWidget : public QWidget +{ + Q_OBJECT +public: + explicit QDesignerAppearanceOptionsWidget(QWidget *parent = 0); + ~QDesignerAppearanceOptionsWidget(); + + AppearanceOptions appearanceOptions() const; + void setAppearanceOptions(const AppearanceOptions &ao); + +signals: + void uiModeChanged(bool modified); + +private slots: + void slotUiModeComboChanged(); + +private: + UIMode uiMode() const; + + Ui::AppearanceOptionsWidget *m_ui; + UIMode m_initialUIMode; +}; + +/* The options page for appearance options. Emits a Timer-0 delayed changed + * signal to allow the preferences dialog to close (and be deleted) before a + * possible switch from docked mode to top-level mode happens. (The switch + * would delete the main window, which the preference dialog is a child of + * -> BOOM) */ + +class QDesignerAppearanceOptionsPage : public QObject, public QDesignerOptionsPageInterface +{ + Q_OBJECT + +public: + QDesignerAppearanceOptionsPage(QDesignerFormEditorInterface *core); + + QString name() const; + QWidget *createPage(QWidget *parent); + virtual void apply(); + virtual void finish(); + +signals: + void settingsChangedDelayed(); + +private: + QDesignerFormEditorInterface *m_core; + QPointer m_widget; + AppearanceOptions m_initialOptions; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_APPEARANCEOPTIONS_H diff --git a/src/designer/src/designer/qdesigner_appearanceoptions.ui b/src/designer/src/designer/qdesigner_appearanceoptions.ui new file mode 100644 index 000000000..a5582f2ab --- /dev/null +++ b/src/designer/src/designer/qdesigner_appearanceoptions.ui @@ -0,0 +1,57 @@ + + + AppearanceOptionsWidget + + + + 0 + 0 + 325 + 360 + + + + Form + + + + + + User Interface Mode + + + + + + + + + + + + + + + Qt::Vertical + + + + 0 + 0 + + + + + + + + + FontPanel + QGroupBox +
fontpanel.h
+ 1 +
+
+ + +
diff --git a/src/designer/src/designer/qdesigner_formwindow.cpp b/src/designer/src/designer/qdesigner_formwindow.cpp new file mode 100644 index 000000000..4770d2a58 --- /dev/null +++ b/src/designer/src/designer/qdesigner_formwindow.cpp @@ -0,0 +1,290 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_formwindow.h" +#include "qdesigner_workbench.h" +#include "formwindowbase_p.h" + +// sdk +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +QDesignerFormWindow::QDesignerFormWindow(QDesignerFormWindowInterface *editor, QDesignerWorkbench *workbench, QWidget *parent, Qt::WindowFlags flags) + : QWidget(parent, flags), + m_editor(editor), + m_workbench(workbench), + m_action(new QAction(this)), + m_initialized(false), + m_windowTitleInitialized(false) +{ + Q_ASSERT(workbench); + + setMaximumSize(0xFFF, 0xFFF); + QDesignerFormEditorInterface *core = workbench->core(); + + if (m_editor) { + m_editor->setParent(this); + } else { + m_editor = core->formWindowManager()->createFormWindow(this); + } + + QVBoxLayout *l = new QVBoxLayout(this); + l->setMargin(0); + l->addWidget(m_editor); + + m_action->setCheckable(true); + + connect(m_editor->commandHistory(), SIGNAL(indexChanged(int)), this, SLOT(updateChanged())); + connect(m_editor, SIGNAL(geometryChanged()), this, SLOT(geometryChanged())); + qdesigner_internal::FormWindowBase::setupDefaultAction(m_editor); +} + +QDesignerFormWindow::~QDesignerFormWindow() +{ + if (workbench()) + workbench()->removeFormWindow(this); +} + +QAction *QDesignerFormWindow::action() const +{ + return m_action; +} + +void QDesignerFormWindow::changeEvent(QEvent *e) +{ + switch (e->type()) { + case QEvent::WindowTitleChange: + m_action->setText(windowTitle().remove(QLatin1String("[*]"))); + break; + case QEvent::WindowIconChange: + m_action->setIcon(windowIcon()); + break; + case QEvent::WindowStateChange: { + const QWindowStateChangeEvent *wsce = static_cast(e); + const bool wasMinimized = Qt::WindowMinimized & wsce->oldState(); + const bool isMinimizedNow = isMinimized(); + if (wasMinimized != isMinimizedNow ) + emit minimizationStateChanged(m_editor, isMinimizedNow); + } + break; + default: + break; + } + QWidget::changeEvent(e); +} + +QRect QDesignerFormWindow::geometryHint() const +{ + const QPoint point(0, 0); + // If we have a container, we want to be just as big. + // QMdiSubWindow attempts to resize its children to sizeHint() when switching user interface modes. + if (QWidget *mainContainer = m_editor->mainContainer()) + return QRect(point, mainContainer->size()); + + return QRect(point, sizeHint()); +} + +QDesignerFormWindowInterface *QDesignerFormWindow::editor() const +{ + return m_editor; +} + +QDesignerWorkbench *QDesignerFormWindow::workbench() const +{ + return m_workbench; +} + +void QDesignerFormWindow::firstShow() +{ + // Set up handling of file name changes and set initial title. + if (!m_windowTitleInitialized) { + m_windowTitleInitialized = true; + if (m_editor) { + connect(m_editor, SIGNAL(fileNameChanged(QString)), this, SLOT(updateWindowTitle(QString))); + updateWindowTitle(m_editor->fileName()); + updateChanged(); + } + } + show(); +} + +int QDesignerFormWindow::getNumberOfUntitledWindows() const +{ + const int totalWindows = m_workbench->formWindowCount(); + if (!totalWindows) + return 0; + + int maxUntitled = 0; + // Find the number of untitled windows excluding ourselves. + // Do not fall for 'untitled.ui', match with modified place holder. + // This will cause some problems with i18n, but for now I need the string to be "static" + QRegExp rx(QLatin1String("untitled( (\\d+))?\\[\\*\\]")); + for (int i = 0; i < totalWindows; ++i) { + QDesignerFormWindow *fw = m_workbench->formWindow(i); + if (fw != this) { + const QString title = m_workbench->formWindow(i)->windowTitle(); + if (rx.indexIn(title) != -1) { + if (maxUntitled == 0) + ++maxUntitled; + if (rx.captureCount() > 1) { + const QString numberCapture = rx.cap(2); + if (!numberCapture.isEmpty()) + maxUntitled = qMax(numberCapture.toInt(), maxUntitled); + } + } + } + } + return maxUntitled; +} + +void QDesignerFormWindow::updateWindowTitle(const QString &fileName) +{ + if (!m_windowTitleInitialized) { + m_windowTitleInitialized = true; + if (m_editor) + connect(m_editor, SIGNAL(fileNameChanged(QString)), this, SLOT(updateWindowTitle(QString))); + } + + QString fileNameTitle; + if (fileName.isEmpty()) { + fileNameTitle = QLatin1String("untitled"); + if (const int maxUntitled = getNumberOfUntitledWindows()) { + fileNameTitle += QLatin1Char(' '); + fileNameTitle += QString::number(maxUntitled + 1); + } + } else { + fileNameTitle = QFileInfo(fileName).fileName(); + } + + if (const QWidget *mc = m_editor->mainContainer()) { + setWindowIcon(mc->windowIcon()); + setWindowTitle(tr("%1 - %2[*]").arg(mc->windowTitle()).arg(fileNameTitle)); + } else { + setWindowTitle(fileNameTitle); + } +} + +void QDesignerFormWindow::closeEvent(QCloseEvent *ev) +{ + if (m_editor->isDirty()) { + raise(); + QMessageBox box(QMessageBox::Information, tr("Save Form?"), + tr("Do you want to save the changes to this document before closing?"), + QMessageBox::Discard | QMessageBox::Cancel | QMessageBox::Save, m_editor); + box.setInformativeText(tr("If you don't save, your changes will be lost.")); + box.setWindowModality(Qt::WindowModal); + static_cast(box.button(QMessageBox::Save))->setDefault(true); + + switch (box.exec()) { + case QMessageBox::Save: { + bool ok = workbench()->saveForm(m_editor); + ev->setAccepted(ok); + m_editor->setDirty(!ok); + break; + } + case QMessageBox::Discard: + m_editor->setDirty(false); // Not really necessary, but stops problems if we get close again. + ev->accept(); + break; + case QMessageBox::Cancel: + ev->ignore(); + break; + } + } +} + +void QDesignerFormWindow::updateChanged() +{ + // Sometimes called after form window destruction. + if (m_editor) { + setWindowModified(m_editor->isDirty()); + updateWindowTitle(m_editor->fileName()); + } +} + +void QDesignerFormWindow::resizeEvent(QResizeEvent *rev) +{ + if(m_initialized) { + m_editor->setDirty(true); + setWindowModified(true); + } + + m_initialized = true; + QWidget::resizeEvent(rev); +} + +void QDesignerFormWindow::geometryChanged() +{ + // If the form window changes, re-update the geometry of the current widget in the property editor. + // Note that in the case of layouts, non-maincontainer widgets must also be updated, + // so, do not do it for the main container only + const QDesignerFormEditorInterface *core = m_editor->core(); + QObject *object = core->propertyEditor()->object(); + if (object == 0 || !object->isWidgetType()) + return; + static const QString geometryProperty = QLatin1String("geometry"); + const QDesignerPropertySheetExtension *sheet = qt_extension(core->extensionManager(), object); + const int geometryIndex = sheet->indexOf(geometryProperty); + if (geometryIndex == -1) + return; + core->propertyEditor()->setPropertyValue(geometryProperty, sheet->property(geometryIndex)); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/qdesigner_formwindow.h b/src/designer/src/designer/qdesigner_formwindow.h new file mode 100644 index 000000000..5ee4c40b4 --- /dev/null +++ b/src/designer/src/designer/qdesigner_formwindow.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_FORMWINDOW_H +#define QDESIGNER_FORMWINDOW_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerWorkbench; +class QDesignerFormWindowInterface; + +class QDesignerFormWindow: public QWidget +{ + Q_OBJECT +public: + QDesignerFormWindow(QDesignerFormWindowInterface *formWindow, QDesignerWorkbench *workbench, + QWidget *parent = 0, Qt::WindowFlags flags = 0); + + void firstShow(); + + virtual ~QDesignerFormWindow(); + + QAction *action() const; + QDesignerWorkbench *workbench() const; + QDesignerFormWindowInterface *editor() const; + + QRect geometryHint() const; + +public slots: + void updateChanged(); + +private slots: + void updateWindowTitle(const QString &fileName); + void geometryChanged(); + +signals: + void minimizationStateChanged(QDesignerFormWindowInterface *formWindow, bool minimized); + void triggerAction(); + +protected: + virtual void changeEvent(QEvent *e); + virtual void closeEvent(QCloseEvent *ev); + virtual void resizeEvent(QResizeEvent* rev); + +private: + int getNumberOfUntitledWindows() const; + QPointer m_editor; + QPointer m_workbench; + QAction *m_action; + bool m_initialized; + bool m_windowTitleInitialized; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_FORMWINDOW_H diff --git a/src/designer/src/designer/qdesigner_pch.h b/src/designer/src/designer/qdesigner_pch.h new file mode 100644 index 000000000..12eb3f376 --- /dev/null +++ b/src/designer/src/designer/qdesigner_pch.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#if defined __cplusplus +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qdesigner.h" +#include "qdesigner_formwindow.h" +#include "qdesigner_settings.h" +#include "qdesigner_toolwindow.h" +#include "qdesigner_workbench.h" +#endif diff --git a/src/designer/src/designer/qdesigner_server.cpp b/src/designer/src/designer/qdesigner_server.cpp new file mode 100644 index 000000000..bffee5b7e --- /dev/null +++ b/src/designer/src/designer/qdesigner_server.cpp @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include +#include +#include + +#include "qdesigner.h" +#include "qdesigner_server.h" + +#include + +QT_BEGIN_NAMESPACE + +// ### review + +QDesignerServer::QDesignerServer(QObject *parent) + : QObject(parent) +{ + m_socket = 0; + m_server = new QTcpServer(this); + m_server->listen(QHostAddress::LocalHost, 0); + if (m_server->isListening()) + { + connect(m_server, SIGNAL(newConnection()), + this, SLOT(handleNewConnection())); + } +} + +QDesignerServer::~QDesignerServer() +{ +} + +quint16 QDesignerServer::serverPort() const +{ + return m_server ? m_server->serverPort() : 0; +} + +void QDesignerServer::sendOpenRequest(int port, const QStringList &files) +{ + QTcpSocket *sSocket = new QTcpSocket(); + sSocket->connectToHost(QHostAddress::LocalHost, port); + if(sSocket->waitForConnected(3000)) + { + foreach(const QString &file, files) + { + QFileInfo fi(file); + sSocket->write(fi.absoluteFilePath().toUtf8() + '\n'); + } + sSocket->waitForBytesWritten(3000); + sSocket->close(); + } + delete sSocket; +} + +void QDesignerServer::readFromClient() +{ + while (m_socket->canReadLine()) { + QString file = QString::fromUtf8(m_socket->readLine()); + if (!file.isNull()) { + file.remove(QLatin1Char('\n')); + file.remove(QLatin1Char('\r')); + qDesigner->postEvent(qDesigner, new QFileOpenEvent(file)); + } + } +} + +void QDesignerServer::socketClosed() +{ + m_socket = 0; +} + +void QDesignerServer::handleNewConnection() +{ + // no need for more than one connection + if (m_socket == 0) { + m_socket = m_server->nextPendingConnection(); + connect(m_socket, SIGNAL(readyRead()), + this, SLOT(readFromClient())); + connect(m_socket, SIGNAL(disconnected()), + this, SLOT(socketClosed())); + } +} + + +QDesignerClient::QDesignerClient(quint16 port, QObject *parent) +: QObject(parent) +{ + m_socket = new QTcpSocket(this); + m_socket->connectToHost(QHostAddress::LocalHost, port); + connect(m_socket, SIGNAL(readyRead()), + this, SLOT(readFromSocket())); + +} + +QDesignerClient::~QDesignerClient() +{ + m_socket->close(); + m_socket->flush(); +} + +void QDesignerClient::readFromSocket() +{ + while (m_socket->canReadLine()) { + QString file = QString::fromUtf8(m_socket->readLine()); + if (!file.isNull()) { + file.remove(QLatin1Char('\n')); + file.remove(QLatin1Char('\r')); + if (QFile::exists(file)) + qDesigner->postEvent(qDesigner, new QFileOpenEvent(file)); + } + } +} + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/qdesigner_server.h b/src/designer/src/designer/qdesigner_server.h new file mode 100644 index 000000000..3aeeebdee --- /dev/null +++ b/src/designer/src/designer/qdesigner_server.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_SERVER_H +#define QDESIGNER_SERVER_H + +#include + +QT_BEGIN_NAMESPACE + +class QTcpServer; +class QTcpSocket; + +class QDesignerServer: public QObject +{ + Q_OBJECT +public: + explicit QDesignerServer(QObject *parent = 0); + virtual ~QDesignerServer(); + + quint16 serverPort() const; + + static void sendOpenRequest(int port, const QStringList &files); + +private slots: + void handleNewConnection(); + void readFromClient(); + void socketClosed(); + +private: + QTcpServer *m_server; + QTcpSocket *m_socket; +}; + +class QDesignerClient: public QObject +{ + Q_OBJECT +public: + explicit QDesignerClient(quint16 port, QObject *parent = 0); + virtual ~QDesignerClient(); + +private slots: + void readFromSocket(); + +private: + QTcpSocket *m_socket; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_SERVER_H diff --git a/src/designer/src/designer/qdesigner_settings.cpp b/src/designer/src/designer/qdesigner_settings.cpp new file mode 100644 index 000000000..89bec14f2 --- /dev/null +++ b/src/designer/src/designer/qdesigner_settings.cpp @@ -0,0 +1,250 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner.h" +#include "qdesigner_settings.h" +#include "qdesigner_toolwindow.h" +#include "qdesigner_workbench.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +enum { debugSettings = 0 }; + +QT_BEGIN_NAMESPACE + +static const char *newFormShowKey = "newFormDialog/ShowOnStartup"; + +// Change the version whenever the arrangement changes significantly. +static const char *mainWindowStateKey = "MainWindowState45"; +static const char *toolBarsStateKey = "ToolBarsState45"; + +static const char *backupOrgListKey = "backup/fileListOrg"; +static const char *backupBakListKey = "backup/fileListBak"; +static const char *recentFilesListKey = "recentFilesList"; + +QDesignerSettings::QDesignerSettings(QDesignerFormEditorInterface *core) : + qdesigner_internal::QDesignerSharedSettings(core) +{ +} + +void QDesignerSettings::setValue(const QString &key, const QVariant &value) +{ + settings()->setValue(key, value); +} + +QVariant QDesignerSettings::value(const QString &key, const QVariant &defaultValue) const +{ + return settings()->value(key, defaultValue); +} + +static inline QChar modeChar(UIMode mode) +{ + return QLatin1Char(static_cast(mode) + '0'); +} + +void QDesignerSettings::saveGeometryFor(const QWidget *w) +{ + Q_ASSERT(w && !w->objectName().isEmpty()); + QDesignerSettingsInterface *s = settings(); + const bool visible = w->isVisible(); + if (debugSettings) + qDebug() << Q_FUNC_INFO << w << "visible=" << visible; + s->beginGroup(w->objectName()); + s->setValue(QLatin1String("visible"), visible); + s->setValue(QLatin1String("geometry"), w->saveGeometry()); + s->endGroup(); +} + +void QDesignerSettings::restoreGeometry(QWidget *w, QRect fallBack) const +{ + Q_ASSERT(w && !w->objectName().isEmpty()); + const QString key = w->objectName(); + const QByteArray ba(settings()->value(key + QLatin1String("/geometry")).toByteArray()); + const bool visible = settings()->value(key + QLatin1String("/visible"), true).toBool(); + + if (debugSettings) + qDebug() << Q_FUNC_INFO << w << fallBack << "visible=" << visible; + if (ba.isEmpty()) { + /// Apply default geometry, check for null and maximal size + if (fallBack.isNull()) + fallBack = QRect(QPoint(0, 0), w->sizeHint()); + if (fallBack.size() == QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)) { + w->setWindowState(w->windowState() | Qt::WindowMaximized); + } else { + w->move(fallBack.topLeft()); + w->resize(fallBack.size()); + } + } else { + w->restoreGeometry(ba); + } + + if (visible) + w->show(); +} + +QStringList QDesignerSettings::recentFilesList() const +{ + return settings()->value(QLatin1String(recentFilesListKey)).toStringList(); +} + +void QDesignerSettings::setRecentFilesList(const QStringList &sl) +{ + settings()->setValue(QLatin1String(recentFilesListKey), sl); +} + +void QDesignerSettings::setShowNewFormOnStartup(bool showIt) +{ + settings()->setValue(QLatin1String(newFormShowKey), showIt); +} + +bool QDesignerSettings::showNewFormOnStartup() const +{ + return settings()->value(QLatin1String(newFormShowKey), true).toBool(); +} + +QByteArray QDesignerSettings::mainWindowState(UIMode mode) const +{ + return settings()->value(QLatin1String(mainWindowStateKey) + modeChar(mode)).toByteArray(); +} + +void QDesignerSettings::setMainWindowState(UIMode mode, const QByteArray &mainWindowState) +{ + settings()->setValue(QLatin1String(mainWindowStateKey) + modeChar(mode), mainWindowState); +} + +QByteArray QDesignerSettings::toolBarsState(UIMode mode) const +{ + QString key = QLatin1String(toolBarsStateKey); + key += modeChar(mode); + return settings()->value(key).toByteArray(); +} + +void QDesignerSettings::setToolBarsState(UIMode mode, const QByteArray &toolBarsState) +{ + QString key = QLatin1String(toolBarsStateKey); + key += modeChar(mode); + settings()->setValue(key, toolBarsState); +} + +void QDesignerSettings::clearBackup() +{ + QDesignerSettingsInterface *s = settings(); + s->remove(QLatin1String(backupOrgListKey)); + s->remove(QLatin1String(backupBakListKey)); +} + +void QDesignerSettings::setBackup(const QMap &map) +{ + const QStringList org = map.keys(); + const QStringList bak = map.values(); + + QDesignerSettingsInterface *s = settings(); + s->setValue(QLatin1String(backupOrgListKey), org); + s->setValue(QLatin1String(backupBakListKey), bak); +} + +QMap QDesignerSettings::backup() const +{ + const QStringList org = settings()->value(QLatin1String(backupOrgListKey), QStringList()).toStringList(); + const QStringList bak = settings()->value(QLatin1String(backupBakListKey), QStringList()).toStringList(); + + QMap map; + const int orgCount = org.count(); + for (int i = 0; i < orgCount; ++i) + map.insert(org.at(i), bak.at(i)); + + return map; +} + +void QDesignerSettings::setUiMode(UIMode mode) +{ + QDesignerSettingsInterface *s = settings(); + s->beginGroup(QLatin1String("UI")); + s->setValue(QLatin1String("currentMode"), mode); + s->endGroup(); +} + +UIMode QDesignerSettings::uiMode() const +{ +#ifdef Q_WS_MAC + const UIMode defaultMode = TopLevelMode; +#else + const UIMode defaultMode = DockedMode; +#endif + UIMode uiMode = static_cast(value(QLatin1String("UI/currentMode"), defaultMode).toInt()); + return uiMode; +} + +void QDesignerSettings::setToolWindowFont(const ToolWindowFontSettings &fontSettings) +{ + QDesignerSettingsInterface *s = settings(); + s->beginGroup(QLatin1String("UI")); + s->setValue(QLatin1String("font"), fontSettings.m_font); + s->setValue(QLatin1String("useFont"), fontSettings.m_useFont); + s->setValue(QLatin1String("writingSystem"), fontSettings.m_writingSystem); + s->endGroup(); +} + +ToolWindowFontSettings QDesignerSettings::toolWindowFont() const +{ + ToolWindowFontSettings fontSettings; + fontSettings.m_writingSystem = + static_cast(value(QLatin1String("UI/writingSystem"), + QFontDatabase::Any).toInt()); + fontSettings.m_font = qvariant_cast(value(QLatin1String("UI/font"))); + fontSettings.m_useFont = + settings()->value(QLatin1String("UI/useFont"), QVariant(false)).toBool(); + return fontSettings; +} + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/qdesigner_settings.h b/src/designer/src/designer/qdesigner_settings.h new file mode 100644 index 000000000..2391581b8 --- /dev/null +++ b/src/designer/src/designer/qdesigner_settings.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_SETTINGS_H +#define QDESIGNER_SETTINGS_H + +#include "designer_enums.h" +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerSettingsInterface; +struct ToolWindowFontSettings; + +class QDesignerSettings : public qdesigner_internal::QDesignerSharedSettings +{ +public: + QDesignerSettings(QDesignerFormEditorInterface *core); + + void setValue(const QString &key, const QVariant &value); + QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const; + + void restoreGeometry(QWidget *w, QRect fallBack = QRect()) const; + void saveGeometryFor(const QWidget *w); + + QStringList recentFilesList() const; + void setRecentFilesList(const QStringList &list); + + void setShowNewFormOnStartup(bool showIt); + bool showNewFormOnStartup() const; + + void setUiMode(UIMode mode); + UIMode uiMode() const; + + void setToolWindowFont(const ToolWindowFontSettings &fontSettings); + ToolWindowFontSettings toolWindowFont() const; + + QByteArray mainWindowState(UIMode mode) const; + void setMainWindowState(UIMode mode, const QByteArray &mainWindowState); + + QByteArray toolBarsState(UIMode mode) const; + void setToolBarsState(UIMode mode, const QByteArray &mainWindowState); + + void clearBackup(); + void setBackup(const QMap &map); + QMap backup() const; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_SETTINGS_H diff --git a/src/designer/src/designer/qdesigner_toolwindow.cpp b/src/designer/src/designer/qdesigner_toolwindow.cpp new file mode 100644 index 000000000..376b0afae --- /dev/null +++ b/src/designer/src/designer/qdesigner_toolwindow.cpp @@ -0,0 +1,438 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner.h" +#include "qdesigner_toolwindow.h" +#include "qdesigner_settings.h" +#include "qdesigner_workbench.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +enum { debugToolWindow = 0 }; + +QT_BEGIN_NAMESPACE + +// ---------------- QDesignerToolWindowFontSettings +ToolWindowFontSettings::ToolWindowFontSettings() : + m_writingSystem(QFontDatabase::Any), + m_useFont(false) +{ +} + +bool ToolWindowFontSettings::equals(const ToolWindowFontSettings &rhs) const +{ + return m_useFont == rhs.m_useFont && + m_writingSystem == rhs.m_writingSystem && + m_font == rhs.m_font; +} + +// ---------------- QDesignerToolWindow +QDesignerToolWindow::QDesignerToolWindow(QDesignerWorkbench *workbench, + QWidget *w, + const QString &objectName, + const QString &title, + const QString &actionObjectName, + Qt::DockWidgetArea dockAreaHint, + QWidget *parent, + Qt::WindowFlags flags) : + MainWindowBase(parent, flags), + m_dockAreaHint(dockAreaHint), + m_workbench(workbench), + m_action(new QAction(this)) +{ + setObjectName(objectName); + setCentralWidget(w); + + setWindowTitle(title); + + m_action->setObjectName(actionObjectName); + m_action->setShortcutContext(Qt::ApplicationShortcut); + m_action->setText(title); + m_action->setCheckable(true); + connect(m_action, SIGNAL(triggered(bool)), this, SLOT(showMe(bool))); +} + +void QDesignerToolWindow::showMe(bool v) +{ + // Access the QMdiSubWindow in MDI mode. + if (QWidget *target = m_workbench->mode() == DockedMode ? parentWidget() : this) { + if (v) + target->setWindowState(target->windowState() & ~Qt::WindowMinimized); + target->setVisible(v); + } +} + +void QDesignerToolWindow::showEvent(QShowEvent *e) +{ + Q_UNUSED(e); + + bool blocked = m_action->blockSignals(true); + m_action->setChecked(true); + m_action->blockSignals(blocked); +} + +void QDesignerToolWindow::hideEvent(QHideEvent *e) +{ + Q_UNUSED(e); + + bool blocked = m_action->blockSignals(true); + m_action->setChecked(false); + m_action->blockSignals(blocked); +} + +QAction *QDesignerToolWindow::action() const +{ + return m_action; +} + +void QDesignerToolWindow::changeEvent(QEvent *e) +{ + switch (e->type()) { + case QEvent::WindowTitleChange: + m_action->setText(windowTitle()); + break; + case QEvent::WindowIconChange: + m_action->setIcon(windowIcon()); + break; + default: + break; + } + QMainWindow::changeEvent(e); +} + +QDesignerWorkbench *QDesignerToolWindow::workbench() const +{ + return m_workbench; +} + +QRect QDesignerToolWindow::geometryHint() const +{ + return QRect(); +} + +QRect QDesignerToolWindow::availableToolWindowGeometry() const +{ + return m_workbench->availableGeometry(); +} + +// ---------------------- PropertyEditorToolWindow + +static inline QWidget *createPropertyEditor(QDesignerFormEditorInterface *core, QWidget *parent = 0) +{ + QDesignerPropertyEditorInterface *widget = QDesignerComponents::createPropertyEditor(core, parent); + core->setPropertyEditor(widget); + return widget; +} + +class PropertyEditorToolWindow : public QDesignerToolWindow +{ +public: + explicit PropertyEditorToolWindow(QDesignerWorkbench *workbench); + + virtual QRect geometryHint() const; + +protected: + virtual void showEvent(QShowEvent *event); +}; + +PropertyEditorToolWindow::PropertyEditorToolWindow(QDesignerWorkbench *workbench) : + QDesignerToolWindow(workbench, + createPropertyEditor(workbench->core()), + QLatin1String("qt_designer_propertyeditor"), + QDesignerToolWindow::tr("Property Editor"), + QLatin1String("__qt_property_editor_action"), + Qt::RightDockWidgetArea) +{ + action()->setShortcut(Qt::CTRL + Qt::Key_I); + +} + +QRect PropertyEditorToolWindow::geometryHint() const +{ + const QRect g = availableToolWindowGeometry(); + const int margin = workbench()->marginHint(); + const int spacing = 40; + const QSize sz(g.width() * 1/4, g.height() * 4/6); + + const QRect rc = QRect((g.right() + 1 - sz.width() - margin), + (g.top() + margin + g.height() * 1/6) + spacing, + sz.width(), sz.height()); + if (debugToolWindow) + qDebug() << Q_FUNC_INFO << rc; + return rc; +} + +void PropertyEditorToolWindow::showEvent(QShowEvent *event) +{ + if (QDesignerPropertyEditorInterface *e = workbench()->core()->propertyEditor()) { + // workaround to update the propertyeditor when it is not visible! + e->setObject(e->object()); // ### remove me + } + + QDesignerToolWindow::showEvent(event); +} + +// ---------------------- ActionEditorToolWindow + +static inline QWidget *createActionEditor(QDesignerFormEditorInterface *core, QWidget *parent = 0) +{ + QDesignerActionEditorInterface *widget = QDesignerComponents::createActionEditor(core, parent); + core->setActionEditor(widget); + return widget; +} + +class ActionEditorToolWindow: public QDesignerToolWindow +{ +public: + explicit ActionEditorToolWindow(QDesignerWorkbench *workbench); + + virtual QRect geometryHint() const; +}; + +ActionEditorToolWindow::ActionEditorToolWindow(QDesignerWorkbench *workbench) : + QDesignerToolWindow(workbench, + createActionEditor(workbench->core()), + QLatin1String("qt_designer_actioneditor"), + QDesignerToolWindow::tr("Action Editor"), + QLatin1String("__qt_action_editor_tool_action"), + Qt::RightDockWidgetArea) +{ +} + +QRect ActionEditorToolWindow::geometryHint() const +{ + const QRect g = availableToolWindowGeometry(); + const int margin = workbench()->marginHint(); + + const QSize sz(g.width() * 1/4, g.height() * 1/6); + + const QRect rc = QRect((g.right() + 1 - sz.width() - margin), + g.top() + margin, + sz.width(), sz.height()); + if (debugToolWindow) + qDebug() << Q_FUNC_INFO << rc; + return rc; +} + +// ---------------------- ObjectInspectorToolWindow + +static inline QWidget *createObjectInspector(QDesignerFormEditorInterface *core, QWidget *parent = 0) +{ + QDesignerObjectInspectorInterface *widget = QDesignerComponents::createObjectInspector(core, parent); + core->setObjectInspector(widget); + return widget; +} + +class ObjectInspectorToolWindow: public QDesignerToolWindow +{ +public: + explicit ObjectInspectorToolWindow(QDesignerWorkbench *workbench); + + virtual QRect geometryHint() const; +}; + +ObjectInspectorToolWindow::ObjectInspectorToolWindow(QDesignerWorkbench *workbench) : + QDesignerToolWindow(workbench, + createObjectInspector(workbench->core()), + QLatin1String("qt_designer_objectinspector"), + QDesignerToolWindow::tr("Object Inspector"), + QLatin1String("__qt_object_inspector_tool_action"), + Qt::RightDockWidgetArea) +{ +} + +QRect ObjectInspectorToolWindow::geometryHint() const +{ + const QRect g = availableToolWindowGeometry(); + const int margin = workbench()->marginHint(); + + const QSize sz(g.width() * 1/4, g.height() * 1/6); + + const QRect rc = QRect((g.right() + 1 - sz.width() - margin), + g.top() + margin, + sz.width(), sz.height()); + if (debugToolWindow) + qDebug() << Q_FUNC_INFO << rc; + return rc; +} + +// ---------------------- ResourceEditorToolWindow + +class ResourceEditorToolWindow: public QDesignerToolWindow +{ +public: + explicit ResourceEditorToolWindow(QDesignerWorkbench *workbench); + + virtual QRect geometryHint() const; +}; + +ResourceEditorToolWindow::ResourceEditorToolWindow(QDesignerWorkbench *workbench) : + QDesignerToolWindow(workbench, + QDesignerComponents::createResourceEditor(workbench->core(), 0), + QLatin1String("qt_designer_resourceeditor"), + QDesignerToolWindow::tr("Resource Browser"), + QLatin1String("__qt_resource_editor_tool_action"), + Qt::RightDockWidgetArea) +{ +} + +QRect ResourceEditorToolWindow::geometryHint() const +{ + const QRect g = availableToolWindowGeometry(); + const int margin = workbench()->marginHint(); + + const QSize sz(g.width() * 1/3, g.height() * 1/6); + QRect r(QPoint(0, 0), sz); + r.moveCenter(g.center()); + r.moveBottom(g.bottom() - margin); + if (debugToolWindow) + qDebug() << Q_FUNC_INFO << r; + return r; +} + +// ---------------------- SignalSlotEditorToolWindow + +class SignalSlotEditorToolWindow: public QDesignerToolWindow +{ +public: + explicit SignalSlotEditorToolWindow(QDesignerWorkbench *workbench); + + virtual QRect geometryHint() const; +}; + +SignalSlotEditorToolWindow::SignalSlotEditorToolWindow(QDesignerWorkbench *workbench) : + QDesignerToolWindow(workbench, + QDesignerComponents::createSignalSlotEditor(workbench->core(), 0), + QLatin1String("qt_designer_signalsloteditor"), + QDesignerToolWindow::tr("Signal/Slot Editor"), + QLatin1String("__qt_signal_slot_editor_tool_action"), + Qt::RightDockWidgetArea) +{ +} + +QRect SignalSlotEditorToolWindow::geometryHint() const +{ + const QRect g = availableToolWindowGeometry(); + const int margin = workbench()->marginHint(); + + const QSize sz(g.width() * 1/3, g.height() * 1/6); + QRect r(QPoint(0, 0), sz); + r.moveCenter(g.center()); + r.moveTop(margin + g.top()); + if (debugToolWindow) + qDebug() << Q_FUNC_INFO << r; + return r; +} + +// ---------------------- WidgetBoxToolWindow + +static inline QWidget *createWidgetBox(QDesignerFormEditorInterface *core, QWidget *parent = 0) +{ + QDesignerWidgetBoxInterface *widget = QDesignerComponents::createWidgetBox(core, parent); + core->setWidgetBox(widget); + return widget; +} + +class WidgetBoxToolWindow: public QDesignerToolWindow +{ +public: + explicit WidgetBoxToolWindow(QDesignerWorkbench *workbench); + + virtual QRect geometryHint() const; +}; + +WidgetBoxToolWindow::WidgetBoxToolWindow(QDesignerWorkbench *workbench) : + QDesignerToolWindow(workbench, + createWidgetBox(workbench->core()), + QLatin1String("qt_designer_widgetbox"), + QDesignerToolWindow::tr("Widget Box"), + QLatin1String("__qt_widget_box_tool_action"), + Qt::LeftDockWidgetArea) +{ +} + +QRect WidgetBoxToolWindow::geometryHint() const +{ + const QRect g = availableToolWindowGeometry(); + const int margin = workbench()->marginHint(); + const QRect rc = QRect(g.left() + margin, + g.top() + margin, + g.width() * 1/4, g.height() * 5/6); + if (debugToolWindow) + qDebug() << Q_FUNC_INFO << rc; + return rc; +} + +// -- Factory +QDesignerToolWindow *QDesignerToolWindow::createStandardToolWindow(StandardToolWindow which, + QDesignerWorkbench *workbench) +{ + switch (which) { + case ActionEditor: + return new ActionEditorToolWindow(workbench); + case ResourceEditor: + return new ResourceEditorToolWindow(workbench); + case SignalSlotEditor: + return new SignalSlotEditorToolWindow(workbench); + case PropertyEditor: + return new PropertyEditorToolWindow(workbench); + case ObjectInspector: + return new ObjectInspectorToolWindow(workbench); + case WidgetBox: + return new WidgetBoxToolWindow(workbench); + default: + break; + } + return 0; +} + + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/qdesigner_toolwindow.h b/src/designer/src/designer/qdesigner_toolwindow.h new file mode 100644 index 000000000..1c7b876d1 --- /dev/null +++ b/src/designer/src/designer/qdesigner_toolwindow.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_TOOLWINDOW_H +#define QDESIGNER_TOOLWINDOW_H + +#include "mainwindow.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +struct ToolWindowFontSettings { + ToolWindowFontSettings(); + bool equals(const ToolWindowFontSettings &) const; + + QFont m_font; + QFontDatabase::WritingSystem m_writingSystem; + bool m_useFont; +}; + +inline bool operator==(const ToolWindowFontSettings &tw1, const ToolWindowFontSettings &tw2) +{ + return tw1.equals(tw2); +} + +inline bool operator!=(const ToolWindowFontSettings &tw1, const ToolWindowFontSettings &tw2) +{ + return !tw1.equals(tw2); +} + +class QDesignerWorkbench; + +/* A tool window with an action that activates it. Note that in toplevel mode, + * the Widget box is a tool window as well as the applications' main window, + * So, we need to inherit from MainWindowBase. */ + +class QDesignerToolWindow : public MainWindowBase +{ + Q_OBJECT +protected: + explicit QDesignerToolWindow(QDesignerWorkbench *workbench, + QWidget *w, + const QString &objectName, + const QString &title, + const QString &actionObjectName, + Qt::DockWidgetArea dockAreaHint, + QWidget *parent = 0, + Qt::WindowFlags flags = Qt::Window); + +public: + // Note: The order influences the dock widget position. + enum StandardToolWindow { WidgetBox, ObjectInspector, PropertyEditor, + ResourceEditor, ActionEditor, SignalSlotEditor, + StandardToolWindowCount }; + + static QDesignerToolWindow *createStandardToolWindow(StandardToolWindow which, QDesignerWorkbench *workbench); + + QDesignerWorkbench *workbench() const; + QAction *action() const; + + Qt::DockWidgetArea dockWidgetAreaHint() const { return m_dockAreaHint; } + virtual QRect geometryHint() const; + +private slots: + void showMe(bool); + +protected: + virtual void showEvent(QShowEvent *e); + virtual void hideEvent(QHideEvent *e); + virtual void changeEvent(QEvent *e); + + QRect availableToolWindowGeometry() const; + +private: + const Qt::DockWidgetArea m_dockAreaHint; + QDesignerWorkbench *m_workbench; + QAction *m_action; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_TOOLWINDOW_H diff --git a/src/designer/src/designer/qdesigner_workbench.cpp b/src/designer/src/designer/qdesigner_workbench.cpp new file mode 100644 index 000000000..ffc4b8c7a --- /dev/null +++ b/src/designer/src/designer/qdesigner_workbench.cpp @@ -0,0 +1,1100 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_workbench.h" +#include "qdesigner.h" +#include "qdesigner_actions.h" +#include "qdesigner_appearanceoptions.h" +#include "qdesigner_settings.h" +#include "qdesigner_toolwindow.h" +#include "qdesigner_formwindow.h" +#include "appfontdialog.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static const char *appFontPrefixC = "AppFonts"; + +typedef QList ActionList; + +static QMdiSubWindow *mdiSubWindowOf(const QWidget *w) +{ + QMdiSubWindow *rc = qobject_cast(w->parentWidget()); + Q_ASSERT(rc); + return rc; +} + +static QDockWidget *dockWidgetOf(const QWidget *w) +{ + for (QWidget *parentWidget = w->parentWidget(); parentWidget ; parentWidget = parentWidget->parentWidget()) { + if (QDockWidget *dw = qobject_cast(parentWidget)) { + return dw; + } + } + Q_ASSERT("Dock widget not found"); + return 0; +} + +// ------------ QDesignerWorkbench::Position +QDesignerWorkbench::Position::Position(const QMdiSubWindow *mdiSubWindow, const QPoint &mdiAreaOffset) : + m_minimized(mdiSubWindow->isShaded()), + m_position(mdiSubWindow->pos() + mdiAreaOffset) +{ +} + +QDesignerWorkbench::Position::Position(const QDockWidget *dockWidget) : + m_minimized(dockWidget->isMinimized()), + m_position(dockWidget->pos()) +{ +} + +QDesignerWorkbench::Position::Position(const QWidget *topLevelWindow, const QPoint &desktopTopLeft) +{ + const QWidget *window =topLevelWindow->window (); + Q_ASSERT(window); + m_minimized = window->isMinimized(); + m_position = window->pos() - desktopTopLeft; +} + +void QDesignerWorkbench::Position::applyTo(QMdiSubWindow *mdiSubWindow, + const QPoint &mdiAreaOffset) const +{ + // QMdiSubWindow attempts to resize its children to sizeHint() when switching user interface modes. + // Restore old size + const QPoint mdiAreaPos = QPoint(qMax(0, m_position.x() - mdiAreaOffset.x()), + qMax(0, m_position.y() - mdiAreaOffset.y())); + mdiSubWindow->move(mdiAreaPos); + const QSize decorationSize = mdiSubWindow->size() - mdiSubWindow->contentsRect().size(); + mdiSubWindow->resize(mdiSubWindow->widget()->size() + decorationSize); + mdiSubWindow->show(); + if (m_minimized) { + mdiSubWindow->showShaded(); + } +} + +void QDesignerWorkbench::Position::applyTo(QWidget *topLevelWindow, const QPoint &desktopTopLeft) const +{ + QWidget *window = topLevelWindow->window (); + const QPoint newPos = m_position + desktopTopLeft; + window->move(newPos); + if ( m_minimized) { + topLevelWindow->showMinimized(); + } else { + topLevelWindow->show(); + } +} + +void QDesignerWorkbench::Position::applyTo(QDockWidget *dockWidget) const +{ + dockWidget->widget()->setVisible(true); + dockWidget->setVisible(!m_minimized); +} + +static inline void addActionsToMenu(QMenu *m, const ActionList &al) +{ + const ActionList::const_iterator cend = al.constEnd(); + for (ActionList::const_iterator it = al.constBegin(); it != cend; ++it) + m->addAction(*it); +} + +static inline QMenu *addMenu(QMenuBar *mb, const QString &title, const ActionList &al) +{ + QMenu *rc = mb->addMenu(title); + addActionsToMenu(rc, al); + return rc; +} + +// -------- QDesignerWorkbench + +QDesignerWorkbench::QDesignerWorkbench() : + m_core(QDesignerComponents::createFormEditor(this)), + m_windowActions(new QActionGroup(this)), + m_globalMenuBar(new QMenuBar), + m_mode(NeutralMode), + m_dockedMainWindow(0), + m_state(StateInitializing) +{ + QDesignerSettings settings(m_core); + + (void) QDesignerComponents::createTaskMenu(core(), this); + + initializeCorePlugins(); + QDesignerComponents::initializePlugins(core()); + m_actionManager = new QDesignerActions(this); // accesses plugin components + + m_windowActions->setExclusive(true); + connect(m_windowActions, SIGNAL(triggered(QAction*)), this, SLOT(formWindowActionTriggered(QAction*))); + + // Build main menu bar + addMenu(m_globalMenuBar, tr("&File"), m_actionManager->fileActions()->actions()); + + QMenu *editMenu = addMenu(m_globalMenuBar, tr("&Edit"), m_actionManager->editActions()->actions()); + editMenu->addSeparator(); + addActionsToMenu(editMenu, m_actionManager->toolActions()->actions()); + + QMenu *formMenu = addMenu(m_globalMenuBar, tr("F&orm"), m_actionManager->formActions()->actions()); + QMenu *previewSubMenu = new QMenu(tr("Preview in"), formMenu); + formMenu->insertMenu(m_actionManager->previewFormAction(), previewSubMenu); + addActionsToMenu(previewSubMenu, m_actionManager->styleActions()->actions()); + + QMenu *viewMenu = m_globalMenuBar->addMenu(tr("&View")); + + addMenu(m_globalMenuBar, tr("&Settings"), m_actionManager->settingsActions()->actions()); + + m_windowMenu = addMenu(m_globalMenuBar, tr("&Window"), m_actionManager->windowActions()->actions()); + + addMenu(m_globalMenuBar, tr("&Help"), m_actionManager->helpActions()->actions()); + + // Add the tools in view menu order + QActionGroup *viewActions = new QActionGroup(this); + viewActions->setExclusive(false); + + for (int i = 0; i < QDesignerToolWindow::StandardToolWindowCount; i++) { + QDesignerToolWindow *toolWindow = QDesignerToolWindow::createStandardToolWindow(static_cast< QDesignerToolWindow::StandardToolWindow>(i), this); + m_toolWindows.push_back(toolWindow); + if (QAction *action = toolWindow->action()) { + viewMenu->addAction(action); + viewActions->addAction(action); + } + // The widget box becomes the main window in top level mode + if (i == QDesignerToolWindow::WidgetBox) + connect(toolWindow, SIGNAL(closeEventReceived(QCloseEvent*)), this, SLOT(handleCloseEvent(QCloseEvent*))); + } + // Integration + m_integration = new qdesigner_internal::QDesignerIntegration(m_core, this); + connect(m_integration, SIGNAL(helpRequested(QString,QString)), m_actionManager, SLOT(helpRequested(QString,QString))); + + // remaining view options (config toolbars) + viewMenu->addSeparator(); + m_toolbarMenu = viewMenu->addMenu(tr("Toolbars")); + + emit initialized(); + + connect(m_core->formWindowManager(), SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)), + this, SLOT(updateWindowMenu(QDesignerFormWindowInterface*))); + + + { // Add application specific options pages + QDesignerAppearanceOptionsPage *appearanceOptions = new QDesignerAppearanceOptionsPage(m_core); + connect(appearanceOptions, SIGNAL(settingsChangedDelayed()), this, SLOT(restoreUISettings())); + QList optionsPages = m_core->optionsPages(); + optionsPages.push_front(appearanceOptions); + m_core->setOptionsPages(optionsPages); + } + + restoreUISettings(); + AppFontWidget::restore(m_core->settingsManager(), QLatin1String(appFontPrefixC)); + m_state = StateUp; +} + +QDesignerWorkbench::~QDesignerWorkbench() +{ + switch (m_mode) { + case NeutralMode: + case DockedMode: + qDeleteAll(m_toolWindows); + break; + case TopLevelMode: // Everything parented here + delete widgetBoxToolWindow(); + break; + } +} + +void QDesignerWorkbench::saveGeometriesForModeChange() +{ + m_Positions.clear(); + switch (m_mode) { + case NeutralMode: + break; + case TopLevelMode: { + const QPoint desktopOffset = QApplication::desktop()->availableGeometry().topLeft(); + foreach (QDesignerToolWindow *tw, m_toolWindows) + m_Positions.insert(tw, Position(tw, desktopOffset)); + foreach (QDesignerFormWindow *fw, m_formWindows) { + m_Positions.insert(fw, Position(fw, desktopOffset)); + } + } + break; + case DockedMode: { + const QPoint mdiAreaOffset = m_dockedMainWindow->mdiArea()->pos(); + foreach (QDesignerToolWindow *tw, m_toolWindows) { + m_Positions.insert(tw, Position(dockWidgetOf(tw))); + } + foreach (QDesignerFormWindow *fw, m_formWindows) { + m_Positions.insert(fw, Position(mdiSubWindowOf(fw), mdiAreaOffset)); + } + } + break; + } +} + +UIMode QDesignerWorkbench::mode() const +{ + return m_mode; +} + +void QDesignerWorkbench::addFormWindow(QDesignerFormWindow *formWindow) +{ + // ### Q_ASSERT(formWindow->windowTitle().isEmpty() == false); + + m_formWindows.append(formWindow); + + + m_actionManager->setWindowListSeparatorVisible(true); + + if (QAction *action = formWindow->action()) { + m_windowActions->addAction(action); + m_windowMenu->addAction(action); + action->setChecked(true); + } + + m_actionManager->minimizeAction()->setEnabled(true); + m_actionManager->minimizeAction()->setChecked(false); + connect(formWindow, SIGNAL(minimizationStateChanged(QDesignerFormWindowInterface*,bool)), + this, SLOT(minimizationStateChanged(QDesignerFormWindowInterface*,bool))); + + m_actionManager->editWidgets()->trigger(); +} + +Qt::WindowFlags QDesignerWorkbench::magicalWindowFlags(const QWidget *widgetForFlags) const +{ + switch (m_mode) { + case TopLevelMode: { +#ifdef Q_WS_MAC + if (qobject_cast(widgetForFlags)) + return Qt::Tool; +#else + Q_UNUSED(widgetForFlags); +#endif + return Qt::Window; + } + case DockedMode: + return Qt::Window | Qt::WindowShadeButtonHint | Qt::WindowSystemMenuHint | Qt::WindowTitleHint; + case NeutralMode: + return Qt::Window; + default: + Q_ASSERT(0); + return 0; + } +} + +QWidget *QDesignerWorkbench::magicalParent(const QWidget *w) const +{ + switch (m_mode) { + case TopLevelMode: { + // Use widget box as parent for all windows except self. This will + // result in having just one entry in the MS Windows task bar. + QWidget *widgetBoxWrapper = widgetBoxToolWindow(); + return w == widgetBoxWrapper ? 0 : widgetBoxWrapper; + } + case DockedMode: + return m_dockedMainWindow->mdiArea(); + case NeutralMode: + return 0; + default: + Q_ASSERT(0); + return 0; + } +} + +void QDesignerWorkbench::switchToNeutralMode() +{ + QDesignerSettings settings(m_core); + saveGeometries(settings); + saveGeometriesForModeChange(); + + if (m_mode == TopLevelMode) { + delete m_topLevelData.toolbarManager; + m_topLevelData.toolbarManager = 0; + qDeleteAll(m_topLevelData.toolbars); + m_topLevelData.toolbars.clear(); + } + + m_mode = NeutralMode; + + foreach (QDesignerToolWindow *tw, m_toolWindows) { + tw->setCloseEventPolicy(MainWindowBase::AcceptCloseEvents); + tw->setParent(0); + } + + foreach (QDesignerFormWindow *fw, m_formWindows) { + fw->setParent(0); + fw->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + } + +#ifndef Q_WS_MAC + m_globalMenuBar->setParent(0); +#endif + + m_core->setTopLevel(0); + qDesigner->setMainWindow(0); + + delete m_dockedMainWindow; + m_dockedMainWindow = 0; +} + +void QDesignerWorkbench::switchToDockedMode() +{ + if (m_mode == DockedMode) + return; + + switchToNeutralMode(); + +#ifndef Q_WS_MAC + QDesignerToolWindow *widgetBoxWrapper = widgetBoxToolWindow(); + widgetBoxWrapper->action()->setVisible(true); + widgetBoxWrapper->setWindowTitle(tr("Widget Box")); +#endif + + m_mode = DockedMode; + const QDesignerSettings settings(m_core); + m_dockedMainWindow = new DockedMainWindow(this, m_toolbarMenu, m_toolWindows); + m_dockedMainWindow->setUnifiedTitleAndToolBarOnMac(true); + m_dockedMainWindow->setCloseEventPolicy(MainWindowBase::EmitCloseEventSignal); + connect(m_dockedMainWindow, SIGNAL(closeEventReceived(QCloseEvent*)), this, SLOT(handleCloseEvent(QCloseEvent*))); + connect(m_dockedMainWindow, SIGNAL(fileDropped(QString)), this, SLOT(slotFileDropped(QString))); + connect(m_dockedMainWindow, SIGNAL(formWindowActivated(QDesignerFormWindow*)), this, SLOT(slotFormWindowActivated(QDesignerFormWindow*))); + m_dockedMainWindow->restoreSettings(settings, m_dockedMainWindow->addToolWindows(m_toolWindows), desktopGeometry()); + + m_core->setTopLevel(m_dockedMainWindow); + +#ifndef Q_WS_MAC + m_dockedMainWindow->setMenuBar(m_globalMenuBar); + m_globalMenuBar->show(); +#endif + qDesigner->setMainWindow(m_dockedMainWindow); + + foreach (QDesignerFormWindow *fw, m_formWindows) { + QMdiSubWindow *subwin = m_dockedMainWindow->createMdiSubWindow(fw, magicalWindowFlags(fw), + m_actionManager->closeFormAction()->shortcut()); + subwin->hide(); + if (QWidget *mainContainer = fw->editor()->mainContainer()) + resizeForm(fw, mainContainer); + } + + m_actionManager->setBringAllToFrontVisible(false); + m_dockedMainWindow->show(); + // Trigger adjustMDIFormPositions() delayed as viewport size is not yet known. + + if (m_state != StateInitializing) + QMetaObject::invokeMethod(this, "adjustMDIFormPositions", Qt::QueuedConnection); +} + +void QDesignerWorkbench::adjustMDIFormPositions() +{ + const QPoint mdiAreaOffset = m_dockedMainWindow->mdiArea()->pos(); + + foreach (QDesignerFormWindow *fw, m_formWindows) { + const PositionMap::const_iterator pit = m_Positions.constFind(fw); + if (pit != m_Positions.constEnd()) + pit->applyTo(mdiSubWindowOf(fw), mdiAreaOffset); + } +} + +void QDesignerWorkbench::switchToTopLevelMode() +{ + if (m_mode == TopLevelMode) + return; + + // make sure that the widgetbox is visible if it is different from neutral. + QDesignerToolWindow *widgetBoxWrapper = widgetBoxToolWindow(); + Q_ASSERT(widgetBoxWrapper); + + switchToNeutralMode(); + const QPoint desktopOffset = desktopGeometry().topLeft(); + m_mode = TopLevelMode; + + // The widget box is special, it gets the menubar and gets to be the main widget. + + m_core->setTopLevel(widgetBoxWrapper); +#ifndef Q_WS_MAC + widgetBoxWrapper->setMenuBar(m_globalMenuBar); + widgetBoxWrapper->action()->setVisible(false); + widgetBoxWrapper->setCloseEventPolicy(MainWindowBase::EmitCloseEventSignal); + qDesigner->setMainWindow(widgetBoxWrapper); + widgetBoxWrapper->setWindowTitle(MainWindowBase::mainWindowTitle()); +#endif + + const QDesignerSettings settings(m_core); + m_topLevelData.toolbars = MainWindowBase::createToolBars(m_actionManager, false); + m_topLevelData.toolbarManager = new ToolBarManager(widgetBoxWrapper, widgetBoxWrapper, + m_toolbarMenu, m_actionManager, + m_topLevelData.toolbars, m_toolWindows); + const int toolBarCount = m_topLevelData.toolbars.size(); + for (int i = 0; i < toolBarCount; i++) { + widgetBoxWrapper->addToolBar(m_topLevelData.toolbars.at(i)); + if (i == 3) + widgetBoxWrapper->insertToolBarBreak(m_topLevelData.toolbars.at(i)); + } + m_topLevelData.toolbarManager->restoreState(settings.toolBarsState(m_mode), MainWindowBase::settingsVersion()); + widgetBoxWrapper->restoreState(settings.mainWindowState(m_mode), MainWindowBase::settingsVersion()); + + bool found_visible_window = false; + foreach (QDesignerToolWindow *tw, m_toolWindows) { + tw->setParent(magicalParent(tw), magicalWindowFlags(tw)); + settings.restoreGeometry(tw, tw->geometryHint()); + tw->action()->setChecked(tw->isVisible()); + found_visible_window |= tw->isVisible(); + } + + if (!m_toolWindows.isEmpty() && !found_visible_window) + m_toolWindows.first()->show(); + + m_actionManager->setBringAllToFrontVisible(true); + + foreach (QDesignerFormWindow *fw, m_formWindows) { + fw->setParent(magicalParent(fw), magicalWindowFlags(fw)); + fw->setAttribute(Qt::WA_DeleteOnClose, true); + const PositionMap::const_iterator pit = m_Positions.constFind(fw); + if (pit != m_Positions.constEnd()) pit->applyTo(fw, desktopOffset); + // Force an activate in order to refresh minimumSize, otherwise it will not be respected + if (QLayout *layout = fw->layout()) + layout->invalidate(); + if (QWidget *mainContainer = fw->editor()->mainContainer()) + resizeForm(fw, mainContainer); + } +} + +QDesignerFormWindowManagerInterface *QDesignerWorkbench::formWindowManager() const +{ + return m_core->formWindowManager(); +} + +QDesignerFormEditorInterface *QDesignerWorkbench::core() const +{ + return m_core; +} + +int QDesignerWorkbench::toolWindowCount() const +{ + return m_toolWindows.count(); +} + +QDesignerToolWindow *QDesignerWorkbench::toolWindow(int index) const +{ + return m_toolWindows.at(index); +} + +int QDesignerWorkbench::formWindowCount() const +{ + return m_formWindows.count(); +} + +QDesignerFormWindow *QDesignerWorkbench::formWindow(int index) const +{ + return m_formWindows.at(index); +} + +QRect QDesignerWorkbench::desktopGeometry() const +{ + // Return geometry of the desktop designer is running in. + QWidget *widget = 0; + switch (m_mode) { + case DockedMode: + widget = m_dockedMainWindow; + break; + case TopLevelMode: + widget = widgetBoxToolWindow(); + break; + case NeutralMode: + break; + } + const QDesktopWidget *desktop = qApp->desktop(); + const int screenNumber = widget ? desktop->screenNumber(widget) : 0; + return desktop->availableGeometry(screenNumber); +} + +QRect QDesignerWorkbench::availableGeometry() const +{ + if (m_mode == DockedMode) + return m_dockedMainWindow->mdiArea()->geometry(); + + const QDesktopWidget *desktop = qDesigner->desktop(); + return desktop->availableGeometry(desktop->screenNumber(widgetBoxToolWindow())); +} + +int QDesignerWorkbench::marginHint() const +{ return 20; +} + +void QDesignerWorkbench::slotFormWindowActivated(QDesignerFormWindow* fw) +{ + core()->formWindowManager()->setActiveFormWindow(fw->editor()); +} + +void QDesignerWorkbench::removeFormWindow(QDesignerFormWindow *formWindow) +{ + QDesignerFormWindowInterface *editor = formWindow->editor(); + const bool loadOk = editor->mainContainer(); + updateBackup(editor); + const int index = m_formWindows.indexOf(formWindow); + if (index != -1) { + m_formWindows.removeAt(index); + } + + if (QAction *action = formWindow->action()) { + m_windowActions->removeAction(action); + m_windowMenu->removeAction(action); + } + + if (m_formWindows.empty()) { + m_actionManager->setWindowListSeparatorVisible(false); + // Show up new form dialog unless closing + if (loadOk && m_state == StateUp + && QDesignerSettings(m_core).showNewFormOnStartup()) { + QTimer::singleShot(200, m_actionManager, SLOT(createForm())); + } + } +} + +void QDesignerWorkbench::initializeCorePlugins() +{ + QList plugins = QPluginLoader::staticInstances(); + plugins += core()->pluginManager()->instances(); + + foreach (QObject *plugin, plugins) { + if (QDesignerFormEditorPluginInterface *formEditorPlugin = qobject_cast(plugin)) { + if (!formEditorPlugin->isInitialized()) + formEditorPlugin->initialize(core()); + } + } +} + +void QDesignerWorkbench::saveSettings() const +{ + QDesignerSettings settings(m_core); + settings.clearBackup(); + saveGeometries(settings); + AppFontWidget::save(m_core->settingsManager(), QLatin1String(appFontPrefixC)); +} + +void QDesignerWorkbench::saveGeometries(QDesignerSettings &settings) const +{ + switch (m_mode) { + case DockedMode: + m_dockedMainWindow->saveSettings(settings); + break; + case TopLevelMode: + settings.setToolBarsState(m_mode, m_topLevelData.toolbarManager->saveState(MainWindowBase::settingsVersion())); + settings.setMainWindowState(m_mode, widgetBoxToolWindow()->saveState(MainWindowBase::settingsVersion())); + foreach (const QDesignerToolWindow *tw, m_toolWindows) + settings.saveGeometryFor(tw); + break; + case NeutralMode: + break; + } +} + +void QDesignerWorkbench::slotFileDropped(const QString &f) +{ + readInForm(f); +} + +bool QDesignerWorkbench::readInForm(const QString &fileName) const +{ + return m_actionManager->readInForm(fileName); +} + +bool QDesignerWorkbench::writeOutForm(QDesignerFormWindowInterface *formWindow, const QString &fileName) const +{ + return m_actionManager->writeOutForm(formWindow, fileName); +} + +bool QDesignerWorkbench::saveForm(QDesignerFormWindowInterface *frm) +{ + return m_actionManager->saveForm(frm); +} + +QDesignerFormWindow *QDesignerWorkbench::findFormWindow(QWidget *widget) const +{ + foreach (QDesignerFormWindow *formWindow, m_formWindows) { + if (formWindow->editor() == widget) + return formWindow; + } + + return 0; +} + +bool QDesignerWorkbench::handleClose() +{ + m_state = StateClosing; + QList dirtyForms; + foreach (QDesignerFormWindow *w, m_formWindows) { + if (w->editor()->isDirty()) + dirtyForms << w; + } + + if (dirtyForms.size()) { + if (dirtyForms.size() == 1) { + if (!dirtyForms.at(0)->close()) { + m_state = StateUp; + return false; + } + } else { + int count = dirtyForms.size(); + QMessageBox box(QMessageBox::Warning, tr("Save Forms?"), + tr("There are %n forms with unsaved changes." + " Do you want to review these changes before quitting?", "", count), + QMessageBox::Cancel | QMessageBox::Discard | QMessageBox::Save); + box.setInformativeText(tr("If you do not review your documents, all your changes will be lost.")); + box.button(QMessageBox::Discard)->setText(tr("Discard Changes")); + QPushButton *save = static_cast(box.button(QMessageBox::Save)); + save->setText(tr("Review Changes")); + box.setDefaultButton(save); + switch (box.exec()) { + case QMessageBox::Cancel: + m_state = StateUp; + return false; + case QMessageBox::Save: + foreach (QDesignerFormWindow *fw, dirtyForms) { + fw->show(); + fw->raise(); + if (!fw->close()) { + m_state = StateUp; + return false; + } + } + break; + case QMessageBox::Discard: + foreach (QDesignerFormWindow *fw, dirtyForms) { + fw->editor()->setDirty(false); + fw->setWindowModified(false); + } + break; + } + } + } + + foreach (QDesignerFormWindow *fw, m_formWindows) + fw->close(); + + saveSettings(); + return true; +} + +QDesignerActions *QDesignerWorkbench::actionManager() const +{ + return m_actionManager; +} + +void QDesignerWorkbench::updateWindowMenu(QDesignerFormWindowInterface *fwi) +{ + bool minimizeChecked = false; + bool minimizeEnabled = false; + QDesignerFormWindow *activeFormWindow = 0; + do { + if (!fwi) + break; + activeFormWindow = qobject_cast(fwi->parentWidget()); + if (!activeFormWindow) + break; + + minimizeEnabled = true; + minimizeChecked = isFormWindowMinimized(activeFormWindow); + } while (false) ; + + m_actionManager->minimizeAction()->setEnabled(minimizeEnabled); + m_actionManager->minimizeAction()->setChecked(minimizeChecked); + + if (!m_formWindows.empty()) { + const QList::const_iterator cend = m_formWindows.constEnd(); + for (QList::const_iterator it = m_formWindows.constBegin(); it != cend; ++it) + (*it)->action()->setChecked(*it == activeFormWindow); + } +} + +void QDesignerWorkbench::formWindowActionTriggered(QAction *a) +{ + QDesignerFormWindow *fw = qobject_cast(a->parentWidget()); + Q_ASSERT(fw); + + if (isFormWindowMinimized(fw)) + setFormWindowMinimized(fw, false); + + if (m_mode == DockedMode) { + if (QMdiSubWindow *subWindow = qobject_cast(fw->parent())) { + m_dockedMainWindow->mdiArea()->setActiveSubWindow(subWindow); + } + } else { + fw->activateWindow(); + fw->raise(); + } +} + +void QDesignerWorkbench::closeAllToolWindows() +{ + foreach (QDesignerToolWindow *tw, m_toolWindows) + tw->hide(); +} + +bool QDesignerWorkbench::readInBackup() +{ + const QMap backupFileMap = QDesignerSettings(m_core).backup(); + if (backupFileMap.isEmpty()) + return false; + + const QMessageBox::StandardButton answer = + QMessageBox::question(0, tr("Backup Information"), + tr("The last session of Designer was not terminated correctly. " + "Backup files were left behind. Do you want to load them?"), + QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes); + if (answer == QMessageBox::No) + return false; + + const QString modifiedPlaceHolder = QLatin1String("[*]"); + QMapIterator it(backupFileMap); + while(it.hasNext()) { + it.next(); + + QString fileName = it.key(); + fileName.remove(modifiedPlaceHolder); + + if(m_actionManager->readInForm(it.value())) + formWindowManager()->activeFormWindow()->setFileName(fileName); + + } + return true; +} + +void QDesignerWorkbench::updateBackup(QDesignerFormWindowInterface* fwi) +{ + QString fwn = QDir::convertSeparators(fwi->fileName()); + if (fwn.isEmpty()) + fwn = fwi->parentWidget()->windowTitle(); + + QDesignerSettings settings(m_core); + QMap map = settings.backup(); + map.remove(fwn); + settings.setBackup(map); +} + +namespace { + void raiseWindow(QWidget *w) { + if (w->isMinimized()) + w->setWindowState(w->windowState() & ~Qt::WindowMinimized); + w->raise(); + } +} + +void QDesignerWorkbench::bringAllToFront() +{ + if (m_mode != TopLevelMode) + return; + foreach(QDesignerToolWindow *tw, m_toolWindows) + raiseWindow(tw); + foreach(QDesignerFormWindow *dfw, m_formWindows) + raiseWindow(dfw); +} + +// Resize a form window taking MDI decorations into account +// Apply maximum size as there is no layout connection between +// the form's main container and the integration's outer +// container due to the tool widget stack. + +void QDesignerWorkbench::resizeForm(QDesignerFormWindow *fw, const QWidget *mainContainer) const +{ + const QSize containerSize = mainContainer->size(); + const QSize containerMinimumSize = mainContainer->minimumSize(); + const QSize containerMaximumSize = mainContainer->maximumSize(); + if (m_mode != DockedMode) { + fw->resize(containerSize); + fw->setMaximumSize(containerMaximumSize); + return; + } + // get decorations and resize MDI + QMdiSubWindow *mdiSubWindow = qobject_cast(fw->parent()); + Q_ASSERT(mdiSubWindow); + const QSize decorationSize = mdiSubWindow->geometry().size() - mdiSubWindow->contentsRect().size(); + mdiSubWindow->resize(containerSize + decorationSize); + // In Qt::RightToLeft mode, the window can grow to be partially hidden by the right border. + const int mdiAreaWidth = m_dockedMainWindow->mdiArea()->width(); + if (qApp->layoutDirection() == Qt::RightToLeft && mdiSubWindow->geometry().right() >= mdiAreaWidth) + mdiSubWindow->move(mdiAreaWidth - mdiSubWindow->width(), mdiSubWindow->pos().y()); + + if (containerMaximumSize == QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)) { + mdiSubWindow->setMaximumSize(containerMaximumSize); + } else { + mdiSubWindow->setMaximumSize(containerMaximumSize + decorationSize); + } +} + + +// Load a form or return 0 and do cleanup. file name and editor file +// name in case of loading a template file. + +QDesignerFormWindow * QDesignerWorkbench::loadForm(const QString &fileName, + bool detectLineTermiantorMode, + bool *uic3Converted, + QString *errorMessage) +{ + QFile file(fileName); + + qdesigner_internal::FormWindowBase::LineTerminatorMode mode = qdesigner_internal::FormWindowBase::NativeLineTerminator; + + if (detectLineTermiantorMode) { + if (file.open(QFile::ReadOnly)) { + const QString text = QString::fromUtf8(file.readLine()); + file.close(); + + const int lf = text.indexOf(QLatin1Char('\n')); + if (lf > 0 && text.at(lf-1) == QLatin1Char('\r')) { + mode = qdesigner_internal::FormWindowBase::CRLFLineTerminator; + } else if (lf >= 0) { + mode = qdesigner_internal::FormWindowBase::LFLineTerminator; + } + } + } + + if (!file.open(QFile::ReadOnly|QFile::Text)) { + *errorMessage = tr("The file %1 could not be opened.").arg(file.fileName()); + return 0; + } + + + // Create a form + QDesignerFormWindowManagerInterface *formWindowManager = m_core->formWindowManager(); + + QDesignerFormWindow *formWindow = new QDesignerFormWindow(/*formWindow=*/ 0, this); + addFormWindow(formWindow); + QDesignerFormWindowInterface *editor = formWindow->editor(); + Q_ASSERT(editor); + + // Temporarily set the file name. It is needed when converting a UIC 3 file. + // In this case, the file name will we be cleared on return to force a save box. + editor->setFileName(fileName); + editor->setContents(&file); + + if (qdesigner_internal::FormWindowBase *fwb = qobject_cast(editor)) + fwb->setLineTerminatorMode(mode); + + switch (m_mode) { + case DockedMode: { + // below code must be after above call to setContents(), because setContents() may popup warning dialogs which would cause + // mdi sub window activation (because of dialogs internal call to processEvent or such) + // That activation could have worse consequences, e.g. NULL resource set for active form) before the form is loaded + QMdiSubWindow *subWin = m_dockedMainWindow->createMdiSubWindow(formWindow, magicalWindowFlags(formWindow), m_actionManager->closeFormAction()->shortcut()); + m_dockedMainWindow->mdiArea()->setActiveSubWindow(subWin); + } + break; + case TopLevelMode: { + const QRect formWindowGeometryHint = formWindow->geometryHint(); + formWindow->setAttribute(Qt::WA_DeleteOnClose, true); + formWindow->setParent(magicalParent(formWindow), magicalWindowFlags(formWindow)); + formWindow->resize(formWindowGeometryHint.size()); + formWindow->move(availableGeometry().center() - formWindowGeometryHint.center()); + } + break; + case NeutralMode: + break; + } + + if (!editor->mainContainer()) { + removeFormWindow(formWindow); + formWindowManager->removeFormWindow(editor); + m_core->metaDataBase()->remove(editor); + *errorMessage = tr("The file %1 is not a valid Designer UI file.").arg(file.fileName()); + return 0; + } + *uic3Converted = editor->fileName().isEmpty(); + // Did user specify another (missing) resource path -> set dirty. + const bool dirty = editor->property("_q_resourcepathchanged").toBool(); + editor->setDirty(dirty); + resizeForm(formWindow, editor->mainContainer()); + formWindowManager->setActiveFormWindow(editor); + return formWindow; +} + + +QDesignerFormWindow * QDesignerWorkbench::openForm(const QString &fileName, QString *errorMessage) +{ + bool uic3Converted; + QDesignerFormWindow *rc =loadForm(fileName, true, &uic3Converted, errorMessage); + if (!rc) + return 0; + + if (!uic3Converted) + rc->editor()->setFileName(fileName); + rc->firstShow(); + return rc; +} + +QDesignerFormWindow * QDesignerWorkbench::openTemplate(const QString &templateFileName, + const QString &editorFileName, + QString *errorMessage) +{ + bool uic3Converted; + QDesignerFormWindow *rc =loadForm(templateFileName, false, &uic3Converted, errorMessage); + if (!rc) + return 0; + + if (!uic3Converted) + rc->editor()->setFileName(editorFileName); + + rc->firstShow(); + return rc; +} + +void QDesignerWorkbench::minimizationStateChanged(QDesignerFormWindowInterface *formWindow, bool minimized) +{ + // refresh the minimize action state + if (core()->formWindowManager()->activeFormWindow() == formWindow) { + m_actionManager->minimizeAction()->setChecked(minimized); + } +} + +void QDesignerWorkbench::toggleFormMinimizationState() +{ + QDesignerFormWindowInterface *fwi = core()->formWindowManager()->activeFormWindow(); + if (!fwi || m_mode == NeutralMode) + return; + QDesignerFormWindow *fw = qobject_cast(fwi->parentWidget()); + Q_ASSERT(fw); + setFormWindowMinimized(fw, !isFormWindowMinimized(fw)); +} + +bool QDesignerWorkbench::isFormWindowMinimized(const QDesignerFormWindow *fw) +{ + switch (m_mode) { + case DockedMode: + return mdiSubWindowOf(fw)->isShaded(); + case TopLevelMode: + return fw->window()->isMinimized(); + default: + break; + } + return fw->isMinimized(); +} + +void QDesignerWorkbench::setFormWindowMinimized(QDesignerFormWindow *fw, bool minimized) +{ + switch (m_mode) { + case DockedMode: { + QMdiSubWindow *mdiSubWindow = mdiSubWindowOf(fw); + if (minimized) { + mdiSubWindow->showShaded(); + } else { + mdiSubWindow->setWindowState(mdiSubWindow->windowState() & ~Qt::WindowMinimized); + } + } + break; + case TopLevelMode: { + QWidget *window = fw->window(); + if (window->isMinimized()) { + window->setWindowState(window->windowState() & ~Qt::WindowMinimized); + } else { + window->showMinimized(); + } + } + break; + default: + break; + } +} + +void QDesignerWorkbench::restoreUISettings() +{ + UIMode mode = QDesignerSettings(m_core).uiMode(); + switch (mode) { + case TopLevelMode: + switchToTopLevelMode(); + break; + case DockedMode: + switchToDockedMode(); + break; + + default: Q_ASSERT(0); + } + + ToolWindowFontSettings fontSettings = QDesignerSettings(m_core).toolWindowFont(); + const QFont &font = fontSettings.m_useFont ? fontSettings.m_font : qApp->font(); + + if (font == m_toolWindows.front()->font()) + return; + + foreach(QDesignerToolWindow *tw, m_toolWindows) + tw->setFont(font); +} + +void QDesignerWorkbench::handleCloseEvent(QCloseEvent *ev) +{ + ev->setAccepted(handleClose()); + if (ev->isAccepted()) + QMetaObject::invokeMethod(qDesigner, "quit", Qt::QueuedConnection); // We're going down! +} + +QDesignerToolWindow *QDesignerWorkbench::widgetBoxToolWindow() const +{ + return m_toolWindows.at(QDesignerToolWindow::WidgetBox); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/qdesigner_workbench.h b/src/designer/src/designer/qdesigner_workbench.h new file mode 100644 index 000000000..9266eea60 --- /dev/null +++ b/src/designer/src/designer/qdesigner_workbench.h @@ -0,0 +1,215 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_WORKBENCH_H +#define QDESIGNER_WORKBENCH_H + +#include "designer_enums.h" + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerActions; +class QDesignerToolWindow; +class QDesignerFormWindow; +class DockedMainWindow; +class QDesignerSettings; + +class QAction; +class QActionGroup; +class QDockWidget; +class QMenu; +class QMenuBar; +class QMainWindow; +class QToolBar; +class QMdiArea; +class QMdiSubWindow; +class QCloseEvent; +class QFont; +class QtToolBarManager; +class ToolBarManager; + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; +class QDesignerFormWindowManagerInterface; + +namespace qdesigner_internal { +class QDesignerIntegration; +} + +class QDesignerWorkbench: public QObject +{ + Q_OBJECT + +public: + QDesignerWorkbench(); + virtual ~QDesignerWorkbench(); + + UIMode mode() const; + + QDesignerFormEditorInterface *core() const; + QDesignerFormWindow *findFormWindow(QWidget *widget) const; + + QDesignerFormWindow *openForm(const QString &fileName, QString *errorMessage); + QDesignerFormWindow *openTemplate(const QString &templateFileName, + const QString &editorFileName, + QString *errorMessage); + + int toolWindowCount() const; + QDesignerToolWindow *toolWindow(int index) const; + + int formWindowCount() const; + QDesignerFormWindow *formWindow(int index) const; + + QDesignerActions *actionManager() const; + + QActionGroup *modeActionGroup() const; + + QRect availableGeometry() const; + QRect desktopGeometry() const; + + int marginHint() const; + + bool readInForm(const QString &fileName) const; + bool writeOutForm(QDesignerFormWindowInterface *formWindow, const QString &fileName) const; + bool saveForm(QDesignerFormWindowInterface *fw); + bool handleClose(); + bool readInBackup(); + void updateBackup(QDesignerFormWindowInterface* fwi); + +signals: + void modeChanged(UIMode mode); + void initialized(); + +public slots: + void addFormWindow(QDesignerFormWindow *formWindow); + void removeFormWindow(QDesignerFormWindow *formWindow); + void bringAllToFront(); + void toggleFormMinimizationState(); + +private slots: + void switchToNeutralMode(); + void switchToDockedMode(); + void switchToTopLevelMode(); + void initializeCorePlugins(); + void handleCloseEvent(QCloseEvent *); + void slotFormWindowActivated(QDesignerFormWindow* fw); + void updateWindowMenu(QDesignerFormWindowInterface *fw); + void formWindowActionTriggered(QAction *a); + void adjustMDIFormPositions(); + void minimizationStateChanged(QDesignerFormWindowInterface *formWindow, bool minimized); + + void restoreUISettings(); + void slotFileDropped(const QString &f); + +private: + QWidget *magicalParent(const QWidget *w) const; + Qt::WindowFlags magicalWindowFlags(const QWidget *widgetForFlags) const; + QDesignerFormWindowManagerInterface *formWindowManager() const; + void closeAllToolWindows(); + QDesignerToolWindow *widgetBoxToolWindow() const; + QDesignerFormWindow *loadForm(const QString &fileName, bool detectLineTermiantorMode, bool *uic3Converted, QString *errorMessage); + void resizeForm(QDesignerFormWindow *fw, const QWidget *mainContainer) const; + void saveGeometriesForModeChange(); + void saveGeometries(QDesignerSettings &settings) const; + + bool isFormWindowMinimized(const QDesignerFormWindow *fw); + void setFormWindowMinimized(QDesignerFormWindow *fw, bool minimized); + void saveSettings() const; + + QDesignerFormEditorInterface *m_core; + qdesigner_internal::QDesignerIntegration *m_integration; + + QDesignerActions *m_actionManager; + QActionGroup *m_windowActions; + + QMenu *m_windowMenu; + + QMenuBar *m_globalMenuBar; + + struct TopLevelData { + ToolBarManager *toolbarManager; + QList toolbars; + }; + TopLevelData m_topLevelData; + + UIMode m_mode; + DockedMainWindow *m_dockedMainWindow; + + QList m_toolWindows; + QList m_formWindows; + + QMenu *m_toolbarMenu; + + // Helper class to remember the position of a window while switching user + // interface modes. + class Position { + public: + Position(const QDockWidget *dockWidget); + Position(const QMdiSubWindow *mdiSubWindow, const QPoint &mdiAreaOffset); + Position(const QWidget *topLevelWindow, const QPoint &desktopTopLeft); + + void applyTo(QMdiSubWindow *mdiSubWindow, const QPoint &mdiAreaOffset) const; + void applyTo(QWidget *topLevelWindow, const QPoint &desktopTopLeft) const; + void applyTo(QDockWidget *dockWidget) const; + + QPoint position() const { return m_position; } + private: + bool m_minimized; + // Position referring to top-left corner (desktop in top-level mode or + // main window in MDI mode) + QPoint m_position; + }; + typedef QHash PositionMap; + PositionMap m_Positions; + + enum State { StateInitializing, StateUp, StateClosing }; + State m_state; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_WORKBENCH_H diff --git a/src/designer/src/designer/saveformastemplate.cpp b/src/designer/src/designer/saveformastemplate.cpp new file mode 100644 index 000000000..49ac64ee5 --- /dev/null +++ b/src/designer/src/designer/saveformastemplate.cpp @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "saveformastemplate.h" +#include "qdesigner_settings.h" + +#include +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +SaveFormAsTemplate::SaveFormAsTemplate(QDesignerFormEditorInterface *core, + QDesignerFormWindowInterface *formWindow, + QWidget *parent) + : QDialog(parent, Qt::Sheet), + m_core(core), + m_formWindow(formWindow) +{ + ui.setupUi(this); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + ui.templateNameEdit->setText(formWindow->mainContainer()->objectName()); + ui.templateNameEdit->selectAll(); + + ui.templateNameEdit->setFocus(); + + QStringList paths = QDesignerSettings(m_core).formTemplatePaths(); + ui.categoryCombo->addItems(paths); + ui.categoryCombo->addItem(tr("Add path...")); + m_addPathIndex = ui.categoryCombo->count() - 1; + connect(ui.templateNameEdit, SIGNAL(textChanged(QString)), + this, SLOT(updateOKButton(QString))); + connect(ui.categoryCombo, SIGNAL(activated(int)), this, SLOT(checkToAddPath(int))); +} + +SaveFormAsTemplate::~SaveFormAsTemplate() +{ +} + +void SaveFormAsTemplate::accept() +{ + QString templateFileName = ui.categoryCombo->currentText(); + templateFileName += QLatin1Char('/'); + const QString name = ui.templateNameEdit->text(); + templateFileName += name; + const QString extension = QLatin1String(".ui"); + if (!templateFileName.endsWith(extension)) + templateFileName.append(extension); + QFile file(templateFileName); + + if (file.exists()) { + QMessageBox msgBox(QMessageBox::Information, tr("Template Exists"), + tr("A template with the name %1 already exists.\n" + "Do you want overwrite the template?").arg(name), QMessageBox::Cancel, m_formWindow); + msgBox.setDefaultButton(QMessageBox::Cancel); + QPushButton *overwriteButton = msgBox.addButton(tr("Overwrite Template"), QMessageBox::AcceptRole); + msgBox.exec(); + if (msgBox.clickedButton() != overwriteButton) + return; + } + + while (!file.open(QFile::WriteOnly)) { + if (QMessageBox::information(m_formWindow, tr("Open Error"), + tr("There was an error opening template %1 for writing. Reason: %2").arg(name).arg(file.errorString()), + QMessageBox::Retry|QMessageBox::Cancel, QMessageBox::Cancel) == QMessageBox::Cancel) { + return; + } + } + + const QString origName = m_formWindow->fileName(); + // ensure m_formWindow->contents() will convert properly resource paths to relative paths + // (relative to template location, not to the current form location) + m_formWindow->setFileName(templateFileName); + QByteArray ba = m_formWindow->contents().toUtf8(); + m_formWindow->setFileName(origName); + while (file.write(ba) != ba.size()) { + if (QMessageBox::information(m_formWindow, tr("Write Error"), + tr("There was an error writing the template %1 to disk. Reason: %2").arg(name).arg(file.errorString()), + QMessageBox::Retry|QMessageBox::Cancel, QMessageBox::Cancel) == QMessageBox::Cancel) { + file.close(); + file.remove(); + return; + } + file.reset(); + } + // update the list of places too... + QStringList sl; + for (int i = 0; i < m_addPathIndex; ++i) + sl << ui.categoryCombo->itemText(i); + + QDesignerSettings(m_core).setFormTemplatePaths(sl); + + QDialog::accept(); +} + +void SaveFormAsTemplate::updateOKButton(const QString &str) +{ + QPushButton *okButton = ui.buttonBox->button(QDialogButtonBox::Ok); + okButton->setEnabled(!str.isEmpty()); +} + +QString SaveFormAsTemplate::chooseTemplatePath(QWidget *parent) +{ + QString rc = QFileDialog::getExistingDirectory(parent, + tr("Pick a directory to save templates in")); + if (rc.isEmpty()) + return rc; + + if (rc.endsWith(QDir::separator())) + rc.remove(rc.size() - 1, 1); + return rc; +} + +void SaveFormAsTemplate::checkToAddPath(int itemIndex) +{ + if (itemIndex != m_addPathIndex) + return; + + const QString dir = chooseTemplatePath(this); + if (dir.isEmpty()) { + ui.categoryCombo->setCurrentIndex(0); + return; + } + + ui.categoryCombo->insertItem(m_addPathIndex, dir); + ui.categoryCombo->setCurrentIndex(m_addPathIndex); + ++m_addPathIndex; +} + +QT_END_NAMESPACE diff --git a/src/designer/src/designer/saveformastemplate.h b/src/designer/src/designer/saveformastemplate.h new file mode 100644 index 000000000..8b0b3ab8e --- /dev/null +++ b/src/designer/src/designer/saveformastemplate.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SAVEFORMASTEMPLATE_H +#define SAVEFORMASTEMPLATE_H + +#include "ui_saveformastemplate.h" + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; + +class SaveFormAsTemplate: public QDialog +{ + Q_OBJECT +public: + explicit SaveFormAsTemplate(QDesignerFormEditorInterface *m_core, + QDesignerFormWindowInterface *formWindow, + QWidget *parent = 0); + virtual ~SaveFormAsTemplate(); + +private slots: + void accept(); + void updateOKButton(const QString &str); + void checkToAddPath(int itemIndex); + +private: + static QString chooseTemplatePath(QWidget *parent); + + Ui::SaveFormAsTemplate ui; + QDesignerFormEditorInterface *m_core; + QDesignerFormWindowInterface *m_formWindow; + int m_addPathIndex; +}; + +QT_END_NAMESPACE + +#endif // SAVEFORMASTEMPLATE_H diff --git a/src/designer/src/designer/saveformastemplate.ui b/src/designer/src/designer/saveformastemplate.ui new file mode 100644 index 000000000..c29ad9ad4 --- /dev/null +++ b/src/designer/src/designer/saveformastemplate.ui @@ -0,0 +1,166 @@ + + ********************************************************************* +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +********************************************************************* + SaveFormAsTemplate + + + Save Form As Template + + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + &Name: + + + Qt::AutoText + + + templateNameEdit + + + + + + + + 222 + 0 + + + + + + + QLineEdit::Normal + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + &Category: + + + Qt::AutoText + + + categoryCombo + + + + + + + + + + + + QFrame::HLine + + + QFrame::Sunken + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + SaveFormAsTemplate + accept() + + + 256 + 124 + + + 113 + 143 + + + + + buttonBox + rejected() + SaveFormAsTemplate + reject() + + + 332 + 127 + + + 372 + 147 + + + + + diff --git a/src/designer/src/designer/uifile.icns b/src/designer/src/designer/uifile.icns new file mode 100644 index 000000000..2473ea4dc Binary files /dev/null and b/src/designer/src/designer/uifile.icns differ diff --git a/src/designer/src/designer/versiondialog.cpp b/src/designer/src/designer/versiondialog.cpp new file mode 100644 index 000000000..63a95e6d7 --- /dev/null +++ b/src/designer/src/designer/versiondialog.cpp @@ -0,0 +1,191 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "versiondialog.h" + +QT_BEGIN_NAMESPACE + +class VersionLabel : public QLabel +{ + Q_OBJECT +public: + VersionLabel(QWidget *parent = 0); + +signals: + void triggered(); + +protected: + void mousePressEvent(QMouseEvent *me); + void mouseMoveEvent(QMouseEvent *me); + void mouseReleaseEvent(QMouseEvent *me); + void paintEvent(QPaintEvent *pe); +private: + QVector hitPoints; + QVector missPoints; + QPainterPath m_path; + bool secondStage; + bool m_pushed; +}; + +VersionLabel::VersionLabel(QWidget *parent) + : QLabel(parent), secondStage(false), m_pushed(false) +{ + setPixmap(QPixmap(QLatin1String(":/trolltech/designer/images/designer.png"))); + hitPoints.append(QPoint(56, 25)); + hitPoints.append(QPoint(29, 55)); + hitPoints.append(QPoint(56, 87)); + hitPoints.append(QPoint(82, 55)); + hitPoints.append(QPoint(58, 56)); + + secondStage = false; + m_pushed = false; +} + +void VersionLabel::mousePressEvent(QMouseEvent *me) +{ + if (me->button() == Qt::LeftButton) { + if (!secondStage) { + m_path = QPainterPath(me->pos()); + } else { + m_pushed = true; + update(); + } + } +} + +void VersionLabel::mouseMoveEvent(QMouseEvent *me) +{ + if (me->buttons() & Qt::LeftButton) + if (!secondStage) + m_path.lineTo(me->pos()); +} + +void VersionLabel::mouseReleaseEvent(QMouseEvent *me) +{ + if (me->button() == Qt::LeftButton) { + if (!secondStage) { + m_path.lineTo(me->pos()); + bool gotIt = true; + foreach(const QPoint &pt, hitPoints) { + if (!m_path.contains(pt)) { + gotIt = false; + break; + } + } + if (gotIt) { + foreach(const QPoint &pt, missPoints) { + if (m_path.contains(pt)) { + gotIt = false; + break; + } + } + } + if (gotIt && !secondStage) { + secondStage = true; + m_path = QPainterPath(); + update(); + } + } else { + m_pushed = false; + update(); + emit triggered(); + } + } +} + +void VersionLabel::paintEvent(QPaintEvent *pe) +{ + if (secondStage) { + QPainter p(this); + QStyleOptionButton opt; + opt.init(this); + if (!m_pushed) + opt.state |= QStyle::State_Raised; + else + opt.state |= QStyle::State_Sunken; + opt.state &= ~QStyle::State_HasFocus; + style()->drawControl(QStyle::CE_PushButtonBevel, &opt, &p, this); + } + QLabel::paintEvent(pe); +} + +VersionDialog::VersionDialog(QWidget *parent) + : QDialog(parent +#ifdef Q_WS_MAC + , Qt::Tool +#endif + ) +{ + setWindowFlags((windowFlags() & ~Qt::WindowContextHelpButtonHint) | Qt::MSWindowsFixedSizeDialogHint); + QGridLayout *layout = new QGridLayout(this); + VersionLabel *label = new VersionLabel; + QLabel *lbl = new QLabel; + QString version = tr("

%1



Version %2"); + version = version.arg(tr("Qt Designer")).arg(QLatin1String(QT_VERSION_STR)); + version.append(tr("
Qt Designer is a graphical user interface designer for Qt applications.
")); + + lbl->setText(tr("%1" + "
Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies)." + ).arg(version)); + + lbl->setWordWrap(true); + lbl->setOpenExternalLinks(true); + + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); + connect(buttonBox , SIGNAL(rejected()), this, SLOT(reject())); + connect(label, SIGNAL(triggered()), this, SLOT(accept())); + layout->addWidget(label, 0, 0, 1, 1); + layout->addWidget(lbl, 0, 1, 4, 4); + layout->addWidget(buttonBox, 4, 2, 1, 1); +} + +QT_END_NAMESPACE + +#include "versiondialog.moc" diff --git a/src/designer/src/designer/versiondialog.h b/src/designer/src/designer/versiondialog.h new file mode 100644 index 000000000..0e6760092 --- /dev/null +++ b/src/designer/src/designer/versiondialog.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef VERSIONDIALOG_H +#define VERSIONDIALOG_H + +#include + +QT_BEGIN_NAMESPACE + +class VersionDialog : public QDialog +{ + Q_OBJECT +public: + explicit VersionDialog(QWidget *parent); +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/designer/src/lib/components/qdesigner_components.h b/src/designer/src/lib/components/qdesigner_components.h new file mode 100644 index 000000000..e11afc3ee --- /dev/null +++ b/src/designer/src/lib/components/qdesigner_components.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_COMPONENTS_H +#define QDESIGNER_COMPONENTS_H + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QObject; +class QWidget; + +class QDesignerFormEditorInterface; +class QDesignerWidgetBoxInterface; +class QDesignerPropertyEditorInterface; +class QDesignerObjectInspectorInterface; +class QDesignerActionEditorInterface; + +class QDESIGNER_COMPONENTS_EXPORT QDesignerComponents +{ +public: + static void initializeResources(); + static void initializePlugins(QDesignerFormEditorInterface *core); + + static QDesignerFormEditorInterface *createFormEditor(QObject *parent); + static QDesignerWidgetBoxInterface *createWidgetBox(QDesignerFormEditorInterface *core, QWidget *parent); + static QDesignerPropertyEditorInterface *createPropertyEditor(QDesignerFormEditorInterface *core, QWidget *parent); + static QDesignerObjectInspectorInterface *createObjectInspector(QDesignerFormEditorInterface *core, QWidget *parent); + static QDesignerActionEditorInterface *createActionEditor(QDesignerFormEditorInterface *core, QWidget *parent); + + static QObject *createTaskMenu(QDesignerFormEditorInterface *core, QObject *parent); + static QWidget *createResourceEditor(QDesignerFormEditorInterface *core, QWidget *parent); + static QWidget *createSignalSlotEditor(QDesignerFormEditorInterface *core, QWidget *parent); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDESIGNER_COMPONENTS_H diff --git a/src/designer/src/lib/components/qdesigner_components_global.h b/src/designer/src/lib/components/qdesigner_components_global.h new file mode 100644 index 000000000..93f3c73ce --- /dev/null +++ b/src/designer/src/lib/components/qdesigner_components_global.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDESIGNER_COMPONENTS_GLOBAL_H +#define QDESIGNER_COMPONENTS_GLOBAL_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#define QDESIGNER_COMPONENTS_EXTERN Q_DECL_EXPORT +#define QDESIGNER_COMPONENTS_IMPORT Q_DECL_IMPORT + +#ifdef QT_DESIGNER_STATIC +# define QDESIGNER_COMPONENTS_EXPORT +#elif defined(QDESIGNER_COMPONENTS_LIBRARY) +# define QDESIGNER_COMPONENTS_EXPORT QDESIGNER_COMPONENTS_EXTERN +#else +# define QDESIGNER_COMPONENTS_EXPORT QDESIGNER_COMPONENTS_IMPORT +#endif + + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QDESIGNER_COMPONENTS_GLOBAL_H diff --git a/src/designer/src/lib/extension/default_extensionfactory.cpp b/src/designer/src/lib/extension/default_extensionfactory.cpp new file mode 100644 index 000000000..a90886695 --- /dev/null +++ b/src/designer/src/lib/extension/default_extensionfactory.cpp @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "qextensionmanager.h" +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QExtensionFactory + + \brief The QExtensionFactory class allows you to create a factory + that is able to make instances of custom extensions in Qt + Designer. + + \inmodule QtDesigner + + In \QD the extensions are not created until they are required. For + that reason, when implementing a custom extension, you must also + create a QExtensionFactory, i.e. a class that is able to make an + instance of your extension, and register it using \QD's \l + {QExtensionManager}{extension manager}. + + The QExtensionManager class provides extension management + facilities for Qt Designer. When an extension is required, Qt + Designer's \l {QExtensionManager}{extension manager} will run + through all its registered factories calling + QExtensionFactory::createExtension() for each until the first one + that is able to create a requested extension for the selected + object, is found. This factory will then make an instance of the + extension. + + There are four available types of extensions in Qt Designer: + QDesignerContainerExtension , QDesignerMemberSheetExtension, + QDesignerPropertySheetExtension and QDesignerTaskMenuExtension. Qt + Designer's behavior is the same whether the requested extension is + associated with a multi page container, a member sheet, a property + sheet or a task menu. + + You can either create a new QExtensionFactory and reimplement the + QExtensionFactory::createExtension() function. For example: + + \snippet doc/src/snippets/code/tools_designer_src_lib_extension_default_extensionfactory.cpp 0 + + Or you can use an existing factory, expanding the + QExtensionFactory::createExtension() function to make the factory + able to create your extension as well. For example: + + \snippet doc/src/snippets/code/tools_designer_src_lib_extension_default_extensionfactory.cpp 1 + + For a complete example using the QExtensionFactory class, see the + \l {designer/taskmenuextension}{Task Menu Extension example}. The + example shows how to create a custom widget plugin for Qt + Designer, and how to to use the QDesignerTaskMenuExtension class + to add custom items to Qt Designer's task menu. + + \sa QExtensionManager, QAbstractExtensionFactory +*/ + +/*! + Constructs an extension factory with the given \a parent. +*/ +QExtensionFactory::QExtensionFactory(QExtensionManager *parent) + : QObject(parent) +{ +} + +/*! + Returns the extension specified by \a iid for the given \a object. + + \sa createExtension() +*/ + +QObject *QExtensionFactory::extension(QObject *object, const QString &iid) const +{ + if (!object) + return 0; + const IdObjectKey key = qMakePair(iid, object); + + ExtensionMap::iterator it = m_extensions.find(key); + if (it == m_extensions.end()) { + if (QObject *ext = createExtension(object, iid, const_cast(this))) { + connect(ext, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*))); + it = m_extensions.insert(key, ext); + } + } + + if (!m_extended.contains(object)) { + connect(object, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*))); + m_extended.insert(object, true); + } + + if (it == m_extensions.end()) + return 0; + + return it.value(); +} + +void QExtensionFactory::objectDestroyed(QObject *object) +{ + QMutableMapIterator< IdObjectKey, QObject*> it(m_extensions); + while (it.hasNext()) { + it.next(); + + QObject *o = it.key().second; + if (o == object || object == it.value()) { + it.remove(); + } + } + + m_extended.remove(object); +} + +/*! + Creates an extension specified by \a iid for the given \a object. + The extension object is created as a child of the specified \a + parent. + + \sa extension() +*/ +QObject *QExtensionFactory::createExtension(QObject *object, const QString &iid, QObject *parent) const +{ + Q_UNUSED(object); + Q_UNUSED(iid); + Q_UNUSED(parent); + + return 0; +} + +/*! + Returns the extension manager for the extension factory. +*/ +QExtensionManager *QExtensionFactory::extensionManager() const +{ + return static_cast(parent()); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/extension/default_extensionfactory.h b/src/designer/src/lib/extension/default_extensionfactory.h new file mode 100644 index 000000000..370e69aae --- /dev/null +++ b/src/designer/src/lib/extension/default_extensionfactory.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DEFAULT_EXTENSIONFACTORY_H +#define DEFAULT_EXTENSIONFACTORY_H + +#include +#include + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QExtensionManager; + +class QDESIGNER_EXTENSION_EXPORT QExtensionFactory : public QObject, public QAbstractExtensionFactory +{ + Q_OBJECT + Q_INTERFACES(QAbstractExtensionFactory) +public: + QExtensionFactory(QExtensionManager *parent = 0); + + virtual QObject *extension(QObject *object, const QString &iid) const; + QExtensionManager *extensionManager() const; + +private Q_SLOTS: + void objectDestroyed(QObject *object); + +protected: + virtual QObject *createExtension(QObject *object, const QString &iid, QObject *parent) const; + +private: + typedef QPair IdObjectKey; + typedef QMap< IdObjectKey, QObject*> ExtensionMap; + mutable ExtensionMap m_extensions; + typedef QHash ExtendedSet; + mutable ExtendedSet m_extended; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // DEFAULT_EXTENSIONFACTORY_H diff --git a/src/designer/src/lib/extension/extension.cpp b/src/designer/src/lib/extension/extension.cpp new file mode 100644 index 000000000..4d325126b --- /dev/null +++ b/src/designer/src/lib/extension/extension.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QAbstractExtensionFactory + + \brief The QAbstractExtensionFactory class provides an interface + for extension factories in Qt Designer. + + \inmodule QtDesigner + + QAbstractExtensionFactory is not intended to be instantiated + directly; use the QExtensionFactory instead. + + In \QD, extension factories are used to look up and create named + extensions as they are required. For that reason, when + implementing a custom extension, you must also create a + QExtensionFactory, i.e a class that is able to make an instance of + your extension, and register it using \QD's \l + {QExtensionManager}{extension manager}. + + When an extension is required, \QD's \l + {QExtensionManager}{extension manager} will run through all its + registered factories calling QExtensionFactory::createExtension() + for each until the first one that is able to create the requested + extension for the selected object, is found. This factory will + then make an instance of the extension. + + \sa QExtensionFactory, QExtensionManager +*/ + +/*! + \fn QAbstractExtensionFactory::~QAbstractExtensionFactory() + + Destroys the extension factory. +*/ + +/*! + \fn QObject *QAbstractExtensionFactory::extension(QObject *object, const QString &iid) const + + Returns the extension specified by \a iid for the given \a object. +*/ + + +/*! + \class QAbstractExtensionManager + + \brief The QAbstractExtensionManager class provides an interface + for extension managers in Qt Designer. + + \inmodule QtDesigner + + QAbstractExtensionManager is not intended to be instantiated + directly; use the QExtensionManager instead. + + In \QD, extension are not created until they are required. For + that reason, when implementing a custom extension, you must also + create a QExtensionFactory, i.e a class that is able to make an + instance of your extension, and register it using \QD's \l + {QExtensionManager}{extension manager}. + + When an extension is required, \QD's \l + {QExtensionManager}{extension manager} will run through all its + registered factories calling QExtensionFactory::createExtension() + for each until the first one that is able to create the requested + extension for the selected object, is found. This factory will + then make an instance of the extension. + + \sa QExtensionManager, QExtensionFactory +*/ + +/*! + \fn QAbstractExtensionManager::~QAbstractExtensionManager() + + Destroys the extension manager. +*/ + +/*! + \fn void QAbstractExtensionManager::registerExtensions(QAbstractExtensionFactory *factory, const QString &iid) + + Register the given extension \a factory with the extension + specified by \a iid. +*/ + +/*! + \fn void QAbstractExtensionManager::unregisterExtensions(QAbstractExtensionFactory *factory, const QString &iid) + + Unregister the given \a factory with the extension specified by \a + iid. +*/ + +/*! + \fn QObject *QAbstractExtensionManager::extension(QObject *object, const QString &iid) const + + Returns the extension, specified by \a iid, for the given \a + object. +*/ + +/*! + \fn T qt_extension(QAbstractExtensionManager* manager, QObject *object) + + \relates QExtensionManager + + Returns the extension of the given \a object cast to type T if the + object is of type T (or of a subclass); otherwise returns 0. The + extension is retrieved using the given extension \a manager. + + \snippet doc/src/snippets/code/tools_designer_src_lib_extension_extension.cpp 0 + + When implementing a custom widget plugin, a pointer to \QD's + current QDesignerFormEditorInterface object (\c formEditor) is + provided by the QDesignerCustomWidgetInterface::initialize() + function's parameter. + + If the widget in the example above doesn't have a defined + QDesignerPropertySheetExtension, \c propertySheet will be a null + pointer. + +*/ + +/*! + \macro Q_DECLARE_EXTENSION_INTERFACE(ExtensionName, Identifier) + + \relates QExtensionManager + + Associates the given \a Identifier (a string literal) to the + extension class called \a ExtensionName. The \a Identifier must be + unique. For example: + + \snippet doc/src/snippets/code/tools_designer_src_lib_extension_extension.cpp 1 + + Using the company and product names is a good way to ensure + uniqueness of the identifier. + + When implementing a custom extension class, you must use + Q_DECLARE_EXTENSION_INTERFACE() to enable usage of the + qt_extension() function. The macro is normally located right after the + class definition for \a ExtensionName, in the associated header + file. + + \sa Q_DECLARE_INTERFACE() +*/ + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/extension/extension.h b/src/designer/src/lib/extension/extension.h new file mode 100644 index 000000000..749550324 --- /dev/null +++ b/src/designer/src/lib/extension/extension.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef EXTENSION_H +#define EXTENSION_H + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +#define Q_TYPEID(IFace) QLatin1String(IFace##_iid) + +class QAbstractExtensionFactory +{ +public: + virtual ~QAbstractExtensionFactory() {} + + virtual QObject *extension(QObject *object, const QString &iid) const = 0; +}; +Q_DECLARE_INTERFACE(QAbstractExtensionFactory, "com.trolltech.Qt.QAbstractExtensionFactory") + +class QAbstractExtensionManager +{ +public: + virtual ~QAbstractExtensionManager() {} + + virtual void registerExtensions(QAbstractExtensionFactory *factory, const QString &iid) = 0; + virtual void unregisterExtensions(QAbstractExtensionFactory *factory, const QString &iid) = 0; + + virtual QObject *extension(QObject *object, const QString &iid) const = 0; +}; +Q_DECLARE_INTERFACE(QAbstractExtensionManager, "com.trolltech.Qt.QAbstractExtensionManager") + +#if defined(Q_CC_MSVC) && (_MSC_VER < 1300) + +template +inline T qt_extension_helper(QAbstractExtensionManager *, QObject *, T) +{ return 0; } + +template +inline T qt_extension(QAbstractExtensionManager* manager, QObject *object) +{ return qt_extension_helper(manager, object, T(0)); } + +#define Q_DECLARE_EXTENSION_INTERFACE(IFace, IId) \ +const char * const IFace##_iid = IId; \ +Q_DECLARE_INTERFACE(IFace, IId) \ +template <> inline IFace *qt_extension_helper(QAbstractExtensionManager *manager, QObject *object, IFace *) \ +{ QObject *extension = manager->extension(object, Q_TYPEID(IFace)); return (IFace *)(extension ? extension->qt_metacast(IFace##_iid) : 0); } + +#else + +template +inline T qt_extension(QAbstractExtensionManager* manager, QObject *object) +{ return 0; } + +#define Q_DECLARE_EXTENSION_INTERFACE(IFace, IId) \ +const char * const IFace##_iid = IId; \ +Q_DECLARE_INTERFACE(IFace, IId) \ +template <> inline IFace *qt_extension(QAbstractExtensionManager *manager, QObject *object) \ +{ QObject *extension = manager->extension(object, Q_TYPEID(IFace)); return extension ? static_cast(extension->qt_metacast(IFace##_iid)) : static_cast(0); } + +#endif + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // EXTENSION_H diff --git a/src/designer/src/lib/extension/extension.pri b/src/designer/src/lib/extension/extension.pri new file mode 100644 index 000000000..d8ef658f2 --- /dev/null +++ b/src/designer/src/lib/extension/extension.pri @@ -0,0 +1,12 @@ +# Input + +INCLUDEPATH += $$PWD + +HEADERS += $$PWD/default_extensionfactory.h \ + $$PWD/extension.h \ + $$PWD/qextensionmanager.h + +SOURCES += $$PWD/default_extensionfactory.cpp \ + $$PWD/extension.cpp \ + $$PWD/qextensionmanager.cpp + diff --git a/src/designer/src/lib/extension/extension_global.h b/src/designer/src/lib/extension/extension_global.h new file mode 100644 index 000000000..25545bb21 --- /dev/null +++ b/src/designer/src/lib/extension/extension_global.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef EXTENSION_GLOBAL_H +#define EXTENSION_GLOBAL_H + +#include + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +#define QDESIGNER_EXTENSION_EXTERN Q_DECL_EXPORT +#define QDESIGNER_EXTENSION_IMPORT Q_DECL_IMPORT + +#ifdef QT_DESIGNER_STATIC +# define QDESIGNER_EXTENSION_EXPORT +#elif defined(QDESIGNER_EXTENSION_LIBRARY) +# define QDESIGNER_EXTENSION_EXPORT QDESIGNER_EXTENSION_EXTERN +#else +# define QDESIGNER_EXTENSION_EXPORT QDESIGNER_EXTENSION_IMPORT +#endif + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // EXTENSION_GLOBAL_H diff --git a/src/designer/src/lib/extension/qextensionmanager.cpp b/src/designer/src/lib/extension/qextensionmanager.cpp new file mode 100644 index 000000000..960ae25ed --- /dev/null +++ b/src/designer/src/lib/extension/qextensionmanager.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qextensionmanager.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QExtensionManager + + \brief The QExtensionManager class provides extension management + facilities for Qt Designer. + + \inmodule QtDesigner + + In \QD the extensions are not created until they are required. For + that reason, when implementing an extension, you must also create + a QExtensionFactory, i.e a class that is able to make an instance + of your extension, and register it using \QD's extension manager. + + The registration of an extension factory is typically made in the + QDesignerCustomWidgetInterface::initialize() function: + + \snippet doc/src/snippets/code/tools_designer_src_lib_extension_qextensionmanager.cpp 0 + + The QExtensionManager is not intended to be instantiated + directly. You can retrieve an interface to \QD's extension manager + using the QDesignerFormEditorInterface::extensionManager() + function. A pointer to \QD's current QDesignerFormEditorInterface + object (\c formEditor in the example above) is provided by the + QDesignerCustomWidgetInterface::initialize() function's + parameter. When implementing a custom widget plugin, you must + subclass the QDesignerCustomWidgetInterface to expose your plugin + to \QD. + + Then, when an extension is required, \QD's extension manager will + run through all its registered factories calling + QExtensionFactory::createExtension() for each until the first one + that is able to create the requested extension for the selected + object, is found. This factory will then make an instance of the + extension. + + There are four available types of extensions in \QD: + QDesignerContainerExtension , QDesignerMemberSheetExtension, + QDesignerPropertySheetExtension and + QDesignerTaskMenuExtension. \QD's behavior is the same whether the + requested extension is associated with a container, a member + sheet, a property sheet or a task menu. + + For a complete example using the QExtensionManager class, see the + \l {designer/taskmenuextension}{Task Menu Extension example}. The + example shows how to create a custom widget plugin for Qt + Designer, and how to to use the QDesignerTaskMenuExtension class + to add custom items to \QD's task menu. + + \sa QExtensionFactory, QAbstractExtensionManager +*/ + +/*! + Constructs an extension manager with the given \a parent. +*/ +QExtensionManager::QExtensionManager(QObject *parent) + : QObject(parent) +{ +} + + +/*! + Destroys the extension manager +*/ +QExtensionManager::~QExtensionManager() +{ +} + +/*! + Register the extension specified by the given \a factory and + extension identifier \a iid. +*/ +void QExtensionManager::registerExtensions(QAbstractExtensionFactory *factory, const QString &iid) +{ + if (iid.isEmpty()) { + m_globalExtension.prepend(factory); + return; + } + + FactoryMap::iterator it = m_extensions.find(iid); + if (it == m_extensions.end()) + it = m_extensions.insert(iid, FactoryList()); + + it.value().prepend(factory); +} + +/*! + Unregister the extension specified by the given \a factory and + extension identifier \a iid. +*/ +void QExtensionManager::unregisterExtensions(QAbstractExtensionFactory *factory, const QString &iid) +{ + if (iid.isEmpty()) { + m_globalExtension.removeAll(factory); + return; + } + + const FactoryMap::iterator it = m_extensions.find(iid); + if (it == m_extensions.end()) + return; + + FactoryList &factories = it.value(); + factories.removeAll(factory); + + if (factories.isEmpty()) + m_extensions.erase(it); +} + +/*! + Returns the extension specified by \a iid, for the given \a + object. +*/ +QObject *QExtensionManager::extension(QObject *object, const QString &iid) const +{ + const FactoryMap::const_iterator it = m_extensions.constFind(iid); + if (it != m_extensions.constEnd()) { + const FactoryList::const_iterator fcend = it.value().constEnd(); + for (FactoryList::const_iterator fit = it.value().constBegin(); fit != fcend; ++fit) + if (QObject *ext = (*fit)->extension(object, iid)) + return ext; + } + const FactoryList::const_iterator gfcend = m_globalExtension.constEnd(); + for (FactoryList::const_iterator git = m_globalExtension.constBegin(); git != gfcend; ++git) + if (QObject *ext = (*git)->extension(object, iid)) + return ext; + + return 0; +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/extension/qextensionmanager.h b/src/designer/src/lib/extension/qextensionmanager.h new file mode 100644 index 000000000..a387924e6 --- /dev/null +++ b/src/designer/src/lib/extension/qextensionmanager.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEXTENSIONMANAGER_H +#define QEXTENSIONMANAGER_H + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QObject; // Fool syncqt + +class QDESIGNER_EXTENSION_EXPORT QExtensionManager: public QObject, public QAbstractExtensionManager +{ + Q_OBJECT + Q_INTERFACES(QAbstractExtensionManager) +public: + QExtensionManager(QObject *parent = 0); + ~QExtensionManager(); + + virtual void registerExtensions(QAbstractExtensionFactory *factory, const QString &iid = QString()); + virtual void unregisterExtensions(QAbstractExtensionFactory *factory, const QString &iid = QString()); + + virtual QObject *extension(QObject *object, const QString &iid) const; + +private: + typedef QList FactoryList; + typedef QHash FactoryMap; + FactoryMap m_extensions; + FactoryList m_globalExtension; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QEXTENSIONMANAGER_H diff --git a/src/designer/src/lib/lib.pro b/src/designer/src/lib/lib.pro new file mode 100644 index 000000000..3ba6f5235 --- /dev/null +++ b/src/designer/src/lib/lib.pro @@ -0,0 +1,78 @@ +TEMPLATE=lib +TARGET=QtDesigner +QT += xml +contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols +CONFIG += qt +win32|mac: CONFIG += debug_and_release +DESTDIR = ../../../../lib +!wince*:DLLDESTDIR = ../../../../bin + +isEmpty(QT_MAJOR_VERSION) { + VERSION=4.3.0 +} else { + VERSION=$${QT_MAJOR_VERSION}.$${QT_MINOR_VERSION}.$${QT_PATCH_VERSION} +} + +unix|win32-g++*:QMAKE_PKGCONFIG_REQUIRES += QtXml + +include(../../../../src/qt_targets.pri) +QMAKE_TARGET_PRODUCT = Designer +QMAKE_TARGET_DESCRIPTION = Graphical user interface designer. + +!contains(CONFIG, static) { + CONFIG += dll + + DEFINES += \ + QDESIGNER_SDK_LIBRARY \ + QDESIGNER_EXTENSION_LIBRARY \ + QDESIGNER_UILIB_LIBRARY \ + QDESIGNER_SHARED_LIBRARY +} else { + DEFINES += QT_DESIGNER_STATIC +} + +#load up the headers info +CONFIG += qt_install_headers +HEADERS_PRI = $$QT_BUILD_TREE/include/QtDesigner/headers.pri +include($$HEADERS_PRI, "", true)|clear(HEADERS_PRI) + +#mac frameworks +mac:CONFIG += explicitlib +mac:!static:contains(QT_CONFIG, qt_framework) { + QMAKE_FRAMEWORK_BUNDLE_NAME = $$TARGET + CONFIG += lib_bundle qt_no_framework_direct_includes qt_framework + CONFIG(debug, debug|release) { + !build_pass:CONFIG += build_all + } else { #release + !debug_and_release|build_pass { + CONFIG -= qt_install_headers #no need to install these as well + FRAMEWORK_HEADERS.version = Versions + FRAMEWORK_HEADERS.files = $$SYNCQT.HEADER_FILES $$SYNCQT.HEADER_CLASSES + FRAMEWORK_HEADERS.path = Headers + } + QMAKE_BUNDLE_DATA += FRAMEWORK_HEADERS + } +} + +include(extension/extension.pri) +include(sdk/sdk.pri) +include(uilib/uilib.pri) +include(shared/shared.pri) +PRECOMPILED_HEADER=lib_pch.h + +include(../sharedcomponents.pri) +include(../components/component.pri) + +target.path=$$[QT_INSTALL_LIBS] +INSTALLS += target +win32 { + dlltarget.path=$$[QT_INSTALL_BINS] + INSTALLS += dlltarget +} + + +qt_install_headers { + designer_headers.files = $$SYNCQT.HEADER_FILES $$SYNCQT.HEADER_CLASSES + designer_headers.path = $$[QT_INSTALL_HEADERS]/QtDesigner + INSTALLS += designer_headers +} diff --git a/src/designer/src/lib/lib_pch.h b/src/designer/src/lib/lib_pch.h new file mode 100644 index 000000000..17c3d8cd6 --- /dev/null +++ b/src/designer/src/lib/lib_pch.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifdef __cplusplus +#include "shared_global_p.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qdesigner_widget_p.h" +#include +#include +#include +#include +#include "layout_p.h" +#endif diff --git a/src/designer/src/lib/sdk/abstractactioneditor.cpp b/src/designer/src/lib/sdk/abstractactioneditor.cpp new file mode 100644 index 000000000..f0a7b76a7 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractactioneditor.cpp @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractactioneditor.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QDesignerActionEditorInterface + + \brief The QDesignerActionEditorInterface class allows you to + change the focus of Qt Designer's action editor. + + \inmodule QtDesigner + + The QDesignerActionEditorInterface class is not intended to be + instantiated directly. You can retrieve an interface to \QD's + action editor using the + QDesignerFormEditorInterface::actionEditor() function. + + You can control which actions that are available in the action + editor's window using the manageAction() and unmanageAction() + functions. An action that is managed by \QD is available in the + action editor while an unmanaged action is ignored. + + QDesignerActionEditorInterface also provides the core() function + that you can use to retrieve a pointer to \QD's current + QDesignerFormEditorInterface object, and the setFormWindow() + function that enables you to change the currently selected form + window. + + \sa QDesignerFormEditorInterface, QDesignerFormWindowInterface +*/ + +/*! + Constructs an action editor interface with the given \a parent and + the specified window \a flags. +*/ +QDesignerActionEditorInterface::QDesignerActionEditorInterface(QWidget *parent, Qt::WindowFlags flags) + : QWidget(parent, flags) +{ +} + +/*! + Destroys the action editor interface. +*/ +QDesignerActionEditorInterface::~QDesignerActionEditorInterface() +{ +} + +/*! + Returns a pointer to \QD's current QDesignerFormEditorInterface + object. +*/ +QDesignerFormEditorInterface *QDesignerActionEditorInterface::core() const +{ + return 0; +} + +/*! + \fn void QDesignerActionEditorInterface::setFormWindow(QDesignerFormWindowInterface *formWindow) + + Sets the currently selected form window to \a formWindow. + +*/ + +/*! + \fn void QDesignerActionEditorInterface::manageAction(QAction *action) + + Instructs \QD to manage the specified \a action. An action that is + managed by \QD is available in the action editor. + + \sa unmanageAction() +*/ + +/*! + \fn void QDesignerActionEditorInterface::unmanageAction(QAction *action) + + Instructs \QD to ignore the specified \a action. An unmanaged + action is not available in the action editor. + + \sa manageAction() +*/ + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/abstractactioneditor.h b/src/designer/src/lib/sdk/abstractactioneditor.h new file mode 100644 index 000000000..2d4241c23 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractactioneditor.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABSTRACTACTIONEDITOR_H +#define ABSTRACTACTIONEDITOR_H + +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; + +class QDESIGNER_SDK_EXPORT QDesignerActionEditorInterface: public QWidget +{ + Q_OBJECT +public: + QDesignerActionEditorInterface(QWidget *parent, Qt::WindowFlags flags = 0); + virtual ~QDesignerActionEditorInterface(); + + virtual QDesignerFormEditorInterface *core() const; + + virtual void manageAction(QAction *action) = 0; + virtual void unmanageAction(QAction *action) = 0; + +public Q_SLOTS: + virtual void setFormWindow(QDesignerFormWindowInterface *formWindow) = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ABSTRACTACTIONEDITOR_H diff --git a/src/designer/src/lib/sdk/abstractbrushmanager.h b/src/designer/src/lib/sdk/abstractbrushmanager.h new file mode 100644 index 000000000..87b1bf2c0 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractbrushmanager.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABSTRACTBRUSHMANAGER_H +#define ABSTRACTBRUSHMANAGER_H + +#include + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QObject; + +class QDESIGNER_SDK_EXPORT QDesignerBrushManagerInterface : public QObject +{ + Q_OBJECT +public: + QDesignerBrushManagerInterface(QObject *parentObject = 0) : QObject(parentObject) {} + + virtual QBrush brush(const QString &name) const = 0; + virtual QMap brushes() const = 0; + virtual QString currentBrush() const = 0; + + virtual QString addBrush(const QString &name, const QBrush &brush) = 0; + virtual void removeBrush(const QString &name) = 0; + virtual void setCurrentBrush(const QString &name) = 0; + + virtual QPixmap brushPixmap(const QBrush &brush) const = 0; +Q_SIGNALS: + void brushAdded(const QString &name, const QBrush &brush); + void brushRemoved(const QString &name); + void currentBrushChanged(const QString &name, const QBrush &brush); + +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/designer/src/lib/sdk/abstractdialoggui.cpp b/src/designer/src/lib/sdk/abstractdialoggui.cpp new file mode 100644 index 000000000..353f1eae6 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractdialoggui.cpp @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractdialoggui_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QDesignerDialogGuiInterface + \since 4.4 + \internal + + \brief The QDesignerDialogGuiInterface allows integrations of \QD to replace the + message boxes displayed by \QD by custom dialogs. + + \inmodule QtDesigner + + QDesignerDialogGuiInterface provides virtual functions that can be overwritten + to display message boxes and file dialogs. + \sa QMessageBox, QFileDialog +*/ + +/*! + \enum QDesignerDialogGuiInterface::Message + + This enum specifies the context from within the message box is called. + + \value FormLoadFailureMessage Loading of a form failed + \value UiVersionMismatchMessage Attempt to load a file created with an old version of Designer + \value ResourceLoadFailureMessage Resources specified in a file could not be found + \value TopLevelSpacerMessage Spacer items detected on a container without layout + \value PropertyEditorMessage Messages of the propert yeditor + \value SignalSlotEditorMessage Messages of the signal / slot editor + \value FormEditorMessage Messages of the form editor + \value PreviewFailureMessage A preview could not be created + \value PromotionErrorMessage Messages related to promotion of a widget + \value ResourceEditorMessage Messages of the resource editor + \value ScriptDialogMessage Messages of the script dialog + \value SignalSlotDialogMessage Messages of the signal slot dialog + \value OtherMessage Unspecified context +*/ + +/*! + Constructs a QDesignerDialogGuiInterface object. +*/ + +QDesignerDialogGuiInterface::QDesignerDialogGuiInterface() +{ +} + +/*! + Destroys the QDesignerDialogGuiInterface object. +*/ +QDesignerDialogGuiInterface::~QDesignerDialogGuiInterface() +{ +} + +/*! + \fn QMessageBox::StandardButton QDesignerDialogGuiInterface::message(QWidget *parent, Message context, QMessageBox::Icon icon, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) + + Opens a message box as child of \a parent within the context \a context, using \a icon, \a title, \a text, \a buttons and \a defaultButton + and returns the button chosen by the user. +*/ + +/*! + \fn QString QDesignerDialogGuiInterface::getExistingDirectory(QWidget *parent, const QString &caption, const QString &dir, QFileDialog::Options options) + + Opens a file dialog as child of \a parent using the parameters \a caption, \a dir and \a options that prompts the + user for an existing directory. Returns a directory selected by the user. +*/ + +/*! + \fn QString QDesignerDialogGuiInterface::getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options) + + Opens a file dialog as child of \a parent using the parameters \a caption, \a dir, \a filter, \a selectedFilter and \a options + that prompts the user for an existing file. Returns a file selected by the user. +*/ + +/*! + \fn QStringList QDesignerDialogGuiInterface::getOpenFileNames(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options) + + Opens a file dialog as child of \a parent using the parameters \a caption, \a dir, \a filter, \a selectedFilter and \a options + that prompts the user for a set of existing files. Returns one or more existing files selected by the user. +*/ + +/*! + Opens a file dialog with image browsing capabilities as child of \a parent using the parameters \a caption, \a dir, \a filter, \a selectedFilter and \a options + that prompts the user for an existing file. Returns a file selected by the user. + + The default implementation simply calls getOpenFileName(). On platforms that do not support an image preview in the QFileDialog, + the function can be reimplemented to provide an image browser. + + \since 4.5 +*/ + +QString QDesignerDialogGuiInterface::getOpenImageFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options) +{ + return getOpenFileName(parent, caption, dir, filter, selectedFilter, options); +} + +/*! + Opens a file dialog with image browsing capabilities as child of \a parent using the parameters \a caption, \a dir, \a filter, \a selectedFilter and \a options + that prompts the user for a set of existing files. Returns one or more existing files selected by the user. + + The default implementation simply calls getOpenFileNames(). On platforms that do not support an image preview in the QFileDialog, + the function can be reimplemented to provide an image browser. + + \since 4.5 +*/ + +QStringList QDesignerDialogGuiInterface::getOpenImageFileNames(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options) +{ + return getOpenImageFileNames(parent, caption, dir, filter, selectedFilter, options); +} + +/*! + \fn QString QDesignerDialogGuiInterface::getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options) + + Opens a file dialog as child of \a parent using the parameters \a caption, \a dir, \a filter, \a selectedFilter and \a options + that prompts the user for a file. Returns a file selected by the user. The file does not have to exist. +*/ + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/abstractdialoggui_p.h b/src/designer/src/lib/sdk/abstractdialoggui_p.h new file mode 100644 index 000000000..af3843850 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractdialoggui_p.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef ABSTRACTDIALOGGUI_H +#define ABSTRACTDIALOGGUI_H + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QWidget; + +class QDESIGNER_SDK_EXPORT QDesignerDialogGuiInterface +{ + Q_DISABLE_COPY(QDesignerDialogGuiInterface) +public: + QDesignerDialogGuiInterface(); + virtual ~QDesignerDialogGuiInterface(); + + enum Message { FormLoadFailureMessage, UiVersionMismatchMessage, ResourceLoadFailureMessage, + TopLevelSpacerMessage, PropertyEditorMessage, SignalSlotEditorMessage, FormEditorMessage, + PreviewFailureMessage, PromotionErrorMessage, ResourceEditorMessage, + ScriptDialogMessage, SignalSlotDialogMessage, OtherMessage, FileChangedMessage }; + + virtual QMessageBox::StandardButton + message(QWidget *parent, Message context, QMessageBox::Icon icon, + const QString &title, const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton defaultButton = QMessageBox::NoButton) = 0; + + virtual QMessageBox::StandardButton + message(QWidget *parent, Message context, QMessageBox::Icon icon, + const QString &title, const QString &text, const QString &informativeText, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton defaultButton = QMessageBox::NoButton) = 0; + + virtual QMessageBox::StandardButton + message(QWidget *parent, Message context, QMessageBox::Icon icon, + const QString &title, const QString &text, const QString &informativeText, const QString &detailedText, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton defaultButton = QMessageBox::NoButton) = 0; + + virtual QString getExistingDirectory(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), QFileDialog::Options options = QFileDialog::ShowDirsOnly)= 0; + virtual QString getOpenFileName(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0)= 0; + virtual QString getOpenImageFileName(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0); + virtual QStringList getOpenFileNames(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0)= 0; + virtual QStringList getOpenImageFileNames(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0); + virtual QString getSaveFileName(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0)= 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ABSTRACTDIALOGGUI_H diff --git a/src/designer/src/lib/sdk/abstractdnditem.h b/src/designer/src/lib/sdk/abstractdnditem.h new file mode 100644 index 000000000..229938d75 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractdnditem.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABSTRACTDNDITEM_H +#define ABSTRACTDNDITEM_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DomUI; +class QWidget; +class QPoint; + +class QDESIGNER_SDK_EXPORT QDesignerDnDItemInterface +{ +public: + enum DropType { MoveDrop, CopyDrop }; + + QDesignerDnDItemInterface() {} + virtual ~QDesignerDnDItemInterface() {} + + virtual DomUI *domUi() const = 0; + virtual QWidget *widget() const = 0; + virtual QWidget *decoration() const = 0; + virtual QPoint hotSpot() const = 0; + virtual DropType type() const = 0; + virtual QWidget *source() const = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ABSTRACTDNDITEM_H diff --git a/src/designer/src/lib/sdk/abstractdnditem.qdoc b/src/designer/src/lib/sdk/abstractdnditem.qdoc new file mode 100644 index 000000000..958ee2865 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractdnditem.qdoc @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QDesignerDnDItemInterface + \brief The QDesignerDnDItemInterface class provides an interface that is used to manage items + during a drag and drop operation. + \inmodule QtDesigner + \internal +*/ + +/*! + \enum QDesignerDnDItemInterface::DropType + + This enum describes the result of a drag and drop operation. + + \value MoveDrop The item was moved. + \value CopyDrop The item was copied. +*/ + +/*! + \fn QDesignerDnDItemInterface::QDesignerDnDItemInterface() + + Constructs a new interface to a drag and drop item. +*/ + +/*! + \fn QDesignerDnDItemInterface::~QDesignerDnDItemInterface() + + Destroys the interface to the item. +*/ + +/*! + \fn DomUI *QDesignerDnDItemInterface::domUi() const + + Returns a user interface object for the item. +*/ + +/*! + \fn QWidget *QDesignerDnDItemInterface::widget() const + + Returns the widget being copied or moved in the drag and drop operation. + + \sa source() +*/ + +/*! + \fn QWidget *QDesignerDnDItemInterface::decoration() const + + Returns the widget used to represent the item. +*/ + +/*! + \fn QPoint QDesignerDnDItemInterface::hotSpot() const + + Returns the cursor's hotspot. + + \sa QDrag::hotSpot() +*/ + +/*! + \fn DropType QDesignerDnDItemInterface::type() const + + Returns the type of drag and drop operation in progress. +*/ + +/*! + \fn QWidget *QDesignerDnDItemInterface::source() const + + Returns the widget that is the source of the drag and drop operation; i.e. the original + container of the widget being dragged. + + \sa widget() +*/ diff --git a/src/designer/src/lib/sdk/abstractformeditor.cpp b/src/designer/src/lib/sdk/abstractformeditor.cpp new file mode 100644 index 000000000..563781631 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractformeditor.cpp @@ -0,0 +1,630 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractformeditor.h" +#include "abstractdialoggui_p.h" +#include "abstractintrospection_p.h" +#include "abstractsettings_p.h" +#include "abstractoptionspage_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Must be done outside of the Qt namespace +static void initResources() +{ + Q_INIT_RESOURCE(shared); + Q_INIT_RESOURCE(ClamshellPhone); + Q_INIT_RESOURCE(PortableMedia); + Q_INIT_RESOURCE(S60_nHD_Touchscreen); + Q_INIT_RESOURCE(S60_QVGA_Candybar); + Q_INIT_RESOURCE(SmartPhone2); + Q_INIT_RESOURCE(SmartPhone); + Q_INIT_RESOURCE(SmartPhoneWithButtons); + Q_INIT_RESOURCE(TouchscreenPhone); +} + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterfacePrivate { +public: + QDesignerFormEditorInterfacePrivate(); + ~QDesignerFormEditorInterfacePrivate(); + + + QPointer m_topLevel; + QPointer m_widgetBox; + QPointer m_propertyEditor; + QPointer m_formWindowManager; + QPointer m_extensionManager; + QPointer m_metaDataBase; + QPointer m_widgetDataBase; + QPointer m_widgetFactory; + QPointer m_objectInspector; + QPointer m_brushManager; + QPointer m_integration; + QPointer m_iconCache; + QPointer m_actionEditor; + QDesignerSettingsInterface *m_settingsManager; + QDesignerPluginManager *m_pluginManager; + QDesignerPromotionInterface *m_promotion; + QDesignerIntrospectionInterface *m_introspection; + QDesignerDialogGuiInterface *m_dialogGui; + QPointer m_resourceModel; + QPointer m_gradientManager; // instantiated and deleted by designer_integration + QList m_optionsPages; +}; + +QDesignerFormEditorInterfacePrivate::QDesignerFormEditorInterfacePrivate() : + m_settingsManager(0), + m_pluginManager(0), + m_promotion(0), + m_introspection(0), + m_dialogGui(0), + m_resourceModel(0), + m_gradientManager(0) +{ +} + +QDesignerFormEditorInterfacePrivate::~QDesignerFormEditorInterfacePrivate() +{ + delete m_settingsManager; + delete m_formWindowManager; + delete m_promotion; + delete m_introspection; + delete m_dialogGui; + delete m_resourceModel; + qDeleteAll(m_optionsPages); +} + +/*! + \class QDesignerFormEditorInterface + + \brief The QDesignerFormEditorInterface class allows you to access + Qt Designer's various components. + + \inmodule QtDesigner + + \QD's current QDesignerFormEditorInterface object holds + information about all \QD's components: The action editor, the + object inspector, the property editor, the widget box, and the + extension and form window managers. QDesignerFormEditorInterface + contains a collection of functions that provides interfaces to all + these components. They are typically used to query (and + manipulate) the respective component. For example: + + \snippet doc/src/snippets/code/tools_designer_src_lib_sdk_abstractformeditor.cpp 0 + + QDesignerFormEditorInterface is not intended to be instantiated + directly. A pointer to \QD's current QDesignerFormEditorInterface + object (\c formEditor in the example above) is provided by the + QDesignerCustomWidgetInterface::initialize() function's + parameter. When implementing a custom widget plugin, you must + subclass the QDesignerCustomWidgetInterface to expose your plugin + to \QD. + + QDesignerFormEditorInterface also provides functions that can set + the action editor, property editor, object inspector and widget + box. These are only useful if you want to provide your own custom + components. + + If designer is embedded in another program, one could to provide its + own settings manager. The manager is used by the components of \QD + to store/retrieve persistent configuration settings. The default + manager uses QSettings as the backend. + + Finally, QDesignerFormEditorInterface provides the topLevel() + function that returns \QD's top-level widget. + + \sa QDesignerCustomWidgetInterface +*/ + +/*! + Constructs a QDesignerFormEditorInterface object with the given \a + parent. +*/ + +QDesignerFormEditorInterface::QDesignerFormEditorInterface(QObject *parent) + : QObject(parent), + d(new QDesignerFormEditorInterfacePrivate()) +{ + initResources(); +} + +/*! + Destroys the QDesignerFormEditorInterface object. +*/ +QDesignerFormEditorInterface::~QDesignerFormEditorInterface() +{ + delete d; +} + +/*! + Returns an interface to \QD's widget box. + + \sa setWidgetBox() +*/ +QDesignerWidgetBoxInterface *QDesignerFormEditorInterface::widgetBox() const +{ + return d->m_widgetBox; +} + +/*! + Sets \QD's widget box to be the specified \a widgetBox. + + \sa widgetBox() +*/ +void QDesignerFormEditorInterface::setWidgetBox(QDesignerWidgetBoxInterface *widgetBox) +{ + d->m_widgetBox = widgetBox; +} + +/*! + Returns an interface to \QD's property editor. + + \sa setPropertyEditor() +*/ +QDesignerPropertyEditorInterface *QDesignerFormEditorInterface::propertyEditor() const +{ + return d->m_propertyEditor; +} + +/*! + Sets \QD's property editor to be the specified \a propertyEditor. + + \sa propertyEditor() +*/ +void QDesignerFormEditorInterface::setPropertyEditor(QDesignerPropertyEditorInterface *propertyEditor) +{ + d->m_propertyEditor = propertyEditor; +} + +/*! + Returns an interface to \QD's action editor. + + \sa setActionEditor() +*/ +QDesignerActionEditorInterface *QDesignerFormEditorInterface::actionEditor() const +{ + return d->m_actionEditor; +} + +/*! + Sets \QD's action editor to be the specified \a actionEditor. + + \sa actionEditor() +*/ +void QDesignerFormEditorInterface::setActionEditor(QDesignerActionEditorInterface *actionEditor) +{ + d->m_actionEditor = actionEditor; +} + +/*! + Returns \QD's top-level widget. +*/ +QWidget *QDesignerFormEditorInterface::topLevel() const +{ + return d->m_topLevel; +} + +/*! + \internal +*/ +void QDesignerFormEditorInterface::setTopLevel(QWidget *topLevel) +{ + d->m_topLevel = topLevel; +} + +/*! + Returns an interface to \QD's form window manager. +*/ +QDesignerFormWindowManagerInterface *QDesignerFormEditorInterface::formWindowManager() const +{ + return d->m_formWindowManager; +} + +/*! + \internal +*/ +void QDesignerFormEditorInterface::setFormManager(QDesignerFormWindowManagerInterface *formWindowManager) +{ + d->m_formWindowManager = formWindowManager; +} + +/*! + Returns an interface to \QD's extension manager. +*/ +QExtensionManager *QDesignerFormEditorInterface::extensionManager() const +{ + return d->m_extensionManager; +} + +/*! + \internal +*/ +void QDesignerFormEditorInterface::setExtensionManager(QExtensionManager *extensionManager) +{ + d->m_extensionManager = extensionManager; +} + +/*! + \internal + + Returns an interface to the meta database used by the form editor. +*/ +QDesignerMetaDataBaseInterface *QDesignerFormEditorInterface::metaDataBase() const +{ + return d->m_metaDataBase; +} + +/*! + \internal +*/ +void QDesignerFormEditorInterface::setMetaDataBase(QDesignerMetaDataBaseInterface *metaDataBase) +{ + d->m_metaDataBase = metaDataBase; +} + +/*! + \internal + + Returns an interface to the widget database used by the form editor. +*/ +QDesignerWidgetDataBaseInterface *QDesignerFormEditorInterface::widgetDataBase() const +{ + return d->m_widgetDataBase; +} + +/*! + \internal +*/ +void QDesignerFormEditorInterface::setWidgetDataBase(QDesignerWidgetDataBaseInterface *widgetDataBase) +{ + d->m_widgetDataBase = widgetDataBase; +} + +/*! + \internal + + Returns an interface to the designer promotion handler. +*/ + +QDesignerPromotionInterface *QDesignerFormEditorInterface::promotion() const +{ + return d->m_promotion; +} + +/*! + \internal + + Sets the designer promotion handler. +*/ + +void QDesignerFormEditorInterface::setPromotion(QDesignerPromotionInterface *promotion) +{ + if (d->m_promotion) + delete d->m_promotion; + d->m_promotion = promotion; +} + +/*! + \internal + + Returns an interface to the widget factory used by the form editor + to create widgets for the form. +*/ +QDesignerWidgetFactoryInterface *QDesignerFormEditorInterface::widgetFactory() const +{ + return d->m_widgetFactory; +} + +/*! + \internal +*/ +void QDesignerFormEditorInterface::setWidgetFactory(QDesignerWidgetFactoryInterface *widgetFactory) +{ + d->m_widgetFactory = widgetFactory; +} + +/*! + Returns an interface to \QD's object inspector. +*/ +QDesignerObjectInspectorInterface *QDesignerFormEditorInterface::objectInspector() const +{ + return d->m_objectInspector; +} + +/*! + Sets \QD's object inspector to be the specified \a + objectInspector. + + \sa objectInspector() +*/ +void QDesignerFormEditorInterface::setObjectInspector(QDesignerObjectInspectorInterface *objectInspector) +{ + d->m_objectInspector = objectInspector; +} + +/*! + \internal + + Returns an interface to the brush manager used by the palette editor. +*/ +QDesignerBrushManagerInterface *QDesignerFormEditorInterface::brushManager() const +{ + return d->m_brushManager; +} + +/*! + \internal +*/ +void QDesignerFormEditorInterface::setBrushManager(QDesignerBrushManagerInterface *brushManager) +{ + d->m_brushManager = brushManager; +} + +/*! + \internal + + Returns an interface to the integration. +*/ +QDesignerIntegrationInterface *QDesignerFormEditorInterface::integration() const +{ + return d->m_integration; +} + +/*! + \internal +*/ +void QDesignerFormEditorInterface::setIntegration(QDesignerIntegrationInterface *integration) +{ + d->m_integration = integration; +} + +/*! + \internal + + Returns an interface to the icon cache used by the form editor to + manage icons. +*/ +QDesignerIconCacheInterface *QDesignerFormEditorInterface::iconCache() const +{ + return d->m_iconCache; +} + +/*! + \internal +*/ +void QDesignerFormEditorInterface::setIconCache(QDesignerIconCacheInterface *cache) +{ + d->m_iconCache = cache; +} + +/*! + \internal + \since 4.5 + Returns the list of options pages that allow the user to configure \QD components. +*/ +QList QDesignerFormEditorInterface::optionsPages() const +{ + return d->m_optionsPages; +} + +/*! + \internal + \since 4.5 + Sets the list of options pages that allow the user to configure \QD components. +*/ +void QDesignerFormEditorInterface::setOptionsPages(const QList &optionsPages) +{ + d->m_optionsPages = optionsPages; +} + + +/*! + \internal + + Returns the plugin manager used by the form editor. +*/ +QDesignerPluginManager *QDesignerFormEditorInterface::pluginManager() const +{ + return d->m_pluginManager; +} + +/*! + \internal + + Sets the plugin manager used by the form editor to the specified + \a pluginManager. +*/ +void QDesignerFormEditorInterface::setPluginManager(QDesignerPluginManager *pluginManager) +{ + d->m_pluginManager = pluginManager; +} + +/*! + \internal + \since 4.4 + Returns the resource model used by the form editor. +*/ +QtResourceModel *QDesignerFormEditorInterface::resourceModel() const +{ + return d->m_resourceModel; +} + +/*! + \internal + + Sets the resource model used by the form editor to the specified + \a resourceModel. +*/ +void QDesignerFormEditorInterface::setResourceModel(QtResourceModel *resourceModel) +{ + d->m_resourceModel = resourceModel; +} + +/*! + \internal + \since 4.4 + Returns the gradient manager used by the style sheet editor. +*/ +QtGradientManager *QDesignerFormEditorInterface::gradientManager() const +{ + return d->m_gradientManager; +} + +/*! + \internal + + Sets the gradient manager used by the style sheet editor to the specified + \a gradientManager. +*/ +void QDesignerFormEditorInterface::setGradientManager(QtGradientManager *gradientManager) +{ + d->m_gradientManager = gradientManager; +} + +/*! + \internal + \since 4.5 + Returns the settings manager used by the components to store persistent settings. +*/ +QDesignerSettingsInterface *QDesignerFormEditorInterface::settingsManager() const +{ + return d->m_settingsManager; +} + +/*! + \internal + \since 4.5 + Sets the settings manager used to store/retrieve the persistent settings of the components. +*/ +void QDesignerFormEditorInterface::setSettingsManager(QDesignerSettingsInterface *settingsManager) +{ + if (d->m_settingsManager) + delete d->m_settingsManager; + d->m_settingsManager = settingsManager; + + // This is a (hopefully) safe place to perform settings-dependent + // initializations. + const qdesigner_internal::QDesignerSharedSettings settings(this); + qdesigner_internal::FormWindowBase::setDefaultDesignerGrid(settings.defaultGrid()); +} + +/*! + \internal + \since 4.4 + Returns the introspection used by the form editor. +*/ +QDesignerIntrospectionInterface *QDesignerFormEditorInterface::introspection() const +{ + return d->m_introspection; +} + +/*! + \internal + \since 4.4 + + Sets the introspection used by the form editor to the specified \a introspection. +*/ +void QDesignerFormEditorInterface::setIntrospection(QDesignerIntrospectionInterface *introspection) +{ + if (d->m_introspection) + delete d->m_introspection; + d->m_introspection = introspection; +} + +/*! + \internal + + Returns the path to the resources used by the form editor. +*/ +QString QDesignerFormEditorInterface::resourceLocation() const +{ +#ifdef Q_WS_MAC + return QLatin1String(":/trolltech/formeditor/images/mac"); +#else + return QLatin1String(":/trolltech/formeditor/images/win"); +#endif +} + +/*! + \internal + + Returns the dialog GUI used by the form editor. +*/ + +QDesignerDialogGuiInterface *QDesignerFormEditorInterface::dialogGui() const +{ + return d->m_dialogGui; +} + +/*! + \internal + + Sets the dialog GUI used by the form editor to the specified \a dialogGui. +*/ + +void QDesignerFormEditorInterface::setDialogGui(QDesignerDialogGuiInterface *dialogGui) +{ + delete d->m_dialogGui; + d->m_dialogGui = dialogGui; +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/abstractformeditor.h b/src/designer/src/lib/sdk/abstractformeditor.h new file mode 100644 index 000000000..fd83ee55d --- /dev/null +++ b/src/designer/src/lib/sdk/abstractformeditor.h @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABSTRACTFORMEDITOR_H +#define ABSTRACTFORMEDITOR_H + +#include + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QDesignerWidgetBoxInterface; +class QDesignerPropertyEditorInterface; +class QDesignerFormWindowManagerInterface; +class QDesignerWidgetDataBaseInterface; +class QDesignerMetaDataBaseInterface; +class QDesignerWidgetFactoryInterface; +class QDesignerObjectInspectorInterface; +class QDesignerPromotionInterface; +class QDesignerBrushManagerInterface; +class QDesignerIconCacheInterface; +class QDesignerActionEditorInterface; +class QDesignerIntegrationInterface; +class QDesignerPluginManager; +class QDesignerIntrospectionInterface; +class QDesignerDialogGuiInterface; +class QDesignerSettingsInterface; +class QDesignerOptionsPageInterface; +class QtResourceModel; +class QtGradientManager; + +class QWidget; + +class QExtensionManager; + +class QDesignerFormEditorInterfacePrivate; + +class QDESIGNER_SDK_EXPORT QDesignerFormEditorInterface : public QObject +{ + Q_OBJECT +public: + QDesignerFormEditorInterface(QObject *parent = 0); + virtual ~QDesignerFormEditorInterface(); + + QExtensionManager *extensionManager() const; + + QWidget *topLevel() const; + QDesignerWidgetBoxInterface *widgetBox() const; + QDesignerPropertyEditorInterface *propertyEditor() const; + QDesignerObjectInspectorInterface *objectInspector() const; + QDesignerFormWindowManagerInterface *formWindowManager() const; + QDesignerWidgetDataBaseInterface *widgetDataBase() const; + QDesignerMetaDataBaseInterface *metaDataBase() const; + QDesignerPromotionInterface *promotion() const; + QDesignerWidgetFactoryInterface *widgetFactory() const; + QDesignerBrushManagerInterface *brushManager() const; + QDesignerIconCacheInterface *iconCache() const; + QDesignerActionEditorInterface *actionEditor() const; + QDesignerIntegrationInterface *integration() const; + QDesignerPluginManager *pluginManager() const; + QDesignerIntrospectionInterface *introspection() const; + QDesignerDialogGuiInterface *dialogGui() const; + QDesignerSettingsInterface *settingsManager() const; + QString resourceLocation() const; + QtResourceModel *resourceModel() const; + QtGradientManager *gradientManager() const; + QList optionsPages() const; + + void setTopLevel(QWidget *topLevel); + void setWidgetBox(QDesignerWidgetBoxInterface *widgetBox); + void setPropertyEditor(QDesignerPropertyEditorInterface *propertyEditor); + void setObjectInspector(QDesignerObjectInspectorInterface *objectInspector); + void setPluginManager(QDesignerPluginManager *pluginManager); + void setActionEditor(QDesignerActionEditorInterface *actionEditor); + void setIntegration(QDesignerIntegrationInterface *integration); + void setIntrospection(QDesignerIntrospectionInterface *introspection); + void setDialogGui(QDesignerDialogGuiInterface *dialogGui); + void setSettingsManager(QDesignerSettingsInterface *settingsManager); + void setResourceModel(QtResourceModel *model); + void setGradientManager(QtGradientManager *manager); + void setOptionsPages(const QList &optionsPages); + +protected: + void setFormManager(QDesignerFormWindowManagerInterface *formWindowManager); + void setMetaDataBase(QDesignerMetaDataBaseInterface *metaDataBase); + void setWidgetDataBase(QDesignerWidgetDataBaseInterface *widgetDataBase); + void setPromotion(QDesignerPromotionInterface *promotion); + void setWidgetFactory(QDesignerWidgetFactoryInterface *widgetFactory); + void setExtensionManager(QExtensionManager *extensionManager); + void setBrushManager(QDesignerBrushManagerInterface *brushManager); + void setIconCache(QDesignerIconCacheInterface *cache); + +private: + QPointer m_pad1; + QPointer m_pad2; + QPointer m_pad3; + QPointer m_pad4; + QPointer m_pad5; + QPointer m_pad6; + QPointer m_pad7; + QPointer m_pad8; + QPointer m_pad9; + QPointer m_pad10; + QPointer m_pad11; + QPointer m_pad12; + QDesignerFormEditorInterfacePrivate *d; + +private: + QDesignerFormEditorInterface(const QDesignerFormEditorInterface &other); + void operator = (const QDesignerFormEditorInterface &other); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ABSTRACTFORMEDITOR_H diff --git a/src/designer/src/lib/sdk/abstractformeditorplugin.cpp b/src/designer/src/lib/sdk/abstractformeditorplugin.cpp new file mode 100644 index 000000000..cb7fd8ee9 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractformeditorplugin.cpp @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +QT_BEGIN_NAMESPACE + +/*! + \internal + \class QDesignerFormEditorPluginInterface + \brief The QDesignerFormEditorPluginInterface class provides an interface that is used to + manage plugins for Qt Designer's form editor component. + \inmodule QtDesigner + + \sa QDesignerFormEditorInterface +*/ + +/*! + \fn virtual QDesignerFormEditorPluginInterface::~QDesignerFormEditorPluginInterface() + + Destroys the plugin interface. +*/ + +/*! + \fn virtual bool QDesignerFormEditorPluginInterface::isInitialized() const = 0 + + Returns true if the plugin interface is initialized; otherwise returns false. +*/ + +/*! + \fn virtual void QDesignerFormEditorPluginInterface::initialize(QDesignerFormEditorInterface *core) = 0 + + Initializes the plugin interface for the specified \a core interface. +*/ + +/*! + \fn virtual QAction *QDesignerFormEditorPluginInterface::action() const = 0 + + Returns the action associated with this interface. +*/ + +/*! + \fn virtual QDesignerFormEditorInterface *QDesignerFormEditorPluginInterface::core() const = 0 + + Returns the core form editor interface associated with this component. +*/ + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/abstractformeditorplugin.h b/src/designer/src/lib/sdk/abstractformeditorplugin.h new file mode 100644 index 000000000..a9e01e81a --- /dev/null +++ b/src/designer/src/lib/sdk/abstractformeditorplugin.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABSTRACTFORMEDITORPLUGIN_H +#define ABSTRACTFORMEDITORPLUGIN_H + +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QAction; + +class QDESIGNER_SDK_EXPORT QDesignerFormEditorPluginInterface +{ +public: + virtual ~QDesignerFormEditorPluginInterface() {} + + virtual bool isInitialized() const = 0; + virtual void initialize(QDesignerFormEditorInterface *core) = 0; + virtual QAction *action() const = 0; + + virtual QDesignerFormEditorInterface *core() const = 0; +}; +Q_DECLARE_INTERFACE(QDesignerFormEditorPluginInterface, "com.trolltech.Qt.Designer.QDesignerFormEditorPluginInterface") + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ABSTRACTFORMEDITORPLUGIN_H diff --git a/src/designer/src/lib/sdk/abstractformwindow.cpp b/src/designer/src/lib/sdk/abstractformwindow.cpp new file mode 100644 index 000000000..7ea450627 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractformwindow.cpp @@ -0,0 +1,814 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractformwindow.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QDesignerFormWindowInterface + + \brief The QDesignerFormWindowInterface class allows you to query + and manipulate form windows appearing in Qt Designer's workspace. + + \inmodule QtDesigner + + QDesignerFormWindowInterface provides information about + the associated form window as well as allowing its properties to be + altered. The interface is not intended to be instantiated + directly, but to provide access to \QD's current form windows + controlled by \QD's \l {QDesignerFormWindowManagerInterface}{form + window manager}. + + If you are looking for the form window containing a specific + widget, you can use the static + QDesignerFormWindowInterface::findFormWindow() function: + + \snippet doc/src/snippets/code/tools_designer_src_lib_sdk_abstractformwindow.cpp 0 + + But in addition, you can access any of the current form windows + through \QD's form window manager: Use the + QDesignerFormEditorInterface::formWindowManager() function to + retrieve an interface to the manager. Once you have this + interface, you have access to all of \QD's current form windows + through the QDesignerFormWindowManagerInterface::formWindow() + function. For example: + + \snippet doc/src/snippets/code/tools_designer_src_lib_sdk_abstractformwindow.cpp 1 + + The pointer to \QD's current QDesignerFormEditorInterface object + (\c formEditor in the example above) is provided by the + QDesignerCustomWidgetInterface::initialize() function's + parameter. When implementing a custom widget plugin, you must + subclass the QDesignerCustomWidgetInterface class to expose your + plugin to \QD. + + Once you have the form window, you can query its properties. For + example, a plain custom widget plugin is managed by \QD only at + its top level, i.e. none of its child widgets can be resized in + \QD's workspace. But QDesignerFormWindowInterface provides you + with functions that enables you to control whether a widget should + be managed by \QD, or not: + + \snippet doc/src/snippets/code/tools_designer_src_lib_sdk_abstractformwindow.cpp 2 + + The complete list of functions concerning widget management is: + isManaged(), manageWidget() and unmanageWidget(). There is also + several associated signals: widgetManaged(), widgetRemoved(), + aboutToUnmanageWidget() and widgetUnmanaged(). + + In addition to controlling the management of widgets, you can + control the current selection in the form window using the + selectWidget(), clearSelection() and emitSelectionChanged() + functions, and the selectionChanged() signal. + + You can also retrieve information about where the form is stored + using absoluteDir(), its include files using includeHints(), and + its layout and pixmap functions using layoutDefault(), + layoutFunction() and pixmapFunction(). You can find out whether + the form window has been modified (but not saved) or not, using + the isDirty() function. You can retrieve its author(), its + contents(), its fileName(), associated comment() and + exportMacro(), its mainContainer(), its features(), its grid() and + its resourceFiles(). + + The interface provides you with functions and slots allowing you + to alter most of this information as well. The exception is the + directory storing the form window. Finally, there is several + signals associated with changes to the information mentioned above + and to the form window in general. + + \sa QDesignerFormWindowCursorInterface, + QDesignerFormEditorInterface, QDesignerFormWindowManagerInterface +*/ + +/*! + \enum QDesignerFormWindowInterface::FeatureFlag + + This enum describes the features that are available and can be + controlled by the form window interface. These values are used + when querying the form window to determine which features it + supports: + + \value EditFeature Form editing + \value GridFeature Grid display and snap-to-grid facilities for editing + \value TabOrderFeature Tab order management + \value DefaultFeature Support for default features (form editing and grid) + + \sa hasFeature(), features() +*/ + +/*! + Constructs a form window interface with the given \a parent and + the specified window \a flags. +*/ +QDesignerFormWindowInterface::QDesignerFormWindowInterface(QWidget *parent, Qt::WindowFlags flags) + : QWidget(parent, flags) +{ +} + +/*! + Destroys the form window interface. +*/ +QDesignerFormWindowInterface::~QDesignerFormWindowInterface() +{ +} + +/*! + Returns a pointer to \QD's current QDesignerFormEditorInterface + object. +*/ +QDesignerFormEditorInterface *QDesignerFormWindowInterface::core() const +{ + return 0; +} + +/*! + \fn QDesignerFormWindowInterface *QDesignerFormWindowInterface::findFormWindow(QWidget *widget) + + Returns the form window interface for the given \a widget. +*/ + +static inline bool stopFindAtTopLevel(const QObject *w, bool stopAtMenu) +{ + // Do we need to go beyond top levels when looking for the form window? + // 1) A dialog has a window attribute at the moment it is created + // before it is properly embedded into a form window. The property + // sheet queries the layout attributes precisely at this moment. + // 2) In the case of floating docks and toolbars, we also need to go beyond the top level window. + // 3) In the case of menu editing, we don't want to block events from the + // Designer menu, so, we say stop. + // Note that there must be no false positives for dialogs parented on + // the form (for example, the "change object name" dialog), else, its + // events will be blocked. + + if (stopAtMenu && w->inherits("QDesignerMenu")) + return true; + return !qdesigner_internal::WidgetFactory::isFormEditorObject(w); +} + +QDesignerFormWindowInterface *QDesignerFormWindowInterface::findFormWindow(QWidget *w) +{ + while (w != 0) { + if (QDesignerFormWindowInterface *fw = qobject_cast(w)) { + return fw; + } else { + if (w->isWindow() && stopFindAtTopLevel(w, true)) + break; + } + + w = w->parentWidget(); + } + + return 0; +} + +/*! + \fn QDesignerFormWindowInterface *QDesignerFormWindowInterface::findFormWindow(QObject *object) + + Returns the form window interface for the given \a object. + + \since 4.4 +*/ + +QDesignerFormWindowInterface *QDesignerFormWindowInterface::findFormWindow(QObject *object) +{ + while (object != 0) { + if (QDesignerFormWindowInterface *fw = qobject_cast(object)) { + return fw; + } else { + QWidget *w = qobject_cast(object); + // QDesignerMenu is a window, so stopFindAtTopLevel(w) returns 0. + // However, we want to find the form window for QActions of a menu. + // If this check is inside stopFindAtTopLevel(w), it will break designer + // menu editing (e.g. when clicking on items inside an opened menu) + if (w && w->isWindow() && stopFindAtTopLevel(w, false)) + break; + + } + + object = object->parent(); + } + + return 0; +} + +/*! + \fn virtual QString QDesignerFormWindowInterface::fileName() const + + Returns the file name of the UI file that describes the form + currently being shown. + + \sa setFileName() +*/ + +/*! + \fn virtual QDir QDesignerFormWindowInterface::absoluteDir() const + + Returns the absolute location of the directory containing the form + shown in the form window. +*/ + +/*! + \fn virtual QString QDesignerFormWindowInterface::contents() const + + Returns details of the contents of the form currently being + displayed in the window. +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::setContents(QIODevice *device) + + Sets the form's contents using data obtained from the given \a device. + + Data can be read from QFile objects or any other subclass of QIODevice. +*/ + +/*! + \fn virtual Feature QDesignerFormWindowInterface::features() const + + Returns a combination of the features provided by the form window + associated with the interface. The value returned can be tested + against the \l Feature enum values to determine which features are + supported by the window. + + \sa setFeatures(), hasFeature() +*/ + +/*! + \fn virtual bool QDesignerFormWindowInterface::hasFeature(Feature feature) const + + Returns true if the form window offers the specified \a feature; + otherwise returns false. + + \sa features() +*/ + +/*! + \fn virtual QString QDesignerFormWindowInterface::author() const + + Returns details of the author or creator of the form currently + being displayed in the window. +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::setAuthor(const QString &author) + + Sets the details for the author or creator of the form to the \a + author specified. +*/ + +/*! + \fn virtual QString QDesignerFormWindowInterface::comment() const + + Returns comments about the form currently being displayed in the window. +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::setComment(const QString &comment) + + Sets the information about the form to the \a comment + specified. This information should be a human-readable comment + about the form. +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::layoutDefault(int *margin, int *spacing) + + Fills in the default margin and spacing for the form's default + layout in the \a margin and \a spacing variables specified. +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::setLayoutDefault(int margin, int spacing) + + Sets the default \a margin and \a spacing for the form's layout. + + \sa layoutDefault() +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::layoutFunction(QString *margin, QString *spacing) + + Fills in the current margin and spacing for the form's layout in + the \a margin and \a spacing variables specified. +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::setLayoutFunction(const QString &margin, const QString &spacing) + + Sets the \a margin and \a spacing for the form's layout. + + The default layout properties will be replaced by the + corresponding layout functions when \c uic generates code for the + form, that is, if the functions are specified. This is useful when + different environments requires different layouts for the same + form. + + \sa layoutFunction() +*/ + +/*! + \fn virtual QString QDesignerFormWindowInterface::pixmapFunction() const + + Returns the name of the function used to load pixmaps into the + form window. + + \sa setPixmapFunction() +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::setPixmapFunction(const QString &pixmapFunction) + + Sets the function used to load pixmaps into the form window + to the given \a pixmapFunction. + + \sa pixmapFunction() +*/ + +/*! + \fn virtual QString QDesignerFormWindowInterface::exportMacro() const + + Returns the export macro associated with the form currently being + displayed in the window. The export macro is used when the form + is compiled to create a widget plugin. + + \sa {Creating Custom Widgets for Qt Designer} +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::setExportMacro(const QString &exportMacro) + + Sets the form window's export macro to \a exportMacro. The export + macro is used when building a widget plugin to export the form's + interface to other components. +*/ + +/*! + \fn virtual QStringList QDesignerFormWindowInterface::includeHints() const + + Returns a list of the header files that will be included in the + form window's associated UI file. + + Header files may be local, i.e. relative to the project's + directory, \c "mywidget.h", or global, i.e. part of Qt or the + compilers standard libraries: \c . + + \sa setIncludeHints() +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::setIncludeHints(const QStringList &includeHints) + + Sets the header files that will be included in the form window's + associated UI file to the specified \a includeHints. + + Header files may be local, i.e. relative to the project's + directory, \c "mywidget.h", or global, i.e. part of Qt or the + compilers standard libraries: \c . + + \sa includeHints() +*/ + +/*! + \fn virtual QDesignerFormWindowCursorInterface *QDesignerFormWindowInterface::cursor() const + + Returns the cursor interface used by the form window. +*/ + +/*! + \fn virtual int QDesignerFormWindowInterface::toolCount() const + + Returns the number of tools available. + + \internal +*/ + +/*! + \fn virtual int QDesignerFormWindowInterface::currentTool() const + + Returns the index of the current tool in use. + + \sa setCurrentTool() + + \internal +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::setCurrentTool(int index) + + Sets the current tool to be the one with the given \a index. + + \sa currentTool() + + \internal +*/ + +/*! + \fn virtual QDesignerFormWindowToolInterface *QDesignerFormWindowInterface::tool(int index) const + + Returns an interface to the tool with the given \a index. + + \internal +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::registerTool(QDesignerFormWindowToolInterface *tool) + + Registers the given \a tool with the form window. + + \internal +*/ + +/*! + \fn virtual QPoint QDesignerFormWindowInterface::grid() const = 0 + + Returns the grid spacing used by the form window. + + \sa setGrid() +*/ + +/*! + \fn virtual QWidget *QDesignerFormWindowInterface::mainContainer() const + + Returns the main container widget for the form window. + + \sa setMainContainer() +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::setMainContainer(QWidget *mainContainer) + + Sets the main container widget on the form to the specified \a + mainContainer. + + \sa mainContainer(), mainContainerChanged() +*/ + +/*! + \fn virtual bool QDesignerFormWindowInterface::isManaged(QWidget *widget) const + + Returns true if the specified \a widget is managed by the form + window; otherwise returns false. + + \sa manageWidget() +*/ + +/*! + \fn virtual bool QDesignerFormWindowInterface::isDirty() const + + Returns true if the form window is "dirty" (modified but not + saved); otherwise returns false. + + \sa setDirty() +*/ + +/*! + \fn virtual QUndoStack *QDesignerFormWindowInterface::commandHistory() const + + Returns an object that can be used to obtain the commands used so + far in the construction of the form. + + \internal +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::beginCommand(const QString &description) + + Begins execution of a command with the given \a + description. Commands are executed between beginCommand() and + endCommand() function calls to ensure that they are recorded on + the undo stack. + + \sa endCommand() + + \internal +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::endCommand() + + Ends execution of the current command. + + \sa beginCommand() + + \internal +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::simplifySelection(QList *widgets) const + + Simplifies the selection of widgets specified by \a widgets. + + \sa selectionChanged() + \internal +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::emitSelectionChanged() + + Emits the selectionChanged() signal. + + \sa selectWidget(), clearSelection() +*/ + +/*! + \fn virtual QStringList QDesignerFormWindowInterface::resourceFiles() const + + Returns a list of paths to resource files that are currently being + used by the form window. + + \sa addResourceFile(), removeResourceFile() +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::addResourceFile(const QString &path) + + Adds the resource file at the given \a path to those used by the form. + + \sa resourceFiles(), resourceFilesChanged() +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::removeResourceFile(const QString &path) + + Removes the resource file at the specified \a path from the list + of those used by the form. + + \sa resourceFiles(), resourceFilesChanged() +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::ensureUniqueObjectName(QObject *object) + + Ensures that the specified \a object has a unique name amongst the + other objects on the form. + + \internal +*/ + +// Slots + +/*! + \fn virtual void QDesignerFormWindowInterface::manageWidget(QWidget *widget) + + Instructs the form window to manage the specified \a widget. + + \sa isManaged(), unmanageWidget(), widgetManaged() +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::unmanageWidget(QWidget *widget) + + Instructs the form window not to manage the specified \a widget. + + \sa aboutToUnmanageWidget(), widgetUnmanaged() +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::setFeatures(Feature features) + + Enables the specified \a features for the form window. + + \sa features(), featureChanged() +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::setDirty(bool dirty) + + If \a dirty is true, the form window is marked as dirty, meaning + that it is modified but not saved. If \a dirty is false, the form + window is considered to be unmodified. + + \sa isDirty() +*/ + +/*! +\fn virtual void QDesignerFormWindowInterface::clearSelection(bool update) + + Clears the current selection in the form window. If \a update is + true, the emitSelectionChanged() function is called, emitting the + selectionChanged() signal. + + \sa selectWidget() +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::selectWidget(QWidget *widget, bool select) + + If \a select is true, the given \a widget is selected; otherwise + the \a widget is deselected. + + \sa clearSelection(), selectionChanged() +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::setGrid(const QPoint &grid) + + Sets the grid size for the form window to the point specified by + \a grid. In this function, the coordinates in the QPoint are used + to specify the dimensions of a rectangle in the grid. + + \sa grid() +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::setFileName(const QString &fileName) + + Sets the file name for the form to the given \a fileName. + + \sa fileName(), fileNameChanged() +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::setContents(const QString &contents) + + Sets the contents of the form using data read from the specified + \a contents string. + + \sa contents() +*/ + +/*! + \fn virtual void QDesignerFormWindowInterface::editWidgets() + + Switches the form window into editing mode. + + \sa \l {Qt Designer's Form Editing Mode} + + \internal +*/ + +// Signals + +/*! + \fn void QDesignerFormWindowInterface::mainContainerChanged(QWidget *mainContainer) + + This signal is emitted whenever the main container changes. + The new container is specified by \a mainContainer. + + \sa setMainContainer() +*/ + +/*! + \fn void QDesignerFormWindowInterface::toolChanged(int toolIndex) + + This signal is emitted whenever the current tool changes. + The specified \a toolIndex is the index of the new tool in the list of + tools in the widget box. + + \internal +*/ + +/*! + \fn void QDesignerFormWindowInterface::fileNameChanged(const QString &fileName) + + This signal is emitted whenever the file name of the form changes. + The new file name is specified by \a fileName. + + \sa setFileName() +*/ + +/*! + \fn void QDesignerFormWindowInterface::featureChanged(Feature feature) + + This signal is emitted whenever a feature changes in the form. + The new feature is specified by \a feature. + + \sa setFeatures() +*/ + +/*! + \fn void QDesignerFormWindowInterface::selectionChanged() + + This signal is emitted whenever the selection in the form changes. + + \sa selectWidget(), clearSelection() +*/ + +/*! + \fn void QDesignerFormWindowInterface::geometryChanged() + + This signal is emitted whenever the form's geometry changes. +*/ + +/*! + \fn void QDesignerFormWindowInterface::resourceFilesChanged() + + This signal is emitted whenever the list of resource files used by the + form changes. + + \sa resourceFiles() +*/ + +/*! + \fn void QDesignerFormWindowInterface::widgetManaged(QWidget *widget) + + This signal is emitted whenever a widget on the form becomes managed. + The newly managed widget is specified by \a widget. + + \sa manageWidget() +*/ + +/*! + \fn void QDesignerFormWindowInterface::widgetUnmanaged(QWidget *widget) + + This signal is emitted whenever a widget on the form becomes unmanaged. + The newly released widget is specified by \a widget. + + \sa unmanageWidget(), aboutToUnmanageWidget() +*/ + +/*! + \fn void QDesignerFormWindowInterface::aboutToUnmanageWidget(QWidget *widget) + + This signal is emitted whenever a widget on the form is about to + become unmanaged. When this signal is emitted, the specified \a + widget is still managed, and a widgetUnmanaged() signal will + follow, indicating when it is no longer managed. + + \sa unmanageWidget(), isManaged() +*/ + +/*! + \fn void QDesignerFormWindowInterface::activated(QWidget *widget) + + This signal is emitted whenever a widget is activated on the form. + The activated widget is specified by \a widget. +*/ + +/*! + \fn void QDesignerFormWindowInterface::changed() + + This signal is emitted whenever a form is changed. +*/ + +/*! + \fn void QDesignerFormWindowInterface::widgetRemoved(QWidget *widget) + + This signal is emitted whenever a widget is removed from the form. + The widget that was removed is specified by \a widget. +*/ + +/*! + \fn void QDesignerFormWindowInterface::objectRemoved(QObject *object) + + This signal is emitted whenever an object (such as + an action or a QButtonGroup) is removed from the form. + The object that was removed is specified by \a object. + + \since 4.5 +*/ + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/abstractformwindow.h b/src/designer/src/lib/sdk/abstractformwindow.h new file mode 100644 index 000000000..36ce4a54c --- /dev/null +++ b/src/designer/src/lib/sdk/abstractformwindow.h @@ -0,0 +1,183 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABSTRACTFORMWINDOW_H +#define ABSTRACTFORMWINDOW_H + +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerFormWindowCursorInterface; +class QDesignerFormWindowToolInterface; +class DomUI; +class QUndoStack; +class QDir; + +class QDESIGNER_SDK_EXPORT QDesignerFormWindowInterface: public QWidget +{ + Q_OBJECT +public: + enum FeatureFlag + { + EditFeature = 0x01, + GridFeature = 0x02, + TabOrderFeature = 0x04, + DefaultFeature = EditFeature | GridFeature + }; + Q_DECLARE_FLAGS(Feature, FeatureFlag) + +public: + QDesignerFormWindowInterface(QWidget *parent = 0, Qt::WindowFlags flags = 0); + virtual ~QDesignerFormWindowInterface(); + + virtual QString fileName() const = 0; + virtual QDir absoluteDir() const = 0; + + virtual QString contents() const = 0; + virtual void setContents(QIODevice *dev) = 0; + + virtual Feature features() const = 0; + virtual bool hasFeature(Feature f) const = 0; + + virtual QString author() const = 0; + virtual void setAuthor(const QString &author) = 0; + + virtual QString comment() const = 0; + virtual void setComment(const QString &comment) = 0; + + virtual void layoutDefault(int *margin, int *spacing) = 0; + virtual void setLayoutDefault(int margin, int spacing) = 0; + + virtual void layoutFunction(QString *margin, QString *spacing) = 0; + virtual void setLayoutFunction(const QString &margin, const QString &spacing) = 0; + + virtual QString pixmapFunction() const = 0; + virtual void setPixmapFunction(const QString &pixmapFunction) = 0; + + virtual QString exportMacro() const = 0; + virtual void setExportMacro(const QString &exportMacro) = 0; + + virtual QStringList includeHints() const = 0; + virtual void setIncludeHints(const QStringList &includeHints) = 0; + + virtual QDesignerFormEditorInterface *core() const; + virtual QDesignerFormWindowCursorInterface *cursor() const = 0; + + virtual int toolCount() const = 0; + + virtual int currentTool() const = 0; + virtual void setCurrentTool(int index) = 0; + + virtual QDesignerFormWindowToolInterface *tool(int index) const = 0; + virtual void registerTool(QDesignerFormWindowToolInterface *tool) = 0; + + virtual QPoint grid() const = 0; + + virtual QWidget *mainContainer() const = 0; + virtual void setMainContainer(QWidget *mainContainer) = 0; + + virtual bool isManaged(QWidget *widget) const = 0; + + virtual bool isDirty() const = 0; + + static QDesignerFormWindowInterface *findFormWindow(QWidget *w); + static QDesignerFormWindowInterface *findFormWindow(QObject *obj); + + virtual QUndoStack *commandHistory() const = 0; + virtual void beginCommand(const QString &description) = 0; + virtual void endCommand() = 0; + + virtual void simplifySelection(QList *widgets) const = 0; + + // notifications + virtual void emitSelectionChanged() = 0; + + virtual QStringList resourceFiles() const = 0; + virtual void addResourceFile(const QString &path) = 0; + virtual void removeResourceFile(const QString &path) = 0; + + virtual void ensureUniqueObjectName(QObject *object) = 0; + +public Q_SLOTS: + virtual void manageWidget(QWidget *widget) = 0; + virtual void unmanageWidget(QWidget *widget) = 0; + + virtual void setFeatures(Feature f) = 0; + virtual void setDirty(bool dirty) = 0; + virtual void clearSelection(bool changePropertyDisplay = true) = 0; + virtual void selectWidget(QWidget *w, bool select = true) = 0; + virtual void setGrid(const QPoint &grid) = 0; + virtual void setFileName(const QString &fileName) = 0; + virtual void setContents(const QString &contents) = 0; + + virtual void editWidgets() = 0; + +Q_SIGNALS: + void mainContainerChanged(QWidget *mainContainer); + void toolChanged(int toolIndex); + void fileNameChanged(const QString &fileName); + void featureChanged(Feature f); + void selectionChanged(); + void geometryChanged(); + + void resourceFilesChanged(); + + void widgetManaged(QWidget *widget); + void widgetUnmanaged(QWidget *widget); + void aboutToUnmanageWidget(QWidget *widget); + void activated(QWidget *widget); + + void changed(); + void widgetRemoved(QWidget *w); + void objectRemoved(QObject *o); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ABSTRACTFORMWINDOW_H diff --git a/src/designer/src/lib/sdk/abstractformwindowcursor.cpp b/src/designer/src/lib/sdk/abstractformwindowcursor.cpp new file mode 100644 index 000000000..c2611931e --- /dev/null +++ b/src/designer/src/lib/sdk/abstractformwindowcursor.cpp @@ -0,0 +1,252 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractformwindowcursor.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QDesignerFormWindowCursorInterface + + \brief The QDesignerFormWindowCursorInterface class allows you to + query and modify a form window's widget selection, and in addition + modify the properties of all the form's widgets. + + \inmodule QtDesigner + + QDesignerFormWindowCursorInterface is a convenience class that + provides an interface to the associated form window's text cursor; + it provides a collection of functions that enables you to query a + given form window's selection and change the selection's focus + according to defined modes (MoveMode) and movements + (MoveOperation). You can also use the interface to query the + form's widgets and change their properties. + + The interface is not intended to be instantiated directly, but to + provide access to the selections and widgets of \QD's current form + windows. QDesignerFormWindowInterface always provides an + associated cursor interface. The form window for a given widget + can be retrieved using the static + QDesignerFormWindowInterface::findFormWindow() functions. For + example: + + \snippet doc/src/snippets/code/tools_designer_src_lib_sdk_abstractformwindowcursor.cpp 0 + + You can retrieve any of \QD's current form windows through + \QD's \l {QDesignerFormWindowManagerInterface}{form window + manager}. + + Once you have a form window's cursor interface, you can check if + the form window has a selection at all using the hasSelection() + function. You can query the form window for its total + widgetCount() and selectedWidgetCount(). You can retrieve the + currently selected widget (or widgets) using the current() or + selectedWidget() functions. + + You can retrieve any of the form window's widgets using the + widget() function, and check if a widget is selected using the + isWidgetSelected() function. You can use the setProperty() + function to set the selected widget's properties, and the + setWidgetProperty() or resetWidgetProperty() functions to modify + the properties of any given widget. + + Finally, you can change the selection by changing the text + cursor's position() using the setPosition() and movePosition() + functions. + + \sa QDesignerFormWindowInterface, QDesignerFormWindowManagerInterface +*/ + +/*! + \enum QDesignerFormWindowCursorInterface::MoveOperation + + This enum describes the types of text cursor operation that can occur in a form window. + + \value NoMove The cursor does not move. + \value Start Moves the cursor to the start of the focus chain. + \value End Moves the cursor to the end of the focus chain. + \value Next Moves the cursor to the next widget in the focus chain. + \value Prev Moves the cursor to the previous widget in the focus chain. + \value Left The cursor moves to the left. + \value Right The cursor moves to the right. + \value Up The cursor moves upwards. + \value Down The cursor moves downwards. +*/ + +/*! + \enum QDesignerFormWindowCursorInterface::MoveMode + + This enum describes the different modes that are used when the text cursor moves. + + \value MoveAnchor The anchor moves with the cursor to its new location. + \value KeepAnchor The anchor remains at the cursor's old location. +*/ + +/*! + Returns true if the specified \a widget is selected; otherwise + returns false. +*/ +bool QDesignerFormWindowCursorInterface::isWidgetSelected(QWidget *widget) const +{ + for (int index=0; index + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QWidget; +class QVariant; +class QString; + +class QDESIGNER_SDK_EXPORT QDesignerFormWindowCursorInterface +{ +public: + enum MoveOperation + { + NoMove, + + Start, + End, + Next, + Prev, + Left, + Right, + Up, + Down + }; + + enum MoveMode + { + MoveAnchor, + KeepAnchor + }; + +public: + virtual ~QDesignerFormWindowCursorInterface() {} + + virtual QDesignerFormWindowInterface *formWindow() const = 0; + + virtual bool movePosition(MoveOperation op, MoveMode mode = MoveAnchor) = 0; + + virtual int position() const = 0; + virtual void setPosition(int pos, MoveMode mode = MoveAnchor) = 0; + + virtual QWidget *current() const = 0; + + virtual int widgetCount() const = 0; + virtual QWidget *widget(int index) const = 0; + + virtual bool hasSelection() const = 0; + virtual int selectedWidgetCount() const = 0; + virtual QWidget *selectedWidget(int index) const = 0; + + virtual void setProperty(const QString &name, const QVariant &value) = 0; + virtual void setWidgetProperty(QWidget *widget, const QString &name, const QVariant &value) = 0; + virtual void resetWidgetProperty(QWidget *widget, const QString &name) = 0; + + bool isWidgetSelected(QWidget *widget) const; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ABSTRACTFORMWINDOWCURSOR_H diff --git a/src/designer/src/lib/sdk/abstractformwindowmanager.cpp b/src/designer/src/lib/sdk/abstractformwindowmanager.cpp new file mode 100644 index 000000000..75c1d4a11 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractformwindowmanager.cpp @@ -0,0 +1,502 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractformwindowmanager.h" + +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QDesignerFormWindowManagerInterface + + \brief The QDesignerFormWindowManagerInterface class allows you to + manipulate the collection of form windows in Qt Designer, and + control Qt Designer's form editing actions. + + \inmodule QtDesigner + + QDesignerFormWindowManagerInterface is not intended to be + instantiated directly. \QD uses the form window manager to + control the various form windows in its workspace. You can + retrieve an interface to \QD's form window manager using + the QDesignerFormEditorInterface::formWindowManager() + function. For example: + + \snippet doc/src/snippets/code/tools_designer_src_lib_sdk_abstractformwindowmanager.cpp 0 + + When implementing a custom widget plugin, a pointer to \QD's + current QDesignerFormEditorInterface object (\c formEditor in the + example above) is provided by the + QDesignerCustomWidgetInterface::initialize() function's parameter. + You must subclass the QDesignerCustomWidgetInterface to expose + your plugin to Qt Designer. + + The form window manager interface provides the createFormWindow() + function that enables you to create a new form window which you + can add to the collection of form windows that the manager + maintains, using the addFormWindow() slot. It also provides the + formWindowCount() function returning the number of form windows + currently under the manager's control, the formWindow() function + returning the form window associated with a given index, and the + activeFormWindow() function returning the currently selected form + window. The removeFormWindow() slot allows you to reduce the + number of form windows the manager must maintain, and the + setActiveFormWindow() slot allows you to change the form window + focus in \QD's workspace. + + In addition, QDesignerFormWindowManagerInterface contains a + collection of functions that enables you to intervene and control + \QD's form editing actions. All these functions return the + original action, making it possible to propagate the function + further after intervention. + + Finally, the interface provides three signals which are emitted + when a form window is added, when the currently selected form + window changes, or when a form window is removed, respectively. All + the signals carry the form window in question as their parameter. + + \sa QDesignerFormEditorInterface, QDesignerFormWindowInterface +*/ + +// ------------- QDesignerFormWindowManagerInterfacePrivate + +struct QDesignerFormWindowManagerInterfacePrivate { + QDesignerFormWindowManagerInterfacePrivate(); + QAction *m_simplifyLayoutAction; + QAction *m_formLayoutAction; +}; + +QDesignerFormWindowManagerInterfacePrivate::QDesignerFormWindowManagerInterfacePrivate() : + m_simplifyLayoutAction(0), + m_formLayoutAction(0) +{ +} + +typedef QMap FormWindowManagerPrivateMap; + +Q_GLOBAL_STATIC(FormWindowManagerPrivateMap, g_FormWindowManagerPrivateMap) + +/*! + Constructs an interface with the given \a parent for the form window + manager. +*/ +QDesignerFormWindowManagerInterface::QDesignerFormWindowManagerInterface(QObject *parent) + : QObject(parent) +{ + g_FormWindowManagerPrivateMap()->insert(this, new QDesignerFormWindowManagerInterfacePrivate); +} + +/*! + Destroys the interface for the form window manager. +*/ +QDesignerFormWindowManagerInterface::~QDesignerFormWindowManagerInterface() +{ + FormWindowManagerPrivateMap *fwmpm = g_FormWindowManagerPrivateMap(); + const FormWindowManagerPrivateMap::iterator it = fwmpm->find(this); + Q_ASSERT(it != fwmpm->end()); + delete it.value(); + fwmpm->erase(it); +} + +/*! + Allows you to intervene and control \QD's "cut" action. The function + returns the original action. + + \sa QAction +*/ +QAction *QDesignerFormWindowManagerInterface::actionCut() const +{ + return 0; +} + +/*! + Allows you to intervene and control \QD's "copy" action. The + function returns the original action. + + \sa QAction +*/ +QAction *QDesignerFormWindowManagerInterface::actionCopy() const +{ + return 0; +} + +/*! + Allows you to intervene and control \QD's "paste" action. The + function returns the original action. + + \sa QAction +*/ +QAction *QDesignerFormWindowManagerInterface::actionPaste() const +{ + return 0; +} + +/*! + Allows you to intervene and control \QD's "delete" action. The function + returns the original action. + + \sa QAction +*/ +QAction *QDesignerFormWindowManagerInterface::actionDelete() const +{ + return 0; +} + +/*! + Allows you to intervene and control \QD's "select all" action. The + function returns the original action. + + \sa QAction +*/ +QAction *QDesignerFormWindowManagerInterface::actionSelectAll() const +{ + return 0; +} + +/*! + Allows you to intervene and control the action of lowering a form + window in \QD's workspace. The function returns the original + action. + + \sa QAction +*/ +QAction *QDesignerFormWindowManagerInterface::actionLower() const +{ + return 0; +} + +/*! + Allows you to intervene and control the action of raising of a + form window in \QD's workspace. The function returns the original + action. + + \sa QAction +*/ +QAction *QDesignerFormWindowManagerInterface::actionRaise() const +{ + return 0; +} + +/*! + Allows you to intervene and control a request for horizontal + layout for a form window in \QD's workspace. The function returns + the original action. + + \sa QAction +*/ +QAction *QDesignerFormWindowManagerInterface::actionHorizontalLayout() const +{ + return 0; +} + +/*! + Allows you to intervene and control a request for vertical layout + for a form window in \QD's workspace. The function returns the + original action. + + \sa QAction +*/ +QAction *QDesignerFormWindowManagerInterface::actionVerticalLayout() const +{ + return 0; +} + +/*! + Allows you to intervene and control \QD's "split horizontal" + action. The function returns the original action. + + \sa QAction +*/ +QAction *QDesignerFormWindowManagerInterface::actionSplitHorizontal() const +{ + return 0; +} + +/*! + Allows you to intervene and control \QD's "split vertical" + action. The function returns the original action. + + \sa QAction +*/ +QAction *QDesignerFormWindowManagerInterface::actionSplitVertical() const +{ + return 0; +} + +/*! + Allows you to intervene and control a request for grid layout for + a form window in \QD's workspace. The function returns the + original action. + + \sa QAction +*/ +QAction *QDesignerFormWindowManagerInterface::actionGridLayout() const +{ + return 0; +} + +/*! + Allows you to intervene and control \QD's "form layout" action. The + function returns the original action. + +FormWindowManagerPrivateMap *fwmpm = g_FormWindowManagerPrivateMap(); \sa QAction + \since 4.4 +*/ + +QAction *QDesignerFormWindowManagerInterface::actionFormLayout() const +{ + const QDesignerFormWindowManagerInterfacePrivate *d = g_FormWindowManagerPrivateMap()->value(this); + Q_ASSERT(d); + return d->m_formLayoutAction; +} + +/*! + Sets the "form layout" action to \a action. + + \internal + \since 4.4 +*/ + +void QDesignerFormWindowManagerInterface::setActionFormLayout(QAction *action) +{ + QDesignerFormWindowManagerInterfacePrivate *d = g_FormWindowManagerPrivateMap()->value(this); + Q_ASSERT(d); + d->m_formLayoutAction = action; +} + +/*! + Allows you to intervene and control \QD's "break layout" action. The + function returns the original action. + + \sa QAction +*/ +QAction *QDesignerFormWindowManagerInterface::actionBreakLayout() const +{ + return 0; +} + +/*! + Allows you to intervene and control \QD's "adjust size" action. The + function returns the original action. + + \sa QAction +*/ +QAction *QDesignerFormWindowManagerInterface::actionAdjustSize() const +{ + return 0; +} + +/*! + Allows you to intervene and control \QD's "simplify layout" action. The + function returns the original action. + + \sa QAction + \since 4.4 +*/ + +QAction *QDesignerFormWindowManagerInterface::actionSimplifyLayout() const +{ + const QDesignerFormWindowManagerInterfacePrivate *d = g_FormWindowManagerPrivateMap()->value(this); + Q_ASSERT(d); + return d->m_simplifyLayoutAction; +} + +/*! + Sets the "simplify layout" action to \a action. + + \internal + \since 4.4 +*/ + +void QDesignerFormWindowManagerInterface::setActionSimplifyLayout(QAction *action) +{ + QDesignerFormWindowManagerInterfacePrivate *d = g_FormWindowManagerPrivateMap()->value(this); + Q_ASSERT(d); + d->m_simplifyLayoutAction = action; +} + +/*! + Returns the currently active form window in \QD's workspace. + + \sa setActiveFormWindow(), removeFormWindow() +*/ +QDesignerFormWindowInterface *QDesignerFormWindowManagerInterface::activeFormWindow() const +{ + return 0; +} + +/*! + Returns a pointer to \QD's current QDesignerFormEditorInterface + object. +*/ +QDesignerFormEditorInterface *QDesignerFormWindowManagerInterface::core() const +{ + return 0; +} + +/*! + Adds the given \a formWindow to the collection of windows that + \QD's form window manager maintains. + + \sa formWindowAdded() +*/ +void QDesignerFormWindowManagerInterface::addFormWindow(QDesignerFormWindowInterface *formWindow) +{ + Q_UNUSED(formWindow); +} + +/*! + Removes the given \a formWindow from the collection of windows that + \QD's form window manager maintains. + + \sa formWindow(), formWindowRemoved() +*/ +void QDesignerFormWindowManagerInterface::removeFormWindow(QDesignerFormWindowInterface *formWindow) +{ + Q_UNUSED(formWindow); +} + +/*! + Sets the given \a formWindow to be the currently active form window in + \QD's workspace. + + \sa activeFormWindow(), activeFormWindowChanged() +*/ +void QDesignerFormWindowManagerInterface::setActiveFormWindow(QDesignerFormWindowInterface *formWindow) +{ + Q_UNUSED(formWindow); +} + +/*! + Returns the number of form windows maintained by \QD's form window + manager. +*/ +int QDesignerFormWindowManagerInterface::formWindowCount() const +{ + return 0; +} + +/*! + Returns the form window at the given \a index. + + \sa setActiveFormWindow(), removeFormWindow() +*/ +QDesignerFormWindowInterface *QDesignerFormWindowManagerInterface::formWindow(int index) const +{ + Q_UNUSED(index); + return 0; +} + +/*! + \fn QDesignerFormWindowInterface *QDesignerFormWindowManagerInterface::createFormWindow(QWidget *parent, Qt::WindowFlags flags) + + Creates a form window with the given \a parent and the given window + \a flags. + + \sa addFormWindow() +*/ +QDesignerFormWindowInterface *QDesignerFormWindowManagerInterface::createFormWindow(QWidget *parentWidget, Qt::WindowFlags flags) +{ + Q_UNUSED(parentWidget); + Q_UNUSED(flags); + return 0; +} + +/*! + Allows you to intervene and control \QD's "undo" action. The + function returns the original action. + + \sa QAction +*/ +QAction *QDesignerFormWindowManagerInterface::actionUndo() const +{ + return 0; +} + +/*! + Allows you to intervene and control \QD's "redo" action. The + function returns the original action. + + \sa QAction +*/ +QAction *QDesignerFormWindowManagerInterface::actionRedo() const +{ + return 0; +} + +/*! + \fn void QDesignerFormWindowManagerInterface::formWindowAdded(QDesignerFormWindowInterface *formWindow) + + This signal is emitted when a new form window is added to the + collection of windows that \QD's form window manager maintains. A + pointer to the new \a formWindow is passed as an argument. + + \sa addFormWindow(), setActiveFormWindow() +*/ + +/*! + \fn void QDesignerFormWindowManagerInterface::formWindowRemoved(QDesignerFormWindowInterface *formWindow) + + This signal is emitted when a form window is removed from the + collection of windows that \QD's form window manager maintains. A + pointer to the removed \a formWindow is passed as an argument. + + \sa removeFormWindow() +*/ + +/*! + \fn void QDesignerFormWindowManagerInterface::activeFormWindowChanged(QDesignerFormWindowInterface *formWindow) + + This signal is emitted when the contents of the currently active + form window in \QD's workspace changed. A pointer to the currently + active \a formWindow is passed as an argument. + + \sa activeFormWindow() +*/ + +/*! + \fn void QDesignerFormWindowManagerInterface::dragItems(const QList &item_list) + + \internal +*/ + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/abstractformwindowmanager.h b/src/designer/src/lib/sdk/abstractformwindowmanager.h new file mode 100644 index 000000000..bdd7c99aa --- /dev/null +++ b/src/designer/src/lib/sdk/abstractformwindowmanager.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABSTRACTFORMWINDOWMANAGER_H +#define ABSTRACTFORMWINDOWMANAGER_H + +#include +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QAction; +class QActionGroup; +class QDesignerFormEditorInterface; +class DomUI; +class QWidget; +class QDesignerDnDItemInterface; + +class QDESIGNER_SDK_EXPORT QDesignerFormWindowManagerInterface: public QObject +{ + Q_OBJECT +public: + QDesignerFormWindowManagerInterface(QObject *parent = 0); + virtual ~QDesignerFormWindowManagerInterface(); + + virtual QAction *actionCut() const; + virtual QAction *actionCopy() const; + virtual QAction *actionPaste() const; + virtual QAction *actionDelete() const; + virtual QAction *actionSelectAll() const; + virtual QAction *actionLower() const; + virtual QAction *actionRaise() const; + virtual QAction *actionUndo() const; + virtual QAction *actionRedo() const; + + virtual QAction *actionHorizontalLayout() const; + virtual QAction *actionVerticalLayout() const; + virtual QAction *actionSplitHorizontal() const; + virtual QAction *actionSplitVertical() const; + virtual QAction *actionGridLayout() const; + QAction *actionFormLayout() const; + virtual QAction *actionBreakLayout() const; + virtual QAction *actionAdjustSize() const; + QAction *actionSimplifyLayout() const; + + virtual QDesignerFormWindowInterface *activeFormWindow() const; + + virtual int formWindowCount() const; + virtual QDesignerFormWindowInterface *formWindow(int index) const; + + virtual QDesignerFormWindowInterface *createFormWindow(QWidget *parentWidget = 0, Qt::WindowFlags flags = 0); + + virtual QDesignerFormEditorInterface *core() const; + + virtual void dragItems(const QList &item_list) = 0; + +Q_SIGNALS: + void formWindowAdded(QDesignerFormWindowInterface *formWindow); + void formWindowRemoved(QDesignerFormWindowInterface *formWindow); + void activeFormWindowChanged(QDesignerFormWindowInterface *formWindow); + +public Q_SLOTS: + virtual void addFormWindow(QDesignerFormWindowInterface *formWindow); + virtual void removeFormWindow(QDesignerFormWindowInterface *formWindow); + virtual void setActiveFormWindow(QDesignerFormWindowInterface *formWindow); + +protected: + void setActionFormLayout(QAction *action); + void setActionSimplifyLayout(QAction *action); + +private: + QDesignerFormWindowManagerInterface(const QDesignerFormWindowManagerInterface &other); + QDesignerFormWindowManagerInterface &operator = (const QDesignerFormWindowManagerInterface &other); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ABSTRACTFORMWINDOWMANAGER_H diff --git a/src/designer/src/lib/sdk/abstractformwindowtool.cpp b/src/designer/src/lib/sdk/abstractformwindowtool.cpp new file mode 100644 index 000000000..b073b22ea --- /dev/null +++ b/src/designer/src/lib/sdk/abstractformwindowtool.cpp @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractformwindowtool.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QDesignerFormWindowToolInterface + + \brief The QDesignerFormWindowToolInterface class provides an + interface that enables tools to be used on items in a form window. + + \inmodule QtDesigner + + \internal +*/ + +/*! +*/ +QDesignerFormWindowToolInterface::QDesignerFormWindowToolInterface(QObject *parent) + : QObject(parent) +{ +} + +/*! +*/ +QDesignerFormWindowToolInterface::~QDesignerFormWindowToolInterface() +{ +} + +/*! + \fn virtual QDesignerFormEditorInterface *QDesignerFormWindowToolInterface::core() const = 0 +*/ + +/*! + \fn virtual QDesignerFormWindowInterface *QDesignerFormWindowToolInterface::formWindow() const = 0 +*/ + +/*! + \fn virtual QWidget *QDesignerFormWindowToolInterface::editor() const = 0 +*/ + +/*! + \fn virtual QAction *QDesignerFormWindowToolInterface::action() const = 0 +*/ + +/*! + \fn virtual void QDesignerFormWindowToolInterface::activated() = 0 +*/ + +/*! + \fn virtual void QDesignerFormWindowToolInterface::deactivated() = 0 +*/ + +/*! + \fn virtual void QDesignerFormWindowToolInterface::saveToDom(DomUI*, QWidget*) { +*/ + +/*! + \fn virtual void QDesignerFormWindowToolInterface::loadFromDom(DomUI*, QWidget*) { +*/ + +/*! + \fn virtual bool QDesignerFormWindowToolInterface::handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event) = 0 +*/ + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/abstractformwindowtool.h b/src/designer/src/lib/sdk/abstractformwindowtool.h new file mode 100644 index 000000000..77c499420 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractformwindowtool.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABSTRACTFORMWINDOWTOOL_H +#define ABSTRACTFORMWINDOWTOOL_H + +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; +class QWidget; +class QAction; +class DomUI; + +class QDESIGNER_SDK_EXPORT QDesignerFormWindowToolInterface: public QObject +{ + Q_OBJECT +public: + QDesignerFormWindowToolInterface(QObject *parent = 0); + virtual ~QDesignerFormWindowToolInterface(); + + virtual QDesignerFormEditorInterface *core() const = 0; + virtual QDesignerFormWindowInterface *formWindow() const = 0; + virtual QWidget *editor() const = 0; + + virtual QAction *action() const = 0; + + virtual void activated() = 0; + virtual void deactivated() = 0; + + virtual void saveToDom(DomUI*, QWidget*) {} + virtual void loadFromDom(DomUI*, QWidget*) {} + + virtual bool handleEvent(QWidget *widget, QWidget *managedWidget, QEvent *event) = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ABSTRACTFORMWINDOWTOOL_H diff --git a/src/designer/src/lib/sdk/abstracticoncache.h b/src/designer/src/lib/sdk/abstracticoncache.h new file mode 100644 index 000000000..ce2ed9d83 --- /dev/null +++ b/src/designer/src/lib/sdk/abstracticoncache.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABSTRACTICONCACHE_H +#define ABSTRACTICONCACHE_H + +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QIcon; +class QPixmap; +class QString; + +class QDESIGNER_SDK_EXPORT QDesignerIconCacheInterface : public QObject +{ + Q_OBJECT +public: + QDesignerIconCacheInterface(QObject *parent_) + : QObject(parent_) {} + + virtual QIcon nameToIcon(const QString &filePath, const QString &qrcPath = QString()) = 0; + virtual QPixmap nameToPixmap(const QString &filePath, const QString &qrcPath = QString()) = 0; + + virtual QString iconToFilePath(const QIcon &pm) const = 0; + virtual QString iconToQrcPath(const QIcon &pm) const = 0; + + virtual QString pixmapToFilePath(const QPixmap &pm) const = 0; + virtual QString pixmapToQrcPath(const QPixmap &pm) const = 0; + + virtual QList pixmapList() const = 0; + virtual QList iconList() const = 0; + + virtual QString resolveQrcPath(const QString &filePath, const QString &qrcPath, const QString &workingDirectory = QString()) const = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ABSTRACTICONCACHE_H diff --git a/src/designer/src/lib/sdk/abstracticoncache.qdoc b/src/designer/src/lib/sdk/abstracticoncache.qdoc new file mode 100644 index 000000000..f211c533c --- /dev/null +++ b/src/designer/src/lib/sdk/abstracticoncache.qdoc @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QDesignerIconCacheInterface + \brief The QDesignerIconCacheInterface class provides an interface to \QD's icon cache. + \inmodule QtDesigner + \internal +*/ + +/*! + \fn QDesignerIconCacheInterface::QDesignerIconCacheInterface(QObject *parent) + + Constructs a new interface with the given \a parent. +*/ + +/*! + \fn QIcon QDesignerIconCacheInterface::nameToIcon(const QString &filePath, const QString &qrcPath) + + Returns the icon associated with the name specified by \a filePath in the resource + file specified by \a qrcPath. + + If \a qrcPath refers to a valid resource file, the name used for the file path is a path + within those resources; otherwise the file path refers to a local file. + + \sa {The Qt Resource System}, nameToPixmap() +*/ + +/*! + \fn QPixmap QDesignerIconCacheInterface::nameToPixmap(const QString &filePath, const QString &qrcPath) + + Returns the pixmap associated with the name specified by \a filePath in the resource + file specified by \a qrcPath. + + If \a qrcPath refers to a valid resource file, the name used for the file path is a path + within those resources; otherwise the file path refers to a local file. + + \sa {The Qt Resource System}, nameToIcon() +*/ + +/*! + \fn QString QDesignerIconCacheInterface::iconToFilePath(const QIcon &icon) const + + Returns the file path associated with the given \a icon. The file path is a path within + an application resources. +*/ + +/*! + \fn QString QDesignerIconCacheInterface::iconToQrcPath(const QIcon &icon) const + + Returns the path to the resource file that refers to the specified \a icon. The resource + path refers to a local file. +*/ + +/*! + \fn QString QDesignerIconCacheInterface::pixmapToFilePath(const QPixmap &pixmap) const + + Returns the file path associated with the given \a pixmap. The file path is a path within + an application resources. +*/ + +/*! + \fn QString QDesignerIconCacheInterface::pixmapToQrcPath(const QPixmap &pixmap) const + + Returns the path to the resource file that refers to the specified \a pixmap. The resource + path refers to a local file. +*/ + +/*! + \fn QList QDesignerIconCacheInterface::pixmapList() const + + Returns a list of pixmaps for the icons provided by the icon cache. +*/ + +/*! + \fn QList QDesignerIconCacheInterface::iconList() const + + Returns a list of icons provided by the icon cache. +*/ + +/*! + \fn QString QDesignerIconCacheInterface::resolveQrcPath(const QString &filePath, const QString &qrcPath, const QString &workingDirectory) const + + Returns a path to a resource specified by the \a filePath within + the resource file located at \a qrcPath. If \a workingDirectory is + a valid path to a directory, the path returned will be relative to + that directory; otherwise an absolute path is returned. + + \omit + ### Needs checking + \endomit +*/ diff --git a/src/designer/src/lib/sdk/abstractintegration.cpp b/src/designer/src/lib/sdk/abstractintegration.cpp new file mode 100644 index 000000000..0c888f651 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractintegration.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractintegration.h" +#include "abstractformeditor.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +// Add 'private' struct as a dynamic property. + +static const char privatePropertyC[] = "_q_integrationprivate"; + +struct QDesignerIntegrationInterfacePrivate { + QDesignerIntegrationInterfacePrivate() : + headerSuffix(QLatin1String(".h")), + headerLowercase(true) {} + + QString headerSuffix; + bool headerLowercase; +}; + +typedef QSharedPointer QDesignerIntegrationInterfacePrivatePtr; + +QT_END_NAMESPACE +Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(QDesignerIntegrationInterfacePrivatePtr)) +QT_BEGIN_NAMESPACE + +static QDesignerIntegrationInterfacePrivatePtr integrationD(const QObject *o) +{ + const QVariant property = o->property(privatePropertyC); + Q_ASSERT(qVariantCanConvert(property)); + return qvariant_cast(property); +} + +QDesignerIntegrationInterface::QDesignerIntegrationInterface(QDesignerFormEditorInterface *core, QObject *parent) + : QObject(parent), + m_core(core) +{ + core->setIntegration(this); + const QDesignerIntegrationInterfacePrivatePtr d(new QDesignerIntegrationInterfacePrivate); + setProperty(privatePropertyC, qVariantFromValue(d)); +} + +QString QDesignerIntegrationInterface::headerSuffix() const +{ + return integrationD(this)->headerSuffix; +} + +void QDesignerIntegrationInterface::setHeaderSuffix(const QString &headerSuffix) +{ + integrationD(this)->headerSuffix = headerSuffix; +} + +bool QDesignerIntegrationInterface::isHeaderLowercase() const +{ + return integrationD(this)->headerLowercase; +} + +void QDesignerIntegrationInterface::setHeaderLowercase(bool headerLowercase) +{ + integrationD(this)->headerLowercase = headerLowercase; +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/abstractintegration.h b/src/designer/src/lib/sdk/abstractintegration.h new file mode 100644 index 000000000..9e27f9037 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractintegration.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABSTRACTINTEGRATION_H +#define ABSTRACTINTEGRATION_H + +#include + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; + +class QDESIGNER_SDK_EXPORT QDesignerIntegrationInterface: public QObject +{ + Q_OBJECT + Q_PROPERTY(QString headerSuffix READ headerSuffix WRITE setHeaderSuffix) + Q_PROPERTY(bool headerLowercase READ isHeaderLowercase WRITE setHeaderLowercase) + +public: + QDesignerIntegrationInterface(QDesignerFormEditorInterface *core, QObject *parent = 0); + + inline QDesignerFormEditorInterface *core() const; + + virtual QWidget *containerWindow(QWidget *widget) const = 0; + + QString headerSuffix() const; + void setHeaderSuffix(const QString &headerSuffix); + + bool isHeaderLowercase() const; + void setHeaderLowercase(bool headerLowerCase); + +private: + QDesignerFormEditorInterface *m_core; +}; + +inline QDesignerFormEditorInterface *QDesignerIntegrationInterface::core() const +{ return m_core; } + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ABSTRACTINTEGRATION_H diff --git a/src/designer/src/lib/sdk/abstractintrospection.cpp b/src/designer/src/lib/sdk/abstractintrospection.cpp new file mode 100644 index 000000000..d733588fb --- /dev/null +++ b/src/designer/src/lib/sdk/abstractintrospection.cpp @@ -0,0 +1,548 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractintrospection_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QDesignerMetaEnumInterface + \internal + \since 4.4 + + \brief QDesignerMetaEnumInterface is part of \QD's introspection interface and represents an enumeration. + + \inmodule QtDesigner + + The QDesignerMetaEnumInterface class provides meta-data about an enumerator. + + \sa QDesignerMetaObjectInterface +*/ + +/*! + Constructs a QDesignerMetaEnumInterface object. +*/ + +QDesignerMetaEnumInterface::QDesignerMetaEnumInterface() +{ +} + +/*! + Destroys the QDesignerMetaEnumInterface object. +*/ +QDesignerMetaEnumInterface::~QDesignerMetaEnumInterface() +{ +} + +/*! + \fn bool QDesignerMetaEnumInterface::isFlag() const + + Returns true if this enumerator is used as a flag. +*/ + +/*! + \fn QString QDesignerMetaEnumInterface::key(int index) const + + Returns the key with the given \a index. +*/ + +/*! + \fn int QDesignerMetaEnumInterface::keyCount() const + + Returns the number of keys. +*/ + +/*! + \fn int QDesignerMetaEnumInterface::keyToValue(const QString &key) const + + Returns the integer value of the given enumeration \a key, or -1 if \a key is not defined. +*/ + +/*! + \fn int QDesignerMetaEnumInterface::keysToValue(const QString &keys) const + + Returns the value derived from combining together the values of the \a keys using the OR operator, or -1 if keys is not defined. Note that the strings in \a keys must be '|'-separated. +*/ + +/*! + \fn QString QDesignerMetaEnumInterface::name() const + + Returns the name of the enumerator (without the scope). +*/ + +/*! + \fn QString QDesignerMetaEnumInterface::scope() const + + Returns the scope this enumerator was declared in. +*/ + +/*! + \fn QString QDesignerMetaEnumInterface::separator() const + + Returns the separator to be used when building enumeration names. +*/ + +/*! + \fn int QDesignerMetaEnumInterface::value(int index) const + + Returns the value with the given \a index; or returns -1 if there is no such value. +*/ + +/*! + \fn QString QDesignerMetaEnumInterface::valueToKey(int value) const + + Returns the string that is used as the name of the given enumeration \a value, or QString::null if value is not defined. +*/ + +/*! + \fn QString QDesignerMetaEnumInterface::valueToKeys(int value) const + + Returns a byte array of '|'-separated keys that represents the given \a value. +*/ + +/*! + \class QDesignerMetaPropertyInterface + \internal + \since 4.4 + + \brief QDesignerMetaPropertyInterface is part of \QD's introspection interface and represents a property. + + \inmodule QtDesigner + + The QDesignerMetaPropertyInterface class provides meta-data about a property. + + \sa QDesignerMetaObjectInterface +*/ + +/*! + Constructs a QDesignerMetaPropertyInterface object. +*/ + +QDesignerMetaPropertyInterface::QDesignerMetaPropertyInterface() +{ +} + +/*! + Destroys the QDesignerMetaPropertyInterface object. +*/ + +QDesignerMetaPropertyInterface::~QDesignerMetaPropertyInterface() +{ +} + +/*! + \enum QDesignerMetaPropertyInterface::Kind + + This enum indicates whether the property is of a special type. + + \value EnumKind The property is of an enumeration type + \value FlagKind The property is of an flag type + \value OtherKind The property is of another type + */ + +/*! + \enum QDesignerMetaPropertyInterface::AccessFlag + + These flags specify the access the property provides. + + \value ReadAccess Property can be read + \value WriteAccess Property can be written + \value ResetAccess Property can be reset to a default value + */ + +/*! + \enum QDesignerMetaPropertyInterface::Attribute + + Various attributes of the property. + + \value DesignableAttribute Property is designable (visible in \QD) + \value ScriptableAttribute Property is scriptable + \value StoredAttribute Property is stored, that is, not calculated + \value UserAttribute Property is the property that the user can edit for the QObject + */ + +/*! + \fn const QDesignerMetaEnumInterface *QDesignerMetaPropertyInterface::enumerator() const + + Returns the enumerator if this property's type is an enumerator type; +*/ + +/*! + \fn Kind QDesignerMetaPropertyInterface::kind() const + + Returns the type of the property. +*/ + +/*! + \fn AccessFlags QDesignerMetaPropertyInterface::accessFlags() const + + Returns a combination of access flags. +*/ + +/*! + \fn Attributes QDesignerMetaPropertyInterface::attributes(const QObject *object) const + + Returns the attributes of the property for the gives \a object. +*/ + +/*! + \fn QVariant::Type QDesignerMetaPropertyInterface::type() const + + Returns the type of the property. +*/ + +/*! + \fn QString QDesignerMetaPropertyInterface::name() const + + Returns the name of the property. +*/ + +/*! + \fn QString QDesignerMetaPropertyInterface::typeName() const + + Returns the name of this property's type. +*/ + + +/*! + \fn int QDesignerMetaPropertyInterface::userType() const + + Returns this property's user type. +*/ + +/*! + \fn bool QDesignerMetaPropertyInterface::hasSetter() const + + Returns whether getter and setter methods exist for this property. +*/ + +/*! + \fn QVariant QDesignerMetaPropertyInterface::read(const QObject *object) const + + Reads the property's value from the given \a object. Returns the value if it was able to read it; otherwise returns an invalid variant. +*/ + +/*! + \fn bool QDesignerMetaPropertyInterface::reset(QObject *object) const + + Resets the property for the given \a object with a reset method. Returns true if the reset worked; otherwise returns false. +*/ + +/*! + \fn bool QDesignerMetaPropertyInterface::write(QObject *object, const QVariant &value) const + + Writes \a value as the property's value to the given \a object. Returns true if the write succeeded; otherwise returns false. +*/ + +/*! + \class QDesignerMetaMethodInterface + \internal + \since 4.4 + + \brief QDesignerMetaMethodInterface is part of \QD's introspection interface and represents a member function. + + \inmodule QtDesigner + + The QDesignerMetaMethodInterface class provides meta-data about a member function. + + \sa QDesignerMetaObjectInterface +*/ + +/*! + Constructs a QDesignerMetaMethodInterface object. +*/ + +QDesignerMetaMethodInterface::QDesignerMetaMethodInterface() +{ +} + +/*! + Destroys the QDesignerMetaMethodInterface object. +*/ + +QDesignerMetaMethodInterface::~QDesignerMetaMethodInterface() +{ +} + +/*! + \enum QDesignerMetaMethodInterface::MethodType + + This enum specifies the type of the method + + \value Method The function is a plain member function. + \value Signal The function is a signal. + \value Slot The function is a slot. + \value Constructor The function is a constructor. + +*/ + +/*! + \enum QDesignerMetaMethodInterface::Access + + This enum represents the access specification of the method + + \value Private A private member function + \value Protected A protected member function + \value Public A public member function +*/ + +/*! + \fn QDesignerMetaMethodInterface::Access QDesignerMetaMethodInterface::access() const + + Returns the access specification of this method. +*/ + + +/*! + \fn QDesignerMetaMethodInterface::MethodType QDesignerMetaMethodInterface::methodType() const + + Returns the type of this method. +*/ + +/*! + \fn QStringList QDesignerMetaMethodInterface::parameterNames() const + + Returns a list of parameter names. +*/ + +/*! + \fn QStringList QDesignerMetaMethodInterface::parameterTypes() const + + Returns a list of parameter types. +*/ + +/*! + \fn QString QDesignerMetaMethodInterface::signature() const + + Returns the signature of this method. +*/ + +/*! + \fn QString QDesignerMetaMethodInterface::normalizedSignature() const + + Returns the normalized signature of this method (suitable as signal/slot specification). +*/ + + +/*! + \fn QString QDesignerMetaMethodInterface::tag() const + + Returns the tag associated with this method. +*/ + +/*! + \fn QString QDesignerMetaMethodInterface::typeName() const + + Returns the return type of this method, or an empty string if the return type is void. +*/ + +/*! + \class QDesignerMetaObjectInterface + \internal + \since 4.4 + + \brief QDesignerMetaObjectInterface is part of \QD's introspection interface and provides meta-information about Qt objects + + \inmodule QtDesigner + + The QDesignerMetaObjectInterface class provides meta-data about Qt objects. For a given object, it can be obtained + by querying QDesignerIntrospectionInterface. + + \sa QDesignerIntrospectionInterface +*/ + +/*! + Constructs a QDesignerMetaObjectInterface object. +*/ + +QDesignerMetaObjectInterface::QDesignerMetaObjectInterface() +{ +} + +/*! + Destroys the QDesignerMetaObjectInterface object. +*/ + +QDesignerMetaObjectInterface::~QDesignerMetaObjectInterface() +{ +} + +/*! + \fn QString QDesignerMetaObjectInterface::className() const + + Returns the class name. +*/ + +/*! + \fn const QDesignerMetaEnumInterface *QDesignerMetaObjectInterface::enumerator(int index) const + + Returns the meta-data for the enumerator with the given \a index. +*/ + +/*! + \fn int QDesignerMetaObjectInterface::enumeratorCount() const + + Returns the number of enumerators in this class. +*/ + +/*! + \fn int QDesignerMetaObjectInterface::enumeratorOffset() const + + Returns the enumerator offset for this class; i.e. the index position of this class's first enumerator. +*/ + +/*! + \fn int QDesignerMetaObjectInterface::indexOfEnumerator(const QString &name) const + + Finds enumerator \a name and returns its index; otherwise returns -1. +*/ + +/*! + \fn int QDesignerMetaObjectInterface::indexOfMethod(const QString &method) const + + Finds \a method and returns its index; otherwise returns -1. +*/ + +/*! + \fn int QDesignerMetaObjectInterface::indexOfProperty(const QString &name) const + + Finds property \a name and returns its index; otherwise returns -1. +*/ + +/*! + \fn int QDesignerMetaObjectInterface::indexOfSignal(const QString &signal) const + + Finds \a signal and returns its index; otherwise returns -1. +*/ + +/*! + \fn int QDesignerMetaObjectInterface::indexOfSlot(const QString &slot) const + + Finds \a slot and returns its index; otherwise returns -1. +*/ + +/*! + \fn const QDesignerMetaMethodInterface *QDesignerMetaObjectInterface::method(int index) const + + Returns the meta-data for the method with the given \a index. +*/ + +/*! + \fn int QDesignerMetaObjectInterface::methodCount() const + + Returns the number of methods in this class. These include ordinary methods, signals, and slots. +*/ + +/*! + \fn int QDesignerMetaObjectInterface::methodOffset() const + + Returns the method offset for this class; i.e. the index position of this class's first member function. +*/ + +/*! + \fn const QDesignerMetaPropertyInterface *QDesignerMetaObjectInterface::property(int index) const + + Returns the meta-data for the property with the given \a index. +*/ +/*! + \fn int QDesignerMetaObjectInterface::propertyCount() const + + Returns the number of properties in this class. +*/ +/*! + \fn int QDesignerMetaObjectInterface::propertyOffset() const + + Returns the property offset for this class; i.e. the index position of this class's first property. +*/ + +/*! + \fn const QDesignerMetaObjectInterface *QDesignerMetaObjectInterface::superClass() const + + Returns the meta-object of the superclass, or 0 if there is no such object. +*/ + +/*! + \fn const QDesignerMetaPropertyInterface *QDesignerMetaObjectInterface::userProperty() const + + Returns the property that has the USER flag set to true. +*/ + +/*! + \class QDesignerIntrospectionInterface + \internal + \since 4.4 + + \brief QDesignerIntrospectionInterface provides access to a QDesignerMetaObjectInterface for a given Qt object. + + \inmodule QtDesigner + + QDesignerIntrospectionInterface is the main class of \QD's introspection interface. These + interfaces provide a layer of abstraction around QMetaObject and related classes to allow for the integration + of other programming languages. + + An instance of QDesignerIntrospectionInterface can be obtained from the core. + + \sa QDesignerMetaObjectInterface +*/ + +/*! + Constructs a QDesignerIntrospectionInterface object. +*/ + +QDesignerIntrospectionInterface::QDesignerIntrospectionInterface() +{ +} + +/*! + Destroys the QDesignerIntrospectionInterface object. +*/ + +QDesignerIntrospectionInterface::~QDesignerIntrospectionInterface() +{ +} + +/*! + \fn const QDesignerMetaObjectInterface* QDesignerIntrospectionInterface::metaObject(const QObject *object) const + + Returns the meta object of this \a object. +*/ + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/abstractintrospection_p.h b/src/designer/src/lib/sdk/abstractintrospection_p.h new file mode 100644 index 000000000..52074b890 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractintrospection_p.h @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef ABSTRACTMETAOBJECT_H +#define ABSTRACTMETAOBJECT_H + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QDESIGNER_SDK_EXPORT QDesignerMetaEnumInterface +{ +public: + QDesignerMetaEnumInterface(); + virtual ~QDesignerMetaEnumInterface(); + virtual bool isFlag() const = 0; + virtual QString key(int index) const = 0; + virtual int keyCount() const = 0; + virtual int keyToValue(const QString &key) const = 0; + virtual int keysToValue(const QString &keys) const = 0; + virtual QString name() const = 0; + virtual QString scope() const = 0; + virtual QString separator() const = 0; + virtual int value(int index) const = 0; + virtual QString valueToKey(int value) const = 0; + virtual QString valueToKeys(int value) const = 0; +}; + +class QDESIGNER_SDK_EXPORT QDesignerMetaPropertyInterface +{ +public: + enum Kind { EnumKind, FlagKind, OtherKind }; + enum AccessFlag { ReadAccess = 0x0001, WriteAccess = 0x0002, ResetAccess = 0x0004 }; + enum Attribute { DesignableAttribute = 0x0001, ScriptableAttribute = 0x0002, StoredAttribute = 0x0004, UserAttribute = 0x0008}; + Q_DECLARE_FLAGS(Attributes, Attribute) + Q_DECLARE_FLAGS(AccessFlags, AccessFlag) + + QDesignerMetaPropertyInterface(); + virtual ~QDesignerMetaPropertyInterface(); + + virtual const QDesignerMetaEnumInterface *enumerator() const = 0; + + virtual Kind kind() const = 0; + virtual AccessFlags accessFlags() const = 0; + virtual Attributes attributes(const QObject *object = 0) const = 0; + + virtual QVariant::Type type() const = 0; + virtual QString name() const = 0; + virtual QString typeName() const = 0; + virtual int userType() const = 0; + virtual bool hasSetter() const = 0; + + virtual QVariant read(const QObject *object) const = 0; + virtual bool reset(QObject *object) const = 0; + virtual bool write(QObject *object, const QVariant &value) const = 0; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QDesignerMetaPropertyInterface::AccessFlags) +Q_DECLARE_OPERATORS_FOR_FLAGS(QDesignerMetaPropertyInterface::Attributes) + +class QDESIGNER_SDK_EXPORT QDesignerMetaMethodInterface +{ +public: + QDesignerMetaMethodInterface(); + virtual ~QDesignerMetaMethodInterface(); + + enum MethodType { Method, Signal, Slot, Constructor }; + enum Access { Private, Protected, Public }; + + virtual Access access() const = 0; + virtual MethodType methodType() const = 0; + virtual QStringList parameterNames() const = 0; + virtual QStringList parameterTypes() const = 0; + virtual QString signature() const = 0; + virtual QString normalizedSignature() const = 0; + virtual QString tag() const = 0; + virtual QString typeName() const = 0; +}; + +class QDESIGNER_SDK_EXPORT QDesignerMetaObjectInterface { +public: + QDesignerMetaObjectInterface(); + virtual ~QDesignerMetaObjectInterface(); + + virtual QString className() const = 0; + virtual const QDesignerMetaEnumInterface *enumerator(int index) const = 0; + virtual int enumeratorCount() const = 0; + virtual int enumeratorOffset() const = 0; + + virtual int indexOfEnumerator(const QString &name) const = 0; + virtual int indexOfMethod(const QString &method) const = 0; + virtual int indexOfProperty(const QString &name) const = 0; + virtual int indexOfSignal(const QString &signal) const = 0; + virtual int indexOfSlot(const QString &slot) const = 0; + + virtual const QDesignerMetaMethodInterface *method(int index) const = 0; + virtual int methodCount() const = 0; + virtual int methodOffset() const = 0; + + virtual const QDesignerMetaPropertyInterface *property(int index) const = 0; + virtual int propertyCount() const = 0; + virtual int propertyOffset() const = 0; + + virtual const QDesignerMetaObjectInterface *superClass() const = 0; + virtual const QDesignerMetaPropertyInterface *userProperty() const = 0; +}; + +// To be obtained from core +class QDESIGNER_SDK_EXPORT QDesignerIntrospectionInterface { +public: + QDesignerIntrospectionInterface(); + virtual ~QDesignerIntrospectionInterface(); + + virtual const QDesignerMetaObjectInterface* metaObject(const QObject *object) const = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ABSTRACTMETAOBJECT_H diff --git a/src/designer/src/lib/sdk/abstractlanguage.h b/src/designer/src/lib/sdk/abstractlanguage.h new file mode 100644 index 000000000..37c0c5de0 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractlanguage.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_ABTRACT_LANGUAGE_H +#define QDESIGNER_ABTRACT_LANGUAGE_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QDialog; +class QWidget; +class QDesignerFormWindowInterface; +class QDesignerFormEditorInterface; +class QDesignerResourceBrowserInterface; + +class QDesignerLanguageExtension +{ +public: + virtual ~QDesignerLanguageExtension() {} + + virtual QDialog *createFormWindowSettingsDialog(QDesignerFormWindowInterface *formWindow, QWidget *parentWidget) = 0; + virtual QDesignerResourceBrowserInterface *createResourceBrowser(QWidget *parentWidget) = 0; + + virtual QDialog *createPromotionDialog(QDesignerFormEditorInterface *formEditor, QWidget *parentWidget = 0) = 0; + + virtual QDialog *createPromotionDialog(QDesignerFormEditorInterface *formEditor, + const QString &promotableWidgetClassName, + QString *promoteToClassName, + QWidget *parentWidget = 0) = 0; + + virtual bool isLanguageResource(const QString &path) const = 0; + + virtual QString classNameOf(QObject *object) const = 0; + + virtual bool signalMatchesSlot(const QString &signal, const QString &slot) const = 0; + + virtual QString widgetBoxContents() const = 0; + + virtual QString uiExtension() const = 0; +}; + +Q_DECLARE_EXTENSION_INTERFACE(QDesignerLanguageExtension, "com.trolltech.Qt.Designer.Language.3") + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDESIGNER_ABTRACT_LANGUAGE_H diff --git a/src/designer/src/lib/sdk/abstractmetadatabase.cpp b/src/designer/src/lib/sdk/abstractmetadatabase.cpp new file mode 100644 index 000000000..061c9aa89 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractmetadatabase.cpp @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// sdk +#include "abstractmetadatabase.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QDesignerMetaDataBaseInterface + \brief The QDesignerMetaDataBaseInterface class provides an interface to Qt Designer's + object meta database. + \inmodule QtDesigner + \internal +*/ + +/*! + Constructs an interface to the meta database with the given \a parent. +*/ +QDesignerMetaDataBaseInterface::QDesignerMetaDataBaseInterface(QObject *parent) + : QObject(parent) +{ +} + +/*! + Destroys the interface to the meta database. +*/ +QDesignerMetaDataBaseInterface::~QDesignerMetaDataBaseInterface() +{ +} + +/*! + \fn QDesignerMetaDataBaseItemInterface *QDesignerMetaDataBaseInterface::item(QObject *object) const + + Returns the item in the meta database associated with the given \a object. +*/ + +/*! + \fn void QDesignerMetaDataBaseInterface::add(QObject *object) + + Adds the specified \a object to the meta database. +*/ + +/*! + \fn void QDesignerMetaDataBaseInterface::remove(QObject *object) + + Removes the specified \a object from the meta database. +*/ + +/*! + \fn QList QDesignerMetaDataBaseInterface::objects() const + + Returns the list of objects that have corresponding items in the meta database. +*/ + +/*! + \fn QDesignerFormEditorInterface *QDesignerMetaDataBaseInterface::core() const + + Returns the core interface that is associated with the meta database. +*/ + + +// Doc: Interface only + +/*! + \class QDesignerMetaDataBaseItemInterface + \brief The QDesignerMetaDataBaseItemInterface class provides an interface to individual + items in Qt Designer's meta database. + \inmodule QtDesigner + \internal + + This class allows individual items in \QD's meta-data database to be accessed and modified. + Use the QDesignerMetaDataBaseInterface class to change the properties of the database itself. +*/ + +/*! + \fn QDesignerMetaDataBaseItemInterface::~QDesignerMetaDataBaseItemInterface() + + Destroys the item interface to the meta-data database. +*/ + +/*! + \fn QString QDesignerMetaDataBaseItemInterface::name() const + + Returns the name of the item in the database. + + \sa setName() +*/ + +/*! + \fn void QDesignerMetaDataBaseItemInterface::setName(const QString &name) + + Sets the name of the item to the given \a name. + + \sa name() +*/ + +/*! + \fn QList QDesignerMetaDataBaseItemInterface::tabOrder() const + + Returns a list of widgets in the order defined by the form's tab order. + + \sa setTabOrder() +*/ + + +/*! + \fn void QDesignerMetaDataBaseItemInterface::setTabOrder(const QList &tabOrder) + + Sets the tab order in the form using the list of widgets defined by \a tabOrder. + + \sa tabOrder() +*/ + + +/*! + \fn bool QDesignerMetaDataBaseItemInterface::enabled() const + + Returns whether the item is enabled. + + \sa setEnabled() +*/ + +/*! + \fn void QDesignerMetaDataBaseItemInterface::setEnabled(bool enabled) + + If \a enabled is true, the item is enabled; otherwise it is disabled. + + \sa enabled() +*/ + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/abstractmetadatabase.h b/src/designer/src/lib/sdk/abstractmetadatabase.h new file mode 100644 index 000000000..1fdc7ef69 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractmetadatabase.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABSTRACTMETADATABASE_H +#define ABSTRACTMETADATABASE_H + +#include + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QCursor; +class QWidget; + +class QDesignerFormEditorInterface; + +class QDesignerMetaDataBaseItemInterface +{ +public: + virtual ~QDesignerMetaDataBaseItemInterface() {} + + virtual QString name() const = 0; + virtual void setName(const QString &name) = 0; + + virtual QList tabOrder() const = 0; + virtual void setTabOrder(const QList &tabOrder) = 0; + + virtual bool enabled() const = 0; + virtual void setEnabled(bool b) = 0; +}; + + +class QDESIGNER_SDK_EXPORT QDesignerMetaDataBaseInterface: public QObject +{ + Q_OBJECT +public: + QDesignerMetaDataBaseInterface(QObject *parent = 0); + virtual ~QDesignerMetaDataBaseInterface(); + + virtual QDesignerMetaDataBaseItemInterface *item(QObject *object) const = 0; + virtual void add(QObject *object) = 0; + virtual void remove(QObject *object) = 0; + + virtual QList objects() const = 0; + + virtual QDesignerFormEditorInterface *core() const = 0; + +Q_SIGNALS: + void changed(); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ABSTRACTMETADATABASE_H diff --git a/src/designer/src/lib/sdk/abstractnewformwidget.cpp b/src/designer/src/lib/sdk/abstractnewformwidget.cpp new file mode 100644 index 000000000..42d43432e --- /dev/null +++ b/src/designer/src/lib/sdk/abstractnewformwidget.cpp @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractnewformwidget_p.h" +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QDesignerNewFormWidgetInterface + \since 4.5 + \internal + + \brief QDesignerNewFormWidgetInterface provides an interface for chooser + widgets that can be used within "New Form" dialogs and wizards. + It presents the user with a list of choices taken from built-in + templates, pre-defined template paths and suitable custom widgets. + It provides a static creation function that returns \QD's + implementation. + + \inmodule QtDesigner +*/ + +/*! + Constructs a QDesignerNewFormWidgetInterface object. +*/ + +QDesignerNewFormWidgetInterface::QDesignerNewFormWidgetInterface(QWidget *parent) : + QWidget(parent) +{ +} + +/*! + Destroys the QDesignerNewFormWidgetInterface object. +*/ + +QDesignerNewFormWidgetInterface::~QDesignerNewFormWidgetInterface() +{ +} + +/*! + Creates an instance of the QDesignerNewFormWidgetInterface as a child + of \a parent using \a core. +*/ + +QDesignerNewFormWidgetInterface *QDesignerNewFormWidgetInterface::createNewFormWidget(QDesignerFormEditorInterface *core, QWidget *parent) +{ + return new qdesigner_internal::NewFormWidget(core, parent); +} + +/*! + \fn bool QDesignerNewFormWidgetInterface::hasCurrentTemplate() const + + Returns whether a form template is currently selected. +*/ + +/*! + \fn QString QDesignerNewFormWidgetInterface::currentTemplate(QString *errorMessage = 0) + + Returns the contents of the currently selected template. If the method fails, + an empty string is returned and \a errorMessage receives an error message. +*/ + +// Signals + +/*! + \fn void QDesignerNewFormWidgetInterface::templateActivated() + + This signal is emitted whenever the user activates a template by double-clicking. +*/ + +/*! + \fn void QDesignerNewFormWidgetInterface::currentTemplateChanged(bool templateSelected) + + This signal is emitted whenever the user changes the current template. + \a templateSelected indicates whether a template is currently selected. +*/ + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/abstractnewformwidget_p.h b/src/designer/src/lib/sdk/abstractnewformwidget_p.h new file mode 100644 index 000000000..db0c74031 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractnewformwidget_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef ABSTRACTNEWFORMWIDGET_H +#define ABSTRACTNEWFORMWIDGET_H + +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; + +class QDESIGNER_SDK_EXPORT QDesignerNewFormWidgetInterface : public QWidget +{ + Q_DISABLE_COPY(QDesignerNewFormWidgetInterface) + Q_OBJECT +public: + explicit QDesignerNewFormWidgetInterface(QWidget *parent = 0); + virtual ~QDesignerNewFormWidgetInterface(); + + virtual bool hasCurrentTemplate() const = 0; + virtual QString currentTemplate(QString *errorMessage = 0) = 0; + + static QDesignerNewFormWidgetInterface *createNewFormWidget(QDesignerFormEditorInterface *core, QWidget *parent = 0); + +Q_SIGNALS: + void templateActivated(); + void currentTemplateChanged(bool templateSelected); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ABSTRACTNEWFORMWIDGET_H diff --git a/src/designer/src/lib/sdk/abstractobjectinspector.cpp b/src/designer/src/lib/sdk/abstractobjectinspector.cpp new file mode 100644 index 000000000..d231fce58 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractobjectinspector.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractobjectinspector.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QDesignerObjectInspectorInterface + + \brief The QDesignerObjectInspectorInterface class allows you to + change the focus of Qt Designer's object inspector. + + \inmodule QtDesigner + + You can use the QDesignerObjectInspectorInterface to change the + current form window selection. For example, when implementing a + custom widget plugin: + + \snippet doc/src/snippets/code/tools_designer_src_lib_sdk_abstractobjectinspector.cpp 0 + + The QDesignerObjectInspectorInterface class is not intended to be + instantiated directly. You can retrieve an interface to \QD's + object inspector using the + QDesignerFormEditorInterface::objectInspector() function. A + pointer to \QD's current QDesignerFormEditorInterface object (\c + formEditor in the example above) is provided by the + QDesignerCustomWidgetInterface::initialize() function's + parameter. When implementing a custom widget plugin, you must + subclass the QDesignerCustomWidgetInterface to expose your plugin + to \QD. + + The interface provides the core() function that you can use to + retrieve a pointer to \QD's current QDesignerFormEditorInterface + object, and the setFormWindow() function that enables you to + change the current form window selection. + + \sa QDesignerFormEditorInterface, QDesignerFormWindowInterface +*/ + +/*! + Constructs an object inspector interface with the given \a parent + and the specified window \a flags. +*/ +QDesignerObjectInspectorInterface::QDesignerObjectInspectorInterface(QWidget *parent, Qt::WindowFlags flags) + : QWidget(parent, flags) +{ +} + +/*! + Destroys the object inspector interface. +*/ +QDesignerObjectInspectorInterface::~QDesignerObjectInspectorInterface() +{ +} + +/*! + Returns a pointer to \QD's current QDesignerFormEditorInterface + object. +*/ +QDesignerFormEditorInterface *QDesignerObjectInspectorInterface::core() const +{ + return 0; +} + +/*! + \fn void QDesignerObjectInspectorInterface::setFormWindow(QDesignerFormWindowInterface *formWindow) + + Sets the currently selected form window to \a formWindow. +*/ + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/abstractobjectinspector.h b/src/designer/src/lib/sdk/abstractobjectinspector.h new file mode 100644 index 000000000..74c6e385a --- /dev/null +++ b/src/designer/src/lib/sdk/abstractobjectinspector.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABSTRACTOBJECTINSPECTOR_H +#define ABSTRACTOBJECTINSPECTOR_H + +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; + +class QDESIGNER_SDK_EXPORT QDesignerObjectInspectorInterface: public QWidget +{ + Q_OBJECT +public: + QDesignerObjectInspectorInterface(QWidget *parent, Qt::WindowFlags flags = 0); + virtual ~QDesignerObjectInspectorInterface(); + + virtual QDesignerFormEditorInterface *core() const; + +public Q_SLOTS: + virtual void setFormWindow(QDesignerFormWindowInterface *formWindow) = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ABSTRACTOBJECTINSPECTOR_H diff --git a/src/designer/src/lib/sdk/abstractoptionspage_p.h b/src/designer/src/lib/sdk/abstractoptionspage_p.h new file mode 100644 index 000000000..f6c54ae44 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractoptionspage_p.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef ABSTRACTOPTIONSPAGE_P_H +#define ABSTRACTOPTIONSPAGE_P_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QString; +class QWidget; + +class QDESIGNER_SDK_EXPORT QDesignerOptionsPageInterface +{ +public: + virtual ~QDesignerOptionsPageInterface() {} + virtual QString name() const = 0; + virtual QWidget *createPage(QWidget *parent) = 0; + virtual void apply() = 0; + virtual void finish() = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ABSTRACTOPTIONSPAGE_P_H diff --git a/src/designer/src/lib/sdk/abstractpromotioninterface.cpp b/src/designer/src/lib/sdk/abstractpromotioninterface.cpp new file mode 100644 index 000000000..5dd590cb3 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractpromotioninterface.cpp @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractpromotioninterface.h" + +QT_BEGIN_NAMESPACE + +QDesignerPromotionInterface::~QDesignerPromotionInterface() +{ +} + +/*! + \class QDesignerPromotionInterface + + \brief The QDesignerPromotionInterface provides functions for modifying + the promoted classes in Designer. + \inmodule QtDesigner + \internal + \since 4.3 +*/ + +/*! + \class QDesignerPromotionInterface::PromotedClass + A pair of database items containing the base class and the promoted class. + + \typedef QDesignerPromotionInterface::PromotedClasses + A list of PromotedClass items. + + virtual QDesignerPromotionInterface::PromotedClasses promotedClasses() const + + Returns a list of promoted classes along with their base classes in alphabetical order. + It can be used to populate tree models for editing promoted widgets. + +*/ + +/*! + \fn virtual QSet QDesignerPromotionInterface::referencedPromotedClassNames() const + + Returns a set of promoted classed that are referenced by the currently opened forms. +*/ + +/*! + \fn virtual bool QDesignerPromotionInterface::addPromotedClass(const QString &baseClass, const QString &className, const QString &includeFile, QString *errorMessage) + + Add a promoted class named \a with the base class \a and include file \a includeFile. Returns \c true on success or \c false along + with an error message in \a errorMessage on failure. +*/ + +/*! + \fn virtual bool QDesignerPromotionInterface::removePromotedClass(const QString &className, QString *errorMessage) + + Remove the promoted class named \a className unless it is referenced by a form. Returns \c true on success or \c false along + with an error message in \a errorMessage on failure. +*/ + +/*! + \fn virtual bool QDesignerPromotionInterface::changePromotedClassName(const QString &oldClassName, const QString &newClassName, QString *errorMessage) + + Change the class name of a promoted class from \a oldClassName to \a newClassName. Returns \c true on success or \c false along + with an error message in \a errorMessage on failure. +*/ + +/*! + \fn virtual bool QDesignerPromotionInterface::setPromotedClassIncludeFile(const QString &className, const QString &includeFile, QString *errorMessage) + + Change the include file of a promoted class named \a className to be \a includeFile. Returns \c true on success or \c false along + with an error message in \a errorMessage on failure. +*/ + +/*! \fn virtual QList QDesignerPromotionInterface::promotionBaseClasses() const + + Return a list of base classes that are suitable for promotion. +*/ + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/abstractpromotioninterface.h b/src/designer/src/lib/sdk/abstractpromotioninterface.h new file mode 100644 index 000000000..6c60991d8 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractpromotioninterface.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABSTRACTPROMOTIONINTERFACE_H +#define ABSTRACTPROMOTIONINTERFACE_H + +#include + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QDesignerWidgetDataBaseItemInterface; + +class QDESIGNER_SDK_EXPORT QDesignerPromotionInterface +{ +public: + virtual ~QDesignerPromotionInterface(); + + struct PromotedClass { + QDesignerWidgetDataBaseItemInterface *baseItem; + QDesignerWidgetDataBaseItemInterface *promotedItem; + }; + + typedef QList PromotedClasses; + + virtual PromotedClasses promotedClasses() const = 0; + + virtual QSet referencedPromotedClassNames() const = 0; + + virtual bool addPromotedClass(const QString &baseClass, + const QString &className, + const QString &includeFile, + QString *errorMessage) = 0; + + virtual bool removePromotedClass(const QString &className, QString *errorMessage) = 0; + + virtual bool changePromotedClassName(const QString &oldClassName, const QString &newClassName, QString *errorMessage) = 0; + + virtual bool setPromotedClassIncludeFile(const QString &className, const QString &includeFile, QString *errorMessage) = 0; + + virtual QList promotionBaseClasses() const = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ABSTRACTPROMOTIONINTERFACE_H diff --git a/src/designer/src/lib/sdk/abstractpropertyeditor.cpp b/src/designer/src/lib/sdk/abstractpropertyeditor.cpp new file mode 100644 index 000000000..040362c9b --- /dev/null +++ b/src/designer/src/lib/sdk/abstractpropertyeditor.cpp @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractpropertyeditor.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QDesignerPropertyEditorInterface + + \brief The QDesignerPropertyEditorInterface class allows you to + query and manipulate the current state of Qt Designer's property + editor. + + \inmodule QtDesigner + + QDesignerPropertyEditorInterface contains a collection of + functions that is typically used to query the property editor for + its current state, and several slots manipulating it's state. The + interface also provide a signal, propertyChanged(), which is + emitted whenever a property changes in the property editor. The + signal's arguments are the property that changed and its new + value. + + For example, when implementing a custom widget plugin, you can + connect the signal to a custom slot: + + \snippet doc/src/snippets/code/tools_designer_src_lib_sdk_abstractpropertyeditor.cpp 0 + + Then the custom slot can check if the new value is within the + range we want when a specified property, belonging to a particular + widget, changes: + + \snippet doc/src/snippets/code/tools_designer_src_lib_sdk_abstractpropertyeditor.cpp 1 + + The QDesignerPropertyEditorInterface class is not intended to be + instantiated directly. You can retrieve an interface to \QD's + property editor using the + QDesignerFormEditorInterface::propertyEditor() function. A pointer + to \QD's current QDesignerFormEditorInterface object (\c + formEditor in the examples above) is provided by the + QDesignerCustomWidgetInterface::initialize() function's + parameter. When implementing a custom widget plugin, you must + subclass the QDesignerCustomWidgetInterface to expose your plugin + to \QD. + + The functions accessing the property editor are the core() + function that you can use to retrieve an interface to the form + editor, the currentPropertyName() function that returns the name + of the currently selected property in the property editor, the + object() function that returns the currently selected object in + \QD's workspace, and the isReadOnly() function that returns true + if the property editor is write proteced (otherwise false). + + The slots manipulating the property editor's state are the + setObject() slot that you can use to change the currently selected + object in \QD's workspace, the setPropertyValue() slot that + changes the value of a given property and the setReadOnly() slot + that control the write protection of the property editor. + + \sa QDesignerFormEditorInterface +*/ + +/*! + Constructs a property editor interface with the given \a parent and + the specified window \a flags. +*/ +QDesignerPropertyEditorInterface::QDesignerPropertyEditorInterface(QWidget *parent, Qt::WindowFlags flags) + : QWidget(parent, flags) +{ +} + +/*! + Destroys the property editor interface. +*/ +QDesignerPropertyEditorInterface::~QDesignerPropertyEditorInterface() +{ +} + +/*! + Returns a pointer to \QD's current QDesignerFormEditorInterface + object. +*/ +QDesignerFormEditorInterface *QDesignerPropertyEditorInterface::core() const +{ + return 0; +} + +/*! + \fn bool QDesignerPropertyEditorInterface::isReadOnly() const + + Returns true if the property editor is write protected; otherwise + false. + + \sa setReadOnly() +*/ + +/*! + \fn QObject *QDesignerPropertyEditorInterface::object() const + + Returns the currently selected object in \QD's workspace. + + \sa setObject() +*/ + +/*! + \fn QString QDesignerPropertyEditorInterface::currentPropertyName() const + + Returns the name of the currently selected property in the + property editor. + + \sa setPropertyValue() +*/ + +/*! + \fn void QDesignerPropertyEditorInterface::propertyChanged(const QString &name, const QVariant &value) + + This signal is emitted whenever a property changes in the property + editor. The property that changed and its new value are specified + by \a name and \a value respectively. + + \sa setPropertyValue() +*/ + +/*! + \fn void QDesignerPropertyEditorInterface::setObject(QObject *object) + + Changes the currently selected object in \QD's workspace, to \a + object. + + \sa object() +*/ + +/*! + \fn void QDesignerPropertyEditorInterface::setPropertyValue(const QString &name, const QVariant &value, bool changed = true) + + Sets the value of the property specified by \a name to \a + value. + + In addition, the property is marked as \a changed in the property + editor, i.e. its value is different from the default value. + + \sa currentPropertyName(), propertyChanged() +*/ + +/*! + \fn void QDesignerPropertyEditorInterface::setReadOnly(bool readOnly) + + If \a readOnly is true, the property editor is made write + protected; otherwise the write protection is removed. + + \sa isReadOnly() +*/ + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/abstractpropertyeditor.h b/src/designer/src/lib/sdk/abstractpropertyeditor.h new file mode 100644 index 000000000..a8d731631 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractpropertyeditor.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABSTRACTPROPERTYEDITOR_H +#define ABSTRACTPROPERTYEDITOR_H + +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QString; +class QVariant; + +class QDESIGNER_SDK_EXPORT QDesignerPropertyEditorInterface: public QWidget +{ + Q_OBJECT +public: + QDesignerPropertyEditorInterface(QWidget *parent, Qt::WindowFlags flags = 0); + virtual ~QDesignerPropertyEditorInterface(); + + virtual QDesignerFormEditorInterface *core() const; + + virtual bool isReadOnly() const = 0; + virtual QObject *object() const = 0; + + virtual QString currentPropertyName() const = 0; + +Q_SIGNALS: + void propertyChanged(const QString &name, const QVariant &value); + +public Q_SLOTS: + virtual void setObject(QObject *object) = 0; + virtual void setPropertyValue(const QString &name, const QVariant &value, bool changed = true) = 0; + virtual void setReadOnly(bool readOnly) = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ABSTRACTPROPERTYEDITOR_H diff --git a/src/designer/src/lib/sdk/abstractresourcebrowser.cpp b/src/designer/src/lib/sdk/abstractresourcebrowser.cpp new file mode 100644 index 000000000..0bb7341ef --- /dev/null +++ b/src/designer/src/lib/sdk/abstractresourcebrowser.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractresourcebrowser.h" + +QT_BEGIN_NAMESPACE + +QDesignerResourceBrowserInterface::QDesignerResourceBrowserInterface(QWidget *parent) + : QWidget(parent) +{ + +} + +QDesignerResourceBrowserInterface::~QDesignerResourceBrowserInterface() +{ + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/abstractresourcebrowser.h b/src/designer/src/lib/sdk/abstractresourcebrowser.h new file mode 100644 index 000000000..836912d9a --- /dev/null +++ b/src/designer/src/lib/sdk/abstractresourcebrowser.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABSTRACTRESOURCEBROWSER_H +#define ABSTRACTRESOURCEBROWSER_H + +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QWidget; // FIXME: fool syncqt + +class QDESIGNER_SDK_EXPORT QDesignerResourceBrowserInterface: public QWidget +{ + Q_OBJECT +public: + QDesignerResourceBrowserInterface(QWidget *parent = 0); + virtual ~QDesignerResourceBrowserInterface(); + + virtual void setCurrentPath(const QString &filePath) = 0; + virtual QString currentPath() const = 0; + +Q_SIGNALS: + void currentPathChanged(const QString &filePath); + void pathActivated(const QString &filePath); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ABSTRACTFORMEDITOR_H + diff --git a/src/designer/src/lib/sdk/abstractsettings_p.h b/src/designer/src/lib/sdk/abstractsettings_p.h new file mode 100644 index 000000000..6637d1ae5 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractsettings_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef ABSTRACTSETTINGS_P_H +#define ABSTRACTSETTINGS_P_H + +#include + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QString; + +/*! + To be implemented by IDEs that want to control the way designer retrieves/stores its settings. + */ +class QDESIGNER_SDK_EXPORT QDesignerSettingsInterface +{ +public: + virtual ~QDesignerSettingsInterface() {} + + virtual void beginGroup(const QString &prefix) = 0; + virtual void endGroup() = 0; + + virtual bool contains(const QString &key) const = 0; + virtual void setValue(const QString &key, const QVariant &value) = 0; + virtual QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const = 0; + virtual void remove(const QString &key) = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ABSTRACTSETTINGS_P_H diff --git a/src/designer/src/lib/sdk/abstractwidgetbox.cpp b/src/designer/src/lib/sdk/abstractwidgetbox.cpp new file mode 100644 index 000000000..6b23c606a --- /dev/null +++ b/src/designer/src/lib/sdk/abstractwidgetbox.cpp @@ -0,0 +1,340 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractwidgetbox.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QDesignerWidgetBoxInterface + + \brief The QDesignerWidgetBoxInterface class allows you to control + the contents of Qt Designer's widget box. + + \inmodule QtDesigner + + QDesignerWidgetBoxInterface contains a collection of functions + that is typically used to manipulate the contents of \QD's widget + box. + + \QD uses an XML file to populate its widget box. The name of that + file is one of the widget box's properties, and you can retrieve + it using the fileName() function. + + QDesignerWidgetBoxInterface also provides the save() function that + saves the contents of the widget box in the file specified by the + widget box's file name property. If you have made changes to the + widget box, for example by dropping a widget into the widget box, + without calling the save() function, the original content can be + restored by a simple invocation of the load() function: + + \snippet doc/src/snippets/code/tools_designer_src_lib_sdk_abstractwidgetbox.cpp 0 + + The QDesignerWidgetBoxInterface class is not intended to be + instantiated directly. You can retrieve an interface to Qt + Designer's widget box using the + QDesignerFormEditorInterface::widgetBox() function. A pointer to + \QD's current QDesignerFormEditorInterface object (\c formEditor + in the example above) is provided by the + QDesignerCustomWidgetInterface::initialize() function's + parameter. When implementing a custom widget plugin, you must + subclass the QDesignerCustomWidgetInterface to expose your plugin + to \QD. + + If you want to save your changes, and at the same time preserve + the original contents, you can use the save() function combined + with the setFileName() function to save your changes into another + file. Remember to store the name of the original file first: + + \snippet doc/src/snippets/code/tools_designer_src_lib_sdk_abstractwidgetbox.cpp 1 + + Then you can restore the original contents of the widget box by + resetting the file name to the original file and calling load(): + + \snippet doc/src/snippets/code/tools_designer_src_lib_sdk_abstractwidgetbox.cpp 2 + + In a similar way, you can later use your customized XML file: + + \snippet doc/src/snippets/code/tools_designer_src_lib_sdk_abstractwidgetbox.cpp 3 + + + \sa QDesignerFormEditorInterface +*/ + +/*! + Constructs a widget box interface with the given \a parent and + the specified window \a flags. +*/ +QDesignerWidgetBoxInterface::QDesignerWidgetBoxInterface(QWidget *parent, Qt::WindowFlags flags) + : QWidget(parent, flags) +{ +} + +/*! + Destroys the widget box interface. +*/ +QDesignerWidgetBoxInterface::~QDesignerWidgetBoxInterface() +{ +} + +/*! + \internal +*/ +int QDesignerWidgetBoxInterface::findOrInsertCategory(const QString &categoryName) +{ + int count = categoryCount(); + for (int index=0; index &item_list, const QPoint &global_mouse_pos) + +*/ + +/*! + \fn void QDesignerWidgetBoxInterface::setFileName(const QString &fileName) + + Sets the XML file that \QD will use to populate its widget box, to + \a fileName. You must call load() to update the widget box with + the new XML file. + + \sa fileName(), load() +*/ + +/*! + \fn QString QDesignerWidgetBoxInterface::fileName() const + + Returns the name of the XML file \QD is currently using to + populate its widget box. + + \sa setFileName() +*/ + +/*! + \fn bool QDesignerWidgetBoxInterface::load() + + Populates \QD's widget box by loading (or reloading) the currently + specified XML file. Returns true if the file is successfully + loaded; otherwise false. + + \sa setFileName() +*/ + +/*! + \fn bool QDesignerWidgetBoxInterface::save() + + Saves the contents of \QD's widget box in the file specified by + the fileName() function. Returns true if the content is + successfully saved; otherwise false. + + \sa fileName(), setFileName() +*/ + + +/*! + \internal + + \class QDesignerWidgetBoxInterface::Widget + + \brief The Widget class specified a widget in Qt Designer's widget + box component. +*/ + +/*! + \enum QDesignerWidgetBoxInterface::Widget::Type + + \value Default + \value Custom +*/ + +/*! + \fn QDesignerWidgetBoxInterface::Widget::Widget(const QString &aname, const QString &xml, const QString &icon_name, Type atype) +*/ + +/*! + \fn QString QDesignerWidgetBoxInterface::Widget::name() const +*/ + +/*! + \fn void QDesignerWidgetBoxInterface::Widget::setName(const QString &aname) +*/ + +/*! + \fn QString QDesignerWidgetBoxInterface::Widget::domXml() const +*/ + +/*! + \fn void QDesignerWidgetBoxInterface::Widget::setDomXml(const QString &xml) +*/ + +/*! + \fn QString QDesignerWidgetBoxInterface::Widget::iconName() const +*/ + +/*! + \fn void QDesignerWidgetBoxInterface::Widget::setIconName(const QString &icon_name) +*/ + +/*! + \fn Type QDesignerWidgetBoxInterface::Widget::type() const +*/ + +/*! + \fn void QDesignerWidgetBoxInterface::Widget::setType(Type atype) +*/ + +/*! + \fn bool QDesignerWidgetBoxInterface::Widget::isNull() const +*/ + + +/*! + \class QDesignerWidgetBoxInterface::Category + \brief The Category class specifies a category in Qt Designer's widget box component. + \internal +*/ + +/*! + \enum QDesignerWidgetBoxInterface::Category::Type + + \value Default + \value Scratchpad +*/ + +/*! + \fn QDesignerWidgetBoxInterface::Category::Category(const QString &aname, Type atype) +*/ + +/*! + \fn QString QDesignerWidgetBoxInterface::Category::name() const +*/ + +/*! + \fn void QDesignerWidgetBoxInterface::Category::setName(const QString &aname) +*/ + +/*! + \fn int QDesignerWidgetBoxInterface::Category::widgetCount() const +*/ + +/*! + \fn Widget QDesignerWidgetBoxInterface::Category::widget(int idx) const +*/ + +/*! + \fn void QDesignerWidgetBoxInterface::Category::removeWidget(int idx) +*/ + +/*! + \fn void QDesignerWidgetBoxInterface::Category::addWidget(const Widget &awidget) +*/ + +/*! + \fn Type QDesignerWidgetBoxInterface::Category::type() const +*/ + +/*! + \fn void QDesignerWidgetBoxInterface::Category::setType(Type atype) +*/ + +/*! + \fn bool QDesignerWidgetBoxInterface::Category::isNull() const +*/ + +/*! + \typedef QDesignerWidgetBoxInterface::CategoryList + \internal +*/ + +/*! + \typedef QDesignerWidgetBoxInterface::WidgetList + \internal +*/ + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/abstractwidgetbox.h b/src/designer/src/lib/sdk/abstractwidgetbox.h new file mode 100644 index 000000000..cf1cb1b2e --- /dev/null +++ b/src/designer/src/lib/sdk/abstractwidgetbox.h @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABSTRACTWIDGETBOX_H +#define ABSTRACTWIDGETBOX_H + +#include + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DomUI; +class QDesignerDnDItemInterface; + +class QDESIGNER_SDK_EXPORT QDesignerWidgetBoxInterface : public QWidget +{ + Q_OBJECT +public: + class Widget { + public: + enum Type { Default, Custom }; + Widget(const QString &aname = QString(), const QString &xml = QString(), + const QString &icon_name = QString(), Type atype = Default) + : m_name(aname), m_xml(xml), m_icon_name(icon_name), m_type(atype) {} + QString name() const { return m_name; } + void setName(const QString &aname) { m_name = aname; } + QString domXml() const { return m_xml; } + void setDomXml(const QString &xml) { m_xml = xml; } + QString iconName() const { return m_icon_name; } + void setIconName(const QString &icon_name) { m_icon_name = icon_name; } + Type type() const { return m_type; } + void setType(Type atype) { m_type = atype; } + + bool isNull() const { return m_name.isEmpty(); } + + private: + QString m_name; + QString m_xml; + QString m_icon_name; + Type m_type; + }; + typedef QList WidgetList; + + class Category { + public: + enum Type { Default, Scratchpad }; + + Category(const QString &aname = QString(), Type atype = Default) + : m_name(aname), m_type(atype) {} + + QString name() const { return m_name; } + void setName(const QString &aname) { m_name = aname; } + int widgetCount() const { return m_widget_list.size(); } + Widget widget(int idx) const { return m_widget_list.at(idx); } + void removeWidget(int idx) { m_widget_list.removeAt(idx); } + void addWidget(const Widget &awidget) { m_widget_list.append(awidget); } + Type type() const { return m_type; } + void setType(Type atype) { m_type = atype; } + + bool isNull() const { return m_name.isEmpty(); } + + private: + QString m_name; + Type m_type; + QList m_widget_list; + }; + typedef QList CategoryList; + + QDesignerWidgetBoxInterface(QWidget *parent = 0, Qt::WindowFlags flags = 0); + virtual ~QDesignerWidgetBoxInterface(); + + virtual int categoryCount() const = 0; + virtual Category category(int cat_idx) const = 0; + virtual void addCategory(const Category &cat) = 0; + virtual void removeCategory(int cat_idx) = 0; + + virtual int widgetCount(int cat_idx) const = 0; + virtual Widget widget(int cat_idx, int wgt_idx) const = 0; + virtual void addWidget(int cat_idx, const Widget &wgt) = 0; + virtual void removeWidget(int cat_idx, int wgt_idx) = 0; + + int findOrInsertCategory(const QString &categoryName); + + virtual void dropWidgets(const QList &item_list, + const QPoint &global_mouse_pos) = 0; + + virtual void setFileName(const QString &file_name) = 0; + virtual QString fileName() const = 0; + virtual bool load() = 0; + virtual bool save() = 0; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE(QDesignerWidgetBoxInterface::Widget)) + +QT_END_HEADER + +#endif // ABSTRACTWIDGETBOX_H diff --git a/src/designer/src/lib/sdk/abstractwidgetdatabase.cpp b/src/designer/src/lib/sdk/abstractwidgetdatabase.cpp new file mode 100644 index 000000000..f48b10030 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractwidgetdatabase.cpp @@ -0,0 +1,360 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractwidgetdatabase.h" +#include +#include + +QT_BEGIN_NAMESPACE + +namespace { + enum { debugWidgetDataBase = 0 }; +} + +/*! + \class QDesignerWidgetDataBaseInterface + \brief The QDesignerWidgetDataBaseInterface class provides an interface that is used to + access and modify Qt Designer's widget database. + \inmodule QtDesigner + \internal +*/ + +/*! + Constructs an interface to the widget database with the given \a parent. +*/ +QDesignerWidgetDataBaseInterface::QDesignerWidgetDataBaseInterface(QObject *parent) + : QObject(parent) +{ +} + +/*! + Destroys the interface to the widget database. +*/ +QDesignerWidgetDataBaseInterface::~QDesignerWidgetDataBaseInterface() +{ + qDeleteAll(m_items); +} + +/*! + +*/ +int QDesignerWidgetDataBaseInterface::count() const +{ + return m_items.count(); +} + +/*! +*/ +QDesignerWidgetDataBaseItemInterface *QDesignerWidgetDataBaseInterface::item(int index) const +{ + return index != -1 ? m_items.at(index) : 0; +} + +/*! +*/ +int QDesignerWidgetDataBaseInterface::indexOf(QDesignerWidgetDataBaseItemInterface *item) const +{ + return m_items.indexOf(item); +} + +/*! +*/ +void QDesignerWidgetDataBaseInterface::insert(int index, QDesignerWidgetDataBaseItemInterface *item) +{ + if (debugWidgetDataBase) + qDebug() << "insert at " << index << ' ' << item->name() << " derived from " << item->extends(); + + m_items.insert(index, item); +} + +/*! +*/ +void QDesignerWidgetDataBaseInterface::append(QDesignerWidgetDataBaseItemInterface *item) +{ + if (debugWidgetDataBase) + qDebug() << "append " << item->name() << " derived from " << item->extends(); + m_items.append(item); +} + +/*! +*/ +QDesignerFormEditorInterface *QDesignerWidgetDataBaseInterface::core() const +{ + return 0; +} + +/*! +*/ +int QDesignerWidgetDataBaseInterface::indexOfClassName(const QString &name, bool) const +{ + const int itemCount = count(); + for (int i=0; iname() == name) + return i; + } + + return -1; +} + +/*! +*/ +int QDesignerWidgetDataBaseInterface::indexOfObject(QObject *object, bool) const +{ + if (!object) + return -1; + + const QString className = QString::fromUtf8(object->metaObject()->className()); + return indexOfClassName(className); +} + +/*! +*/ +bool QDesignerWidgetDataBaseInterface::isContainer(QObject *object, bool resolveName) const +{ + if (const QDesignerWidgetDataBaseItemInterface *i = item(indexOfObject(object, resolveName))) + return i->isContainer(); + return false; +} + +/*! +*/ +bool QDesignerWidgetDataBaseInterface::isCustom(QObject *object, bool resolveName) const +{ + if (const QDesignerWidgetDataBaseItemInterface *i = item(indexOfObject(object, resolveName))) + return i->isCustom(); + return false; +} + +/*! + \fn void QDesignerWidgetDataBaseInterface::changed() + + This signal is emitted ... +*/ + + +// Doc: No implementation - an abstract class + +/*! + \class QDesignerWidgetDataBaseItemInterface + \brief The QDesignerWidgetDataBaseItemInterface class provides an interface that is used to + access individual items in Qt Designer's widget database. + \inmodule QtDesigner + \internal + + This class enables individual items in the widget database to be accessed and modified. + Changes to the widget database itself are made through the QDesignerWidgetDataBaseInterface + class. +*/ + +/*! + \fn virtual QDesignerWidgetDataBaseItemInterface::~QDesignerWidgetDataBaseItemInterface() + + Destroys the interface. +*/ + +/*! + \fn virtual QString QDesignerWidgetDataBaseItemInterface::name() const = 0 + + Returns the name of the widget. +*/ + +/*! + \fn virtual void QDesignerWidgetDataBaseItemInterface::setName(const QString &name) = 0 +*/ + +/*! + \fn virtual QString QDesignerWidgetDataBaseItemInterface::group() const = 0 + + Returns the name of the group that the widget belongs to. +*/ + +/*! + \fn virtual void QDesignerWidgetDataBaseItemInterface::setGroup(const QString &group) = 0 +*/ + +/*! + \fn virtual QString QDesignerWidgetDataBaseItemInterface::toolTip() const = 0 + + Returns the tool tip to be used by the widget. +*/ + +/*! + \fn virtual void QDesignerWidgetDataBaseItemInterface::setToolTip(const QString &toolTip) = 0 +*/ + +/*! + \fn virtual QString QDesignerWidgetDataBaseItemInterface::whatsThis() const = 0 + + Returns the "What's This?" help for the widget. +*/ + +/*! + \fn virtual void QDesignerWidgetDataBaseItemInterface::setWhatsThis(const QString &whatsThis) = 0 +*/ + +/*! + \fn virtual QString QDesignerWidgetDataBaseItemInterface::includeFile() const = 0 + + Returns the name of the include file that the widget needs when being built from source. +*/ + +/*! + \fn virtual void QDesignerWidgetDataBaseItemInterface::setIncludeFile(const QString &includeFile) = 0 +*/ + +/*! + \fn virtual QIcon QDesignerWidgetDataBaseItemInterface::icon() const = 0 + + Returns the icon used to represent the item. +*/ + +/*! + \fn virtual void QDesignerWidgetDataBaseItemInterface::setIcon(const QIcon &icon) = 0 +*/ + +/*! + \fn virtual bool QDesignerWidgetDataBaseItemInterface::isCompat() const = 0 + + Returns true if this type of widget is provided for compatibility purposes (e.g. Qt3Support + widgets); otherwise returns false. + + \sa setCompat() +*/ + +/*! + \fn virtual void QDesignerWidgetDataBaseItemInterface::setCompat(bool compat) = 0 + + If \a compat is true, the widget is handled as a compatibility widget; otherwise it is + handled normally by \QD. + + \sa isCompat() +*/ + +/*! + \fn virtual bool QDesignerWidgetDataBaseItemInterface::isContainer() const = 0 + + Returns true if this widget is intended to be used to hold other widgets; otherwise returns + false. + + \sa setContainer() +*/ + +/*! + \fn virtual void QDesignerWidgetDataBaseItemInterface::setContainer(bool container) = 0 + + If \a container is true, the widget can be used to hold other widgets in \QD; otherwise + \QD will refuse to let the user place other widgets inside it. + + \sa isContainer() +*/ + +/*! + \fn virtual bool QDesignerWidgetDataBaseItemInterface::isCustom() const = 0 + + Returns true if the widget is a custom widget; otherwise return false if it is a standard + Qt widget. + + \sa setCustom() +*/ + +/*! + \fn virtual void QDesignerWidgetDataBaseItemInterface::setCustom(bool custom) = 0 + + If \a custom is true, the widget is handled specially by \QD; otherwise it is handled as + a standard Qt widget. + + \sa isCustom() +*/ + +/*! + \fn virtual QString QDesignerWidgetDataBaseItemInterface::pluginPath() const = 0 + + Returns the path to use for the widget plugin. +*/ + +/*! + \fn virtual void QDesignerWidgetDataBaseItemInterface::setPluginPath(const QString &path) = 0 +*/ + +/*! + \fn virtual bool QDesignerWidgetDataBaseItemInterface::isPromoted() const = 0 + + Returns true if the widget is promoted; otherwise returns false. + + Promoted widgets are those that represent custom widgets, but which are represented in + \QD by either standard Qt widgets or readily-available custom widgets. + + \sa setPromoted() +*/ + +/*! + \fn virtual void QDesignerWidgetDataBaseItemInterface::setPromoted(bool promoted) = 0 + + If \a promoted is true, the widget is handled as a promoted widget by \QD and will use + a placeholder widget to represent it; otherwise it is handled as a standard widget. + + \sa isPromoted() +*/ + +/*! + \fn virtual QString QDesignerWidgetDataBaseItemInterface::extends() const = 0 + + Returns the name of the widget that the item extends. +*/ + +/*! + \fn virtual void QDesignerWidgetDataBaseItemInterface::setExtends(const QString &s) = 0 +*/ + +/*! + \fn virtual void QDesignerWidgetDataBaseItemInterface::setDefaultPropertyValues(const QList &list) = 0 + + Sets the default property values for the widget to the given \a list. +*/ + +/*! + \fn virtual QList QDesignerWidgetDataBaseItemInterface::defaultPropertyValues() const = 0 + + Returns a list of default values to be used as properties for the item. +*/ + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/abstractwidgetdatabase.h b/src/designer/src/lib/sdk/abstractwidgetdatabase.h new file mode 100644 index 000000000..7ea5db8a1 --- /dev/null +++ b/src/designer/src/lib/sdk/abstractwidgetdatabase.h @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABSTRACTWIDGETDATABASE_H +#define ABSTRACTWIDGETDATABASE_H + +#include + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QIcon; +class QString; +class QDesignerFormEditorInterface; +class QDebug; + +class QDesignerWidgetDataBaseItemInterface +{ +public: + virtual ~QDesignerWidgetDataBaseItemInterface() {} + + virtual QString name() const = 0; + virtual void setName(const QString &name) = 0; + + virtual QString group() const = 0; + virtual void setGroup(const QString &group) = 0; + + virtual QString toolTip() const = 0; + virtual void setToolTip(const QString &toolTip) = 0; + + virtual QString whatsThis() const = 0; + virtual void setWhatsThis(const QString &whatsThis) = 0; + + virtual QString includeFile() const = 0; + virtual void setIncludeFile(const QString &includeFile) = 0; + + virtual QIcon icon() const = 0; + virtual void setIcon(const QIcon &icon) = 0; + + virtual bool isCompat() const = 0; + virtual void setCompat(bool compat) = 0; + + virtual bool isContainer() const = 0; + virtual void setContainer(bool container) = 0; + + virtual bool isCustom() const = 0; + virtual void setCustom(bool custom) = 0; + + virtual QString pluginPath() const = 0; + virtual void setPluginPath(const QString &path) = 0; + + virtual bool isPromoted() const = 0; + virtual void setPromoted(bool b) = 0; + + virtual QString extends() const = 0; + virtual void setExtends(const QString &s) = 0; + + virtual void setDefaultPropertyValues(const QList &list) = 0; + virtual QList defaultPropertyValues() const = 0; +}; + +class QDESIGNER_SDK_EXPORT QDesignerWidgetDataBaseInterface: public QObject +{ + Q_OBJECT +public: + QDesignerWidgetDataBaseInterface(QObject *parent = 0); + virtual ~QDesignerWidgetDataBaseInterface(); + + virtual int count() const; + virtual QDesignerWidgetDataBaseItemInterface *item(int index) const; + + virtual int indexOf(QDesignerWidgetDataBaseItemInterface *item) const; + virtual void insert(int index, QDesignerWidgetDataBaseItemInterface *item); + virtual void append(QDesignerWidgetDataBaseItemInterface *item); + + virtual int indexOfObject(QObject *object, bool resolveName = true) const; + virtual int indexOfClassName(const QString &className, bool resolveName = true) const; + + virtual QDesignerFormEditorInterface *core() const; + + bool isContainer(QObject *object, bool resolveName = true) const; + bool isCustom(QObject *object, bool resolveName = true) const; + +Q_SIGNALS: + void changed(); + +protected: + QList m_items; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ABSTRACTWIDGETDATABASE_H diff --git a/src/designer/src/lib/sdk/abstractwidgetfactory.cpp b/src/designer/src/lib/sdk/abstractwidgetfactory.cpp new file mode 100644 index 000000000..769db175c --- /dev/null +++ b/src/designer/src/lib/sdk/abstractwidgetfactory.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "abstractformeditor.h" +#include "abstractwidgetdatabase.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QDesignerWidgetFactoryInterface + \brief The QDesignerWidgetFactoryInterface class provides an interface that is used to control + the widget factory used by Qt Designer. + \inmodule QtDesigner + \internal +*/ + +/*! + \fn QDesignerWidgetFactoryInterface::QDesignerWidgetFactoryInterface(QObject *parent) + + Constructs an interface to a widget factory with the given \a parent. +*/ +QDesignerWidgetFactoryInterface::QDesignerWidgetFactoryInterface(QObject *parent) + : QObject(parent) +{ +} + +/*! + \fn virtual QDesignerWidgetFactoryInterface::~QDesignerWidgetFactoryInterface() +*/ +QDesignerWidgetFactoryInterface::~QDesignerWidgetFactoryInterface() +{ +} + +/*! + \fn virtual QDesignerFormEditorInterface *QDesignerWidgetFactoryInterface::core() const = 0 + + Returns the core form editor interface associated with this interface. +*/ + +/*! + \fn virtual QWidget* QDesignerWidgetFactoryInterface::containerOfWidget(QWidget *child) const = 0 + + Returns the widget that contains the specified \a child widget. +*/ + +/*! + \fn virtual QWidget* QDesignerWidgetFactoryInterface::widgetOfContainer(QWidget *container) const = 0 + + +*/ + +/*! + \fn virtual QWidget *QDesignerWidgetFactoryInterface::createWidget(const QString &name, QWidget *parent) const = 0 + + Returns a new widget with the given \a name and \a parent widget. If no parent is specified, + the widget created will be a top-level widget. +*/ + +/*! + \fn virtual QLayout *QDesignerWidgetFactoryInterface::createLayout(QWidget *widget, QLayout *layout, int type) const = 0 + + Returns a new layout of the specified \a type for the given \a widget or \a layout. +*/ + +/*! + \fn virtual bool QDesignerWidgetFactoryInterface::isPassiveInteractor(QWidget *widget) = 0 +*/ + +/*! + \fn virtual void QDesignerWidgetFactoryInterface::initialize(QObject *object) const = 0 +*/ + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/abstractwidgetfactory.h b/src/designer/src/lib/sdk/abstractwidgetfactory.h new file mode 100644 index 000000000..a5c2ab16d --- /dev/null +++ b/src/designer/src/lib/sdk/abstractwidgetfactory.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ABSTRACTWIDGETFACTORY_H +#define ABSTRACTWIDGETFACTORY_H + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QWidget; +class QLayout; + +class QDESIGNER_SDK_EXPORT QDesignerWidgetFactoryInterface: public QObject +{ + Q_OBJECT +public: + QDesignerWidgetFactoryInterface(QObject *parent = 0); + virtual ~QDesignerWidgetFactoryInterface(); + + virtual QDesignerFormEditorInterface *core() const = 0; + + virtual QWidget* containerOfWidget(QWidget *w) const = 0; + virtual QWidget* widgetOfContainer(QWidget *w) const = 0; + + virtual QWidget *createWidget(const QString &name, QWidget *parentWidget = 0) const = 0; + virtual QLayout *createLayout(QWidget *widget, QLayout *layout, int type) const = 0; + + virtual bool isPassiveInteractor(QWidget *widget) = 0; + virtual void initialize(QObject *object) const = 0; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // ABSTRACTWIDGETFACTORY_H diff --git a/src/designer/src/lib/sdk/dynamicpropertysheet.h b/src/designer/src/lib/sdk/dynamicpropertysheet.h new file mode 100644 index 000000000..478f3a4a6 --- /dev/null +++ b/src/designer/src/lib/sdk/dynamicpropertysheet.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef DYNAMICPROPERTYSHEET_H +#define DYNAMICPROPERTYSHEET_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QString; // FIXME: fool syncqt + +class QDesignerDynamicPropertySheetExtension +{ +public: + virtual ~QDesignerDynamicPropertySheetExtension() {} + + virtual bool dynamicPropertiesAllowed() const = 0; + virtual int addDynamicProperty(const QString &propertyName, const QVariant &value) = 0; + virtual bool removeDynamicProperty(int index) = 0; + virtual bool isDynamicProperty(int index) const = 0; + virtual bool canAddDynamicProperty(const QString &propertyName) const = 0; +}; +Q_DECLARE_EXTENSION_INTERFACE(QDesignerDynamicPropertySheetExtension, "com.trolltech.Qt.Designer.DynamicPropertySheet") + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // DYNAMICPROPERTYSHEET_H diff --git a/src/designer/src/lib/sdk/dynamicpropertysheet.qdoc b/src/designer/src/lib/sdk/dynamicpropertysheet.qdoc new file mode 100644 index 000000000..e077e714d --- /dev/null +++ b/src/designer/src/lib/sdk/dynamicpropertysheet.qdoc @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QDesignerDynamicPropertySheetExtension + + \brief The QDesignerDynamicPropertySheetExtension class allows you to + manipulate a widget's dynamic properties in Qt Designer's property editor. + + \sa QDesignerPropertySheetExtension, {QObject#Dynamic Properties}{Dynamic Properties} + + \inmodule QtDesigner + \since 4.3 +*/ + +/*! + \fn QDesignerDynamicPropertySheetExtension::~QDesignerDynamicPropertySheetExtension() + + Destroys the dynamic property sheet extension. +*/ + +/*! + \fn bool QDesignerDynamicPropertySheetExtension::dynamicPropertiesAllowed() const + + Returns true if the widget supports dynamic properties; otherwise returns false. +*/ + +/*! + \fn int QDesignerDynamicPropertySheetExtension::addDynamicProperty(const QString &propertyName, const QVariant &value) + + Adds a dynamic property named \a propertyName and sets its value to \a value. + Returns the index of the property if it was added successfully; otherwise returns -1 to + indicate failure. +*/ + +/*! + \fn bool QDesignerDynamicPropertySheetExtension::removeDynamicProperty(int index) + + Removes the dynamic property at the given \a index. + Returns true if the operation succeeds; otherwise returns false. +*/ + +/*! + \fn bool QDesignerDynamicPropertySheetExtension::isDynamicProperty(int index) const + + Returns true if the property at the given \a index is a dynamic property; otherwise + returns false. +*/ + +/*! + \fn bool QDesignerDynamicPropertySheetExtension::canAddDynamicProperty(const QString &propertyName) const + + Returns true if \a propertyName is a valid, unique name for a dynamic + property; otherwise returns false. + +*/ diff --git a/src/designer/src/lib/sdk/extrainfo.cpp b/src/designer/src/lib/sdk/extrainfo.cpp new file mode 100644 index 000000000..9c272dc16 --- /dev/null +++ b/src/designer/src/lib/sdk/extrainfo.cpp @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "extrainfo.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QDesignerExtraInfoExtension + \brief The QDesignerExtraInfoExtension class provides extra information about a widget in + Qt Designer. + \inmodule QtDesigner + \internal +*/ + +/*! + Returns the path to the working directory used by this extension.*/ +QString QDesignerExtraInfoExtension::workingDirectory() const +{ + return m_workingDirectory; +} + +/*! + Sets the path to the working directory used by the extension to \a workingDirectory.*/ +void QDesignerExtraInfoExtension::setWorkingDirectory(const QString &workingDirectory) +{ + m_workingDirectory = workingDirectory; +} + +/*! + \fn virtual QDesignerExtraInfoExtension::~QDesignerExtraInfoExtension() + + Destroys the extension. +*/ + +/*! + \fn virtual QDesignerFormEditorInterface *QDesignerExtraInfoExtension::core() const = 0 + + \omit + ### Description required + \endomit +*/ + +/*! + \fn virtual QWidget *QDesignerExtraInfoExtension::widget() const = 0 + + Returns the widget described by this extension. +*/ + +/*! + \fn virtual bool QDesignerExtraInfoExtension::saveUiExtraInfo(DomUI *ui) = 0 + + Saves the information about the user interface specified by \a ui, and returns true if + successful; otherwise returns false. +*/ + +/*! + \fn virtual bool QDesignerExtraInfoExtension::loadUiExtraInfo(DomUI *ui) = 0 + + Loads extra information about the user interface specified by \a ui, and returns true if + successful; otherwise returns false. +*/ + +/*! + \fn virtual bool QDesignerExtraInfoExtension::saveWidgetExtraInfo(DomWidget *widget) = 0 + + Saves the information about the specified \a widget, and returns true if successful; + otherwise returns false. +*/ + +/*! + \fn virtual bool QDesignerExtraInfoExtension::loadWidgetExtraInfo(DomWidget *widget) = 0 + + Loads extra information about the specified \a widget, and returns true if successful; + otherwise returns false. +*/ + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/extrainfo.h b/src/designer/src/lib/sdk/extrainfo.h new file mode 100644 index 000000000..10034e9a6 --- /dev/null +++ b/src/designer/src/lib/sdk/extrainfo.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef EXTRAINFO_H +#define EXTRAINFO_H + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DomWidget; +class DomUI; +class QWidget; + +class QDesignerFormEditorInterface; + +class QDESIGNER_SDK_EXPORT QDesignerExtraInfoExtension +{ +public: + virtual ~QDesignerExtraInfoExtension() {} + + virtual QDesignerFormEditorInterface *core() const = 0; + virtual QWidget *widget() const = 0; + + virtual bool saveUiExtraInfo(DomUI *ui) = 0; + virtual bool loadUiExtraInfo(DomUI *ui) = 0; + + virtual bool saveWidgetExtraInfo(DomWidget *ui_widget) = 0; + virtual bool loadWidgetExtraInfo(DomWidget *ui_widget) = 0; + + QString workingDirectory() const; + void setWorkingDirectory(const QString &workingDirectory); + +private: + QString m_workingDirectory; +}; +Q_DECLARE_EXTENSION_INTERFACE(QDesignerExtraInfoExtension, "com.trolltech.Qt.Designer.ExtraInfo.2") + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // EXTRAINFO_H diff --git a/src/designer/src/lib/sdk/layoutdecoration.h b/src/designer/src/lib/sdk/layoutdecoration.h new file mode 100644 index 000000000..4a6577059 --- /dev/null +++ b/src/designer/src/lib/sdk/layoutdecoration.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef LAYOUTDECORATION_H +#define LAYOUTDECORATION_H + +#include + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QPoint; +class QLayoutItem; +class QWidget; +class QRect; +class QLayout; + +class QDesignerLayoutDecorationExtension +{ +public: + enum InsertMode + { + InsertWidgetMode, + InsertRowMode, + InsertColumnMode + }; + + virtual ~QDesignerLayoutDecorationExtension() {} + + virtual QList widgets(QLayout *layout) const = 0; + + virtual QRect itemInfo(int index) const = 0; + virtual int indexOf(QWidget *widget) const = 0; + virtual int indexOf(QLayoutItem *item) const = 0; + + virtual InsertMode currentInsertMode() const = 0; + virtual int currentIndex() const = 0; + virtual QPair currentCell() const = 0; + virtual void insertWidget(QWidget *widget, const QPair &cell) = 0; + virtual void removeWidget(QWidget *widget) = 0; + + virtual void insertRow(int row) = 0; + virtual void insertColumn(int column) = 0; + virtual void simplify() = 0; + + virtual int findItemAt(const QPoint &pos) const = 0; + virtual int findItemAt(int row, int column) const = 0; // atm only for grid. + + virtual void adjustIndicator(const QPoint &pos, int index) = 0; +}; +Q_DECLARE_EXTENSION_INTERFACE(QDesignerLayoutDecorationExtension, "com.trolltech.Qt.Designer.LayoutDecoration") + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // LAYOUTDECORATION_H diff --git a/src/designer/src/lib/sdk/layoutdecoration.qdoc b/src/designer/src/lib/sdk/layoutdecoration.qdoc new file mode 100644 index 000000000..9456e380d --- /dev/null +++ b/src/designer/src/lib/sdk/layoutdecoration.qdoc @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QDesignerLayoutDecorationExtension + \brief The QDesignerLayoutDecorationExtension class provides an extension to a layout in \QD. + \inmodule QtDesigner + \internal +*/ + +/*! + \enum QDesignerLayoutDecorationExtension::InsertMode + + This enum describes the modes that are used to insert items into a layout. + + \value InsertWidgetMode Widgets are inserted into empty cells in a layout. + \value InsertRowMode Whole rows are inserted into a vertical or grid layout. + \value InsertColumnMode Whole columns are inserted into a horizontal or grid layout. +*/ + +/*! + \fn virtual QDesignerLayoutDecorationExtension::~QDesignerLayoutDecorationExtension() + + Destroys the extension. +*/ + +/*! + \fn virtual QList QDesignerLayoutDecorationExtension::widgets(QLayout *layout) const + + Returns the widgets that are managed by the given \a layout. + + \sa insertWidget(), removeWidget() +*/ + +/*! + \fn QRect QDesignerLayoutDecorationExtension::itemInfo(int index) const + + Returns the rectangle covered by the item at the given \a index in the layout. +*/ + +/*! + \fn int QDesignerLayoutDecorationExtension::indexOf(QWidget *widget) const + + Returns the index of the specified \a widget in the layout. +*/ + +/*! + \fn int QDesignerLayoutDecorationExtension::indexOf(QLayoutItem *item) const + + Returns the index of the specified layout \a item. +*/ + +/*! + \fn QDesignerLayoutDecorationExtension::InsertMode QDesignerLayoutDecorationExtension::currentInsertMode() const + + Returns the current insertion mode. +*/ + +/*! + \fn int QDesignerLayoutDecorationExtension::currentIndex() const + + Returns the current index in the layout. +*/ + +/*! + \fn QPair QDesignerLayoutDecorationExtension::currentCell() const + + Returns a pair containing the row and column of the current cell in the layout. +*/ + +/*! + \fn void QDesignerLayoutDecorationExtension::insertWidget(QWidget *widget, const QPair &cell) + + Inserts the given \a widget into the specified \a cell in the layout. + + \sa removeWidget() +*/ + +/*! + \fn void QDesignerLayoutDecorationExtension::removeWidget(QWidget *widget) + + Removes the specified \a widget from the layout. + + \sa insertWidget() +*/ + +/*! + \fn void QDesignerLayoutDecorationExtension::insertRow(int row) + + Inserts a new row into the form at the position specified by \a row. +*/ + +/*! + \fn void QDesignerLayoutDecorationExtension::insertColumn(int column) + + Inserts a new column into the form at the position specified by \a column. +*/ + +/*! + \fn void QDesignerLayoutDecorationExtension::simplify() + + Simplifies the layout by removing unnecessary empty rows and columns, and by changing the + number of rows or columns spanned by widgets. +*/ + +/*! + \fn int QDesignerLayoutDecorationExtension::findItemAt(const QPoint &position) const + + Returns the index of the item in the layout that covers the given \a position. +*/ + +/*! + \fn int QDesignerLayoutDecorationExtension::findItemAt(int row, int column) const + + Returns the item in the layout that occupies the specified \a row and \a column in the layout. + + Currently, this only applies to grid layouts. +*/ + +/*! + \fn void QDesignerLayoutDecorationExtension::adjustIndicator(const QPoint &position, int index) + + Adjusts the indicator for the item specified by \a index so that + it lies at the given \a position on the form. +*/ diff --git a/src/designer/src/lib/sdk/membersheet.h b/src/designer/src/lib/sdk/membersheet.h new file mode 100644 index 000000000..b1ff1a4c6 --- /dev/null +++ b/src/designer/src/lib/sdk/membersheet.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MEMBERSHEET_H +#define MEMBERSHEET_H + +#include + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QString; // FIXME: fool syncqt + +class QDesignerMemberSheetExtension +{ +public: + virtual ~QDesignerMemberSheetExtension() {} + + virtual int count() const = 0; + + virtual int indexOf(const QString &name) const = 0; + + virtual QString memberName(int index) const = 0; + virtual QString memberGroup(int index) const = 0; + virtual void setMemberGroup(int index, const QString &group) = 0; + + virtual bool isVisible(int index) const = 0; + virtual void setVisible(int index, bool b) = 0; + + virtual bool isSignal(int index) const = 0; + virtual bool isSlot(int index) const = 0; + + virtual bool inheritedFromWidget(int index) const = 0; + + virtual QString declaredInClass(int index) const = 0; + + virtual QString signature(int index) const = 0; + virtual QList parameterTypes(int index) const = 0; + virtual QList parameterNames(int index) const = 0; +}; +Q_DECLARE_EXTENSION_INTERFACE(QDesignerMemberSheetExtension, "com.trolltech.Qt.Designer.MemberSheet") + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // MEMBERSHEET_H diff --git a/src/designer/src/lib/sdk/membersheet.qdoc b/src/designer/src/lib/sdk/membersheet.qdoc new file mode 100644 index 000000000..57a366407 --- /dev/null +++ b/src/designer/src/lib/sdk/membersheet.qdoc @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QDesignerMemberSheetExtension + + \brief The QDesignerMemberSheetExtension class allows you to + manipulate a widget's member functions which is displayed when + configuring connections using Qt Designer's mode for editing + signals and slots. + + \inmodule QtDesigner + + QDesignerMemberSheetExtension is a collection of functions that is + typically used to query a widget's member functions, and to + manipulate the member functions' appearance in \QD's signals and + slots editing mode. For example: + + \snippet doc/src/snippets/code/doc_src_qtdesigner.cpp 2 + + When implementing a custom widget plugin, a pointer to \QD's + current QDesignerFormEditorInterface object (\c formEditor in the + example above) is provided by the + QDesignerCustomWidgetInterface::initialize() function's parameter. + + The member sheet (and any other extension), can be retrieved by + querying \QD's extension manager using the qt_extension() + function. When you want to release the extension, you only need to + delete the pointer. + + All widgets have a default member sheet used in \QD's signals and + slots editing mode with the widget's member functions. But + QDesignerMemberSheetExtension also provides an interface for + creating custom member sheet extensions. + + \warning \QD uses the QDesignerMemberSheetExtension to facilitate + the signal and slot editing mode. Whenever a connection between + two widgets is requested, \QD will query for the widgets' member + sheet extensions. If a widget has an implemented member sheet + extension, this extension will override the default member sheet. + + To create a member sheet extension, your extension class must + inherit from both QObject and QDesignerMemberSheetExtension. Then, + since we are implementing an interface, we must ensure that it's + made known to the meta object system using the Q_INTERFACES() + macro: + + \snippet doc/src/snippets/code/doc_src_qtdesigner.cpp 3 + + This enables \QD to use qobject_cast() to query for + supported interfaces using nothing but a QObject pointer. + + In \QD the extensions are not created until they are + required. For that reason, when implementing a member sheet + extension, you must also create a QExtensionFactory, i.e a class + that is able to make an instance of your extension, and register + it using \QD's \l {QExtensionManager}{extension manager}. + + When a widget's member sheet extension is required, \QD's \l + {QExtensionManager}{extension manager} will run through all its + registered factories calling QExtensionFactory::createExtension() + for each until the first one that is able to create a member sheet + extension for that widget, is found. This factory will then make + an instance of the extension. If no such factory is found, \QD + will use the default member sheet. + + There are four available types of extensions in \QD: + QDesignerContainerExtension, QDesignerMemberSheetExtension, + QDesignerPropertySheetExtension and + QDesignerTaskMenuExtension. \QD's behavior is the same whether the + requested extension is associated with a multi page container, a + member sheet, a property sheet or a task menu. + + The QExtensionFactory class provides a standard extension + factory, and can also be used as an interface for custom + extension factories. You can either create a new + QExtensionFactory and reimplement the + QExtensionFactory::createExtension() function. For example: + + \snippet doc/src/snippets/code/doc_src_qtdesigner.cpp 4 + + Or you can use an existing factory, expanding the + QExtensionFactory::createExtension() function to make the factory + able to create a member sheet extension as well. For example: + + \snippet doc/src/snippets/code/doc_src_qtdesigner.cpp 5 + + For a complete example using an extension class, see \l + {designer/taskmenuextension}{Task Menu Extension example}. The + example shows how to create a custom widget plugin for Qt + Designer, and how to to use the QDesignerTaskMenuExtension class + to add custom items to \QD's task menu. + + \sa QExtensionFactory, QExtensionManager, {Creating Custom Widget + Extensions} +*/ + +/*! + \fn QDesignerMemberSheetExtension::~QDesignerMemberSheetExtension() + + Destroys the member sheet extension. +*/ + +/*! + \fn int QDesignerMemberSheetExtension::count() const + + Returns the extension's number of member functions. +*/ + +/*! + \fn int QDesignerMemberSheetExtension::indexOf(const QString &name) const + + Returns the index of the member function specified by the given \a + name. + + \sa memberName() +*/ + +/*! + \fn QString QDesignerMemberSheetExtension::memberName(int index) const + + Returns the name of the member function with the given \a index. + + \sa indexOf() +*/ + +/*! + \fn QString QDesignerMemberSheetExtension::memberGroup(int index) const + + Returns the name of the member group specified for the function + with the given \a index. + + \sa indexOf(), setMemberGroup() +*/ + +/*! + \fn void QDesignerMemberSheetExtension::setMemberGroup(int index, const QString &group) + + Sets the member group of the member function with the given \a + index, to \a group. + + \sa indexOf(), memberGroup() +*/ + +/*! + \fn bool QDesignerMemberSheetExtension::isVisible(int index) const + + Returns true if the member function with the given \a index is + visible in \QD's signal and slot editor, otherwise false. + + \sa indexOf(), setVisible() +*/ + +/*! + \fn void QDesignerMemberSheetExtension::setVisible(int index, bool visible) + + If \a visible is true, the member function with the given \a index + is visible in \QD's signals and slots editing mode; otherwise the + member function is hidden. + + \sa indexOf(), isVisible() +*/ + +/*! + \fn virtual bool QDesignerMemberSheetExtension::isSignal(int index) const + + Returns true if the member function with the given \a index is a + signal, otherwise false. + + \sa indexOf() +*/ + +/*! + \fn bool QDesignerMemberSheetExtension::isSlot(int index) const + + Returns true if the member function with the given \a index is a + slot, otherwise false. + + \sa indexOf() +*/ + +/*! + \fn bool QDesignerMemberSheetExtension::inheritedFromWidget(int index) const + + Returns true if the member function with the given \a index is + inherited from QWidget, otherwise false. + + \sa indexOf() +*/ + +/*! + \fn QString QDesignerMemberSheetExtension::declaredInClass(int index) const + + Returns the name of the class in which the member function with + the given \a index is declared. + + \sa indexOf() +*/ + +/*! + \fn QString QDesignerMemberSheetExtension::signature(int index) const + + Returns the signature of the member function with the given \a + index. + + \sa indexOf() +*/ + +/*! + \fn QList QDesignerMemberSheetExtension::parameterTypes(int index) const + + Returns the parameter types of the member function with the given + \a index, as a QByteArray list. + + \sa indexOf(), parameterNames() +*/ + +/*! + \fn QList QDesignerMemberSheetExtension::parameterNames(int index) const + + Returns the parameter names of the member function with the given + \a index, as a QByteArray list. + + \sa indexOf(), parameterTypes() +*/ diff --git a/src/designer/src/lib/sdk/propertysheet.h b/src/designer/src/lib/sdk/propertysheet.h new file mode 100644 index 000000000..36a0e4e1b --- /dev/null +++ b/src/designer/src/lib/sdk/propertysheet.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PROPERTYSHEET_H +#define PROPERTYSHEET_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QVariant; + +class QDesignerPropertySheetExtension +{ +public: + virtual ~QDesignerPropertySheetExtension() {} + + virtual int count() const = 0; + + virtual int indexOf(const QString &name) const = 0; + + virtual QString propertyName(int index) const = 0; + virtual QString propertyGroup(int index) const = 0; + virtual void setPropertyGroup(int index, const QString &group) = 0; + + virtual bool hasReset(int index) const = 0; + virtual bool reset(int index) = 0; + + virtual bool isVisible(int index) const = 0; + virtual void setVisible(int index, bool b) = 0; + + virtual bool isAttribute(int index) const = 0; + virtual void setAttribute(int index, bool b) = 0; + + virtual QVariant property(int index) const = 0; + virtual void setProperty(int index, const QVariant &value) = 0; + + virtual bool isChanged(int index) const = 0; + virtual void setChanged(int index, bool changed) = 0; + +}; + +Q_DECLARE_EXTENSION_INTERFACE(QDesignerPropertySheetExtension, + "com.trolltech.Qt.Designer.PropertySheet") + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // PROPERTYSHEET_H diff --git a/src/designer/src/lib/sdk/propertysheet.qdoc b/src/designer/src/lib/sdk/propertysheet.qdoc new file mode 100644 index 000000000..becc74b0e --- /dev/null +++ b/src/designer/src/lib/sdk/propertysheet.qdoc @@ -0,0 +1,288 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QDesignerPropertySheetExtension + + \brief The QDesignerPropertySheetExtension class allows you to + manipulate a widget's properties which is displayed in Qt + Designer's property editor. + + \sa QDesignerDynamicPropertySheetExtension + + \inmodule QtDesigner + + QDesignerPropertySheetExtension provides a collection of functions that + are typically used to query a widget's properties, and to + manipulate the properties' appearance in the property editor. For + example: + + \snippet doc/src/snippets/code/doc_src_qtdesigner.cpp 15 + + Note that if you change the value of a property using the + QDesignerPropertySheetExtension::setProperty() function, the undo + stack is not updated. To ensure that a property's value can be + reverted using the undo stack, you must use the + QDesignerFormWindowCursorInterface::setProperty() function, or its + buddy \l + {QDesignerFormWindowCursorInterface::setWidgetProperty()}{setWidgetProperty()}, + instead. + + When implementing a custom widget plugin, a pointer to \QD's + current QDesignerFormEditorInterface object (\c formEditor in the + example above) is provided by the + QDesignerCustomWidgetInterface::initialize() function's parameter. + + The property sheet, or any other extension, can be retrieved by + querying \QD's extension manager using the qt_extension() + function. When you want to release the extension, you only need to + delete the pointer. + + All widgets have a default property sheet which populates \QD's + property editor with the widget's properties (i.e the ones defined + with the Q_PROPERTY() macro). But QDesignerPropertySheetExtension + also provides an interface for creating custom property sheet + extensions. + + \warning \QD uses the QDesignerPropertySheetExtension to feed its + property editor. Whenever a widget is selected in its workspace, + \QD will query for the widget's property sheet extension. If the + selected widget has an implemented property sheet extension, this + extension will override the default property sheet. + + To create a property sheet extension, your extension class must + inherit from both QObject and + QDesignerPropertySheetExtension. Then, since we are implementing + an interface, we must ensure that it's made known to the meta + object system using the Q_INTERFACES() macro: + + \snippet doc/src/snippets/code/doc_src_qtdesigner.cpp 16 + + This enables \QD to use qobject_cast() to query for supported + interfaces using nothing but a QObject pointer. + + In \QD the extensions are not created until they are + required. For that reason, when implementing a property sheet + extension, you must also create a QExtensionFactory, i.e a class + that is able to make an instance of your extension, and register + it using \QD's \l {QExtensionManager}{extension manager}. + + When a property sheet extension is required, \QD's \l + {QExtensionManager}{extension manager} will run through all its + registered factories calling QExtensionFactory::createExtension() + for each until the first one that is able to create a property + sheet extension for the selected widget, is found. This factory + will then make an instance of the extension. If no such factory + can be found, \QD will use the default property sheet. + + There are four available types of extensions in \QD: + QDesignerContainerExtension, QDesignerMemberSheetExtension, + QDesignerPropertySheetExtension and QDesignerTaskMenuExtension. Qt + Designer's behavior is the same whether the requested extension is + associated with a multi page container, a member sheet, a property + sheet or a task menu. + + The QExtensionFactory class provides a standard extension factory, + and can also be used as an interface for custom extension + factories. You can either create a new QExtensionFactory and + reimplement the QExtensionFactory::createExtension() function. For + example: + + \snippet doc/src/snippets/code/doc_src_qtdesigner.cpp 17 + + Or you can use an existing factory, expanding the + QExtensionFactory::createExtension() function to make the factory + able to create a property sheet extension extension as well. For + example: + + \snippet doc/src/snippets/code/doc_src_qtdesigner.cpp 18 + + For a complete example using an extension class, see the \l + {designer/taskmenuextension}{Task Menu Extension example}. The + example shows how to create a custom widget plugin for Qt + Designer, and how to to use the QDesignerTaskMenuExtension class + to add custom items to \QD's task menu. + + \sa QExtensionFactory, QExtensionManager, {Creating Custom Widget + Extensions} +*/ + +/*! + \fn QDesignerPropertySheetExtension::~QDesignerPropertySheetExtension() + + Destroys the property sheet extension. +*/ + +/*! + \fn int QDesignerPropertySheetExtension::count() const + + Returns the selected widget's number of properties. +*/ + +/*! + \fn int QDesignerPropertySheetExtension::indexOf(const QString &name) const + + Returns the index for a given property \a name. + + \sa propertyName() +*/ + +/*! + \fn QString QDesignerPropertySheetExtension::propertyName(int index) const + + Returns the name of the property at the given \a index. + + \sa indexOf() +*/ + +/*! + \fn QString QDesignerPropertySheetExtension::propertyGroup(int index) const + + Returns the property group for the property at the given \a index. + + \QD's property editor supports property groups, i.e. sections of + related properties. A property can be related to a group using the + setPropertyGroup() function. The default group of any property is + the name of the class that defines it. For example, the + QObject::objectName property appears within the QObject property + group. + + \sa indexOf(), setPropertyGroup() +*/ + +/*! + \fn void QDesignerPropertySheetExtension::setPropertyGroup(int index, const QString &group) + + Sets the property group for the property at the given \a index to + \a group. + + Relating a property to a group makes it appear within that group's + section in the property editor. The default property group of any + property is the name of the class that defines it. For example, + the QObject::objectName property appears within the QObject + property group. + + \sa indexOf(), property(), propertyGroup() +*/ + +/*! + \fn bool QDesignerPropertySheetExtension::hasReset(int index) const + + Returns true if the property at the given \a index has a reset + button in \QD's property editor, otherwise false. + + \sa indexOf(), reset() +*/ + +/*! + \fn bool QDesignerPropertySheetExtension::reset(int index) + + Resets the value of the property at the given \a index, to the + default value. Returns true if a default value could be found, otherwise false. + + \sa indexOf(), hasReset(), isChanged() +*/ + +/*! + \fn bool QDesignerPropertySheetExtension::isVisible(int index) const + + Returns true if the property at the given \a index is visible in + \QD's property editor, otherwise false. + + \sa indexOf(), setVisible() +*/ + +/*! + \fn void QDesignerPropertySheetExtension::setVisible(int index, bool visible) + + If \a visible is true, the property at the given \a index is + visible in \QD's property editor; otherwise the property is + hidden. + + \sa indexOf(), isVisible() +*/ + +/*! + \fn bool QDesignerPropertySheetExtension::isAttribute(int index) const + + Returns true if the property at the given \a index is an attribute, + which will be \e excluded from the UI file, otherwise false. + + \sa indexOf(), setAttribute() +*/ + +/*! + \fn void QDesignerPropertySheetExtension::setAttribute(int index, bool attribute) + + If \a attribute is true, the property at the given \a index is + made an attribute which will be \e excluded from the UI file; + otherwise it will be included. + + \sa indexOf(), isAttribute() +*/ + +/*! + \fn QVariant QDesignerPropertySheetExtension::property(int index) const + + Returns the value of the property at the given \a index. + + \sa indexOf(), setProperty(), propertyGroup() +*/ + +/*! + \fn void QDesignerPropertySheetExtension::setProperty(int index, const QVariant &value) + + Sets the \a value of the property at the given \a index. + + \warning If you change the value of a property using this + function, the undo stack is not updated. To ensure that a + property's value can be reverted using the undo stack, you must + use the QDesignerFormWindowCursorInterface::setProperty() + function, or its buddy \l + {QDesignerFormWindowCursorInterface::setWidgetProperty()}{setWidgetProperty()}, + instead. + + \sa indexOf(), property(), propertyGroup() +*/ + +/*! + \fn bool QDesignerPropertySheetExtension::isChanged(int index) const + + Returns true if the value of the property at the given \a index + differs from the property's default value, otherwise false. + + \sa indexOf(), setChanged(), reset() +*/ + +/*! + \fn void QDesignerPropertySheetExtension::setChanged(int index, bool changed) + + Sets whether the property at the given \a index is different from + its default value, or not, depending on the \a changed parameter. + + \sa indexOf(), isChanged() +*/ diff --git a/src/designer/src/lib/sdk/script.cpp b/src/designer/src/lib/sdk/script.cpp new file mode 100644 index 000000000..0723b6dcd --- /dev/null +++ b/src/designer/src/lib/sdk/script.cpp @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "script_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QDesignerScriptExtension + \brief The QDesignerScriptExtension class allows you to generate a + per-widget \l{QtScript} {Qt Script} snippet to be executed while + building the form. + + \internal + \inmodule QtDesigner + \since 4.3 + + On saving the form, the extension is queried for a script snippet + to be associated with the widget while saving the UI file. + This script is then run after creating the widget by \l uic or + QUiLoader. + + As opposed to \l QDesignerCustomWidgetInterface::codeTemplate(), + it allows for applying an internal state of the widget + that can be manipulated using \QD. + + Such a state might for example be the contents of a custom item view widget, + for which an editor is provided by the QDesignerTaskMenuExtension. + + While saving the form, the state is serialized as a QVariantMap of + \QD-supported properties, which is stored in the UI file. This is + handled by data() and setData(). + + For item view contents, there might be for example a key that determines + the number of items and other keys that contain the actual items following + a naming scheme (\c numItems, \c item1, \c item2, ...). + + On saving, script() is invoked, which should return a script snippet that + applies the state to the widget while building the form. + + \sa {Creating Custom Widgets for Qt Designer#Using Qt Script to Aid in Building Forms}{Creating Custom Widgets for Qt Designer}, QtScript +*/ + +/*! + Destroys the extension. +*/ + +QDesignerScriptExtension::~QDesignerScriptExtension() +{ +} + +/*! + \fn virtual QString QDesignerScriptExtension::script() const + + Returns a script snippet to be associated with the widget. +*/ + +/*! + \fn virtual QVariantMap QDesignerScriptExtension::data() const + + Returns a map of variants describing the internal state to be + stored in the UI file. +*/ + +/*! + \fn virtual void QDesignerScriptExtension::setData(const QVariantMap &data) + + Applies the internal state stored in \a data to the widget while loading a form. +*/ + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/sdk/script_p.h b/src/designer/src/lib/sdk/script_p.h new file mode 100644 index 000000000..81b588ccb --- /dev/null +++ b/src/designer/src/lib/sdk/script_p.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef SCRIPT_H +#define SCRIPT_H + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QString; // FIXME: fool syncqt + +class QDESIGNER_SDK_EXPORT QDesignerScriptExtension +{ +public: + virtual ~QDesignerScriptExtension(); + + virtual QVariantMap data() const = 0; + virtual void setData(const QVariantMap &data) = 0; + + virtual QString script() const = 0; + +}; +Q_DECLARE_EXTENSION_INTERFACE(QDesignerScriptExtension, "com.trolltech.Qt.Designer.Script") + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // SCRIPT_H diff --git a/src/designer/src/lib/sdk/sdk.pri b/src/designer/src/lib/sdk/sdk.pri new file mode 100644 index 000000000..bc46a1edb --- /dev/null +++ b/src/designer/src/lib/sdk/sdk.pri @@ -0,0 +1,58 @@ +# Input + +INCLUDEPATH += $$PWD + +HEADERS += $$PWD/abstractformeditor.h \ + $$PWD/abstractintrospection_p.h \ + $$PWD/abstractsettings_p.h \ + $$PWD/abstractformeditorplugin.h \ + $$PWD/abstractresourcebrowser.h \ + $$PWD/abstractintegration.h \ + $$PWD/abstractpropertyeditor.h \ + $$PWD/abstractformwindow.h \ + $$PWD/abstractformwindowtool.h \ + $$PWD/abstractformwindowcursor.h \ + $$PWD/abstractformwindowmanager.h \ + $$PWD/abstractwidgetdatabase.h \ + $$PWD/abstractmetadatabase.h \ + $$PWD/abstractwidgetfactory.h \ + $$PWD/abstractobjectinspector.h \ + $$PWD/abstractactioneditor.h \ + $$PWD/abstractbrushmanager.h \ + $$PWD/abstracticoncache.h \ + $$PWD/abstractlanguage.h \ + $$PWD/abstractoptionspage_p.h \ + $$PWD/propertysheet.h \ + $$PWD/dynamicpropertysheet.h \ + $$PWD/membersheet.h \ + $$PWD/taskmenu.h \ + $$PWD/extrainfo.h \ + $$PWD/abstractwidgetbox.h \ + $$PWD/layoutdecoration.h \ + $$PWD/abstractdnditem.h \ + $$PWD/abstractpromotioninterface.h \ + $$PWD/abstractdialoggui_p.h \ + $$PWD/script_p.h \ + $$PWD/abstractnewformwidget_p.h + +SOURCES += $$PWD/abstractformeditor.cpp \ + $$PWD/abstractintrospection.cpp \ + $$PWD/abstractformeditorplugin.cpp \ + $$PWD/abstractresourcebrowser.cpp \ + $$PWD/abstractintegration.cpp \ + $$PWD/abstractpropertyeditor.cpp \ + $$PWD/abstractformwindow.cpp \ + $$PWD/abstractformwindowtool.cpp \ + $$PWD/abstractformwindowcursor.cpp \ + $$PWD/abstractformwindowmanager.cpp \ + $$PWD/abstractwidgetdatabase.cpp \ + $$PWD/abstractmetadatabase.cpp \ + $$PWD/abstractwidgetfactory.cpp \ + $$PWD/abstractobjectinspector.cpp \ + $$PWD/abstractactioneditor.cpp \ + $$PWD/abstractwidgetbox.cpp \ + $$PWD/extrainfo.cpp \ + $$PWD/abstractpromotioninterface.cpp \ + $$PWD/abstractdialoggui.cpp \ + $$PWD/script.cpp \ + $$PWD/abstractnewformwidget.cpp diff --git a/src/designer/src/lib/sdk/sdk_global.h b/src/designer/src/lib/sdk/sdk_global.h new file mode 100644 index 000000000..b2a0f5767 --- /dev/null +++ b/src/designer/src/lib/sdk/sdk_global.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SDK_GLOBAL_H +#define SDK_GLOBAL_H + +#include + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +#define QDESIGNER_SDK_EXTERN Q_DECL_EXPORT +#define QDESIGNER_SDK_IMPORT Q_DECL_IMPORT + +#ifdef QT_DESIGNER_STATIC +# define QDESIGNER_SDK_EXPORT +#elif defined(QDESIGNER_SDK_LIBRARY) +# define QDESIGNER_SDK_EXPORT QDESIGNER_SDK_EXTERN +#else +# define QDESIGNER_SDK_EXPORT QDESIGNER_SDK_IMPORT +#endif + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // SDK_GLOBAL_H diff --git a/src/designer/src/lib/sdk/taskmenu.h b/src/designer/src/lib/sdk/taskmenu.h new file mode 100644 index 000000000..94db7bc26 --- /dev/null +++ b/src/designer/src/lib/sdk/taskmenu.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TASKMENU_H +#define TASKMENU_H + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QAction; + +class QDesignerTaskMenuExtension +{ +public: + virtual ~QDesignerTaskMenuExtension() {} + + virtual QAction *preferredEditAction() const; + + virtual QList taskActions() const = 0; +}; +Q_DECLARE_EXTENSION_INTERFACE(QDesignerTaskMenuExtension, "com.trolltech.Qt.Designer.TaskMenu") + + +inline QAction *QDesignerTaskMenuExtension::preferredEditAction() const +{ return 0; } + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // TASKMENU_H diff --git a/src/designer/src/lib/sdk/taskmenu.qdoc b/src/designer/src/lib/sdk/taskmenu.qdoc new file mode 100644 index 000000000..c5a379539 --- /dev/null +++ b/src/designer/src/lib/sdk/taskmenu.qdoc @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Free Documentation License +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of this +** file. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \class QDesignerTaskMenuExtension + \brief The QDesignerTaskMenuExtension class allows you to add custom + menu entries to Qt Designer's task menu. + \inmodule QtDesigner + + QDesignerTaskMenuExtension provides an interface for creating + custom task menu extensions. It is typically used to create task + menu entries that are specific to a plugin in \QD. + + \QD uses the QDesignerTaskMenuExtension to feed its task + menu. Whenever a task menu is requested, \QD will query + for the selected widget's task menu extension. + + \image taskmenuextension-example-faded.png + + A task menu extension is a collection of QActions. The actions + appear as entries in the task menu when the plugin with the + specified extension is selected. The image above shows the custom + \gui {Edit State...} action which appears in addition to \QD's + default task menu entries: \gui Cut, \gui Copy, \gui Paste etc. + + To create a custom task menu extension, your extension class must + inherit from both QObject and QDesignerTaskMenuExtension. For + example: + + \snippet doc/src/snippets/code/doc_src_qtdesigner.cpp 9 + + Since we are implementing an interface, we must ensure that it + is made known to the meta-object system using the Q_INTERFACES() + macro. This enables \QD to use the qobject_cast() function to + query for supported interfaces using nothing but a QObject + pointer. + + You must reimplement the taskActions() function to return a list + of actions that will be included in \QD task menu. Optionally, you + can reimplement the preferredEditAction() function to set the + action that is invoked when selecting your plugin and pressing + \key F2. The preferred edit action must be one of the actions + returned by taskActions() and, if it's not defined, pressing the + \key F2 key will simply be ignored. + + In \QD, extensions are not created until they are required. A + task menu extension, for example, is created when you click the + right mouse button over a widget in \QD's workspace. For that + reason you must also construct an extension factory, using either + QExtensionFactory or a subclass, and register it using \QD's + \l {QExtensionManager}{extension manager}. + + When a task menu extension is required, \QD's \l + {QExtensionManager}{extension manager} will run through all its + registered factories calling QExtensionFactory::createExtension() + for each until it finds one that is able to create a task menu + extension for the selected widget. This factory will then make an + instance of the extension. + + There are four available types of extensions in \QD: + QDesignerContainerExtension, QDesignerMemberSheetExtension, + QDesignerPropertySheetExtension, and QDesignerTaskMenuExtension. + \QD's behavior is the same whether the requested extension is + associated with a container, a member sheet, a property sheet or a + task menu. + + The QExtensionFactory class provides a standard extension factory, + and can also be used as an interface for custom extension + factories. You can either create a new QExtensionFactory and + reimplement the QExtensionFactory::createExtension() function. For + example: + + \snippet doc/src/snippets/code/doc_src_qtdesigner.cpp 10 + + Or you can use an existing factory, expanding the + QExtensionFactory::createExtension() function to make the factory + able to create a task menu extension as well. For example: + + \snippet doc/src/snippets/code/doc_src_qtdesigner.cpp 11 + + For a complete example using the QDesignerTaskMenuExtension class, + see the \l {designer/taskmenuextension}{Task Menu Extension + example}. The example shows how to create a custom widget plugin + for \QD, and how to to use the QDesignerTaskMenuExtension + class to add custom items to \QD's task menu. + + \sa QExtensionFactory, QExtensionManager, {Creating Custom Widget + Extensions} +*/ + +/*! + \fn QDesignerTaskMenuExtension::~QDesignerTaskMenuExtension() + + Destroys the task menu extension. +*/ + +/*! + \fn QAction *QDesignerTaskMenuExtension::preferredEditAction() const + + Returns the action that is invoked when selecting a plugin with + the specified extension and pressing \key F2. + + The action must be one of the actions returned by taskActions(). +*/ + +/*! + \fn QList QDesignerTaskMenuExtension::taskActions() const + + Returns the task menu extension as a list of actions which will be + included in \QD's task menu when a plugin with the specified + extension is selected. + + The function must be reimplemented to add actions to the list. +*/ diff --git a/src/designer/src/lib/shared/actioneditor.cpp b/src/designer/src/lib/shared/actioneditor.cpp new file mode 100644 index 000000000..fb882c30b --- /dev/null +++ b/src/designer/src/lib/shared/actioneditor.cpp @@ -0,0 +1,823 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "actioneditor_p.h" +#include "filterwidget_p.h" +#include "actionrepository_p.h" +#include "iconloader_p.h" +#include "newactiondialog_p.h" +#include "qdesigner_menu_p.h" +#include "qdesigner_command_p.h" +#include "qdesigner_propertycommand_p.h" +#include "qdesigner_objectinspector_p.h" +#include "qdesigner_utils_p.h" +#include "qsimpleresource_p.h" +#include "formwindowbase_p.h" +#include "qdesigner_taskmenu_p.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +Q_DECLARE_METATYPE(QAction*) + +QT_BEGIN_NAMESPACE + +static const char *actionEditorViewModeKey = "ActionEditorViewMode"; + +static const char *iconPropertyC = "icon"; +static const char *shortcutPropertyC = "shortcut"; +static const char *toolTipPropertyC = "toolTip"; +static const char *checkablePropertyC = "checkable"; +static const char *objectNamePropertyC = "objectName"; +static const char *textPropertyC = "text"; + +namespace qdesigner_internal { +//-------- ActionGroupDelegate +class ActionGroupDelegate: public QItemDelegate +{ +public: + ActionGroupDelegate(QObject *parent) + : QItemDelegate(parent) {} + + virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const + { + if (option.state & QStyle::State_Selected) + painter->fillRect(option.rect, option.palette.highlight()); + + QItemDelegate::paint(painter, option, index); + } + + virtual void drawFocus(QPainter * /*painter*/, const QStyleOptionViewItem &/*option*/, const QRect &/*rect*/) const {} +}; + +//-------- ActionEditor +ActionEditor::ActionEditor(QDesignerFormEditorInterface *core, QWidget *parent, Qt::WindowFlags flags) : + QDesignerActionEditorInterface(parent, flags), + m_core(core), + m_actionGroups(0), + m_actionView(new ActionView), + m_actionNew(new QAction(tr("New..."), this)), + m_actionEdit(new QAction(tr("Edit..."), this)), + m_actionNavigateToSlot(new QAction(tr("Go to slot..."), this)), + m_actionCopy(new QAction(tr("Copy"), this)), + m_actionCut(new QAction(tr("Cut"), this)), + m_actionPaste(new QAction(tr("Paste"), this)), + m_actionSelectAll(new QAction(tr("Select all"), this)), + m_actionDelete(new QAction(tr("Delete"), this)), + m_viewModeGroup(new QActionGroup(this)), + m_iconViewAction(0), + m_listViewAction(0), + m_filterWidget(0), + m_selectAssociatedWidgetsMapper(0) +{ + m_actionView->initialize(m_core); + m_actionView->setSelectionMode(QAbstractItemView::ExtendedSelection); + setWindowTitle(tr("Actions")); + + QVBoxLayout *l = new QVBoxLayout(this); + l->setMargin(0); + l->setSpacing(0); + + QToolBar *toolbar = new QToolBar; + toolbar->setIconSize(QSize(22, 22)); + toolbar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); + l->addWidget(toolbar); + // edit actions + QIcon documentNewIcon = QIcon::fromTheme("document-new", createIconSet(QLatin1String("filenew.png"))); + m_actionNew->setIcon(documentNewIcon); + m_actionNew->setEnabled(false); + connect(m_actionNew, SIGNAL(triggered()), this, SLOT(slotNewAction())); + toolbar->addAction(m_actionNew); + + connect(m_actionSelectAll, SIGNAL(triggered()), m_actionView, SLOT(selectAll())); + + m_actionCut->setEnabled(false); + connect(m_actionCut, SIGNAL(triggered()), this, SLOT(slotCut())); + QIcon editCutIcon = QIcon::fromTheme("edit-cut", createIconSet(QLatin1String("editcut.png"))); + m_actionCut->setIcon(editCutIcon); + + m_actionCopy->setEnabled(false); + connect(m_actionCopy, SIGNAL(triggered()), this, SLOT(slotCopy())); + QIcon editCopyIcon = QIcon::fromTheme("edit-copy", createIconSet(QLatin1String("editcopy.png"))); + m_actionCopy->setIcon(editCopyIcon); + toolbar->addAction(m_actionCopy); + + connect(m_actionPaste, SIGNAL(triggered()), this, SLOT(slotPaste())); + QIcon editPasteIcon = QIcon::fromTheme("edit-paste", createIconSet(QLatin1String("editpaste.png"))); + m_actionPaste->setIcon(editPasteIcon); + toolbar->addAction(m_actionPaste); + + m_actionEdit->setEnabled(false); + connect(m_actionEdit, SIGNAL(triggered()), this, SLOT(editCurrentAction())); + + connect(m_actionNavigateToSlot, SIGNAL(triggered()), this, SLOT(navigateToSlotCurrentAction())); + + QIcon editDeleteIcon = QIcon::fromTheme("edit-delete", createIconSet(QLatin1String("editdelete.png"))); + m_actionDelete->setIcon(editDeleteIcon); + m_actionDelete->setEnabled(false); + connect(m_actionDelete, SIGNAL(triggered()), this, SLOT(slotDelete())); + toolbar->addAction(m_actionDelete); + + // Toolbutton with menu containing action group for detailed/icon view. Steal the icons from the file dialog. + // + QMenu *configureMenu; + toolbar->addWidget(createConfigureMenuButton(tr("Configure Action Editor"), &configureMenu)); + + connect(m_viewModeGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotViewMode(QAction*))); + m_iconViewAction = m_viewModeGroup->addAction(tr("Icon View")); + m_iconViewAction->setData(QVariant(ActionView::IconView)); + m_iconViewAction->setCheckable(true); + m_iconViewAction->setIcon(style()->standardIcon (QStyle::SP_FileDialogListView)); + configureMenu->addAction(m_iconViewAction); + + m_listViewAction = m_viewModeGroup->addAction(tr("Detailed View")); + m_listViewAction->setData(QVariant(ActionView::DetailedView)); + m_listViewAction->setCheckable(true); + m_listViewAction->setIcon(style()->standardIcon (QStyle::SP_FileDialogDetailedView)); + configureMenu->addAction(m_listViewAction); + // filter + m_filterWidget = new FilterWidget(toolbar); + connect(m_filterWidget, SIGNAL(filterChanged(QString)), this, SLOT(setFilter(QString))); + m_filterWidget->setEnabled(false); + toolbar->addWidget(m_filterWidget); + + // main layout + QSplitter *splitter = new QSplitter(Qt::Horizontal); + splitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + splitter->addWidget(m_actionView); + l->addWidget(splitter); + +#if 0 // ### implement me + m_actionGroups = new QListWidget(splitter); + splitter->addWidget(m_actionGroups); + m_actionGroups->setItemDelegate(new ActionGroupDelegate(m_actionGroups)); + m_actionGroups->setMovement(QListWidget::Static); + m_actionGroups->setResizeMode(QListWidget::Fixed); + m_actionGroups->setIconSize(QSize(48, 48)); + m_actionGroups->setFlow(QListWidget::TopToBottom); + m_actionGroups->setViewMode(QListWidget::IconMode); + m_actionGroups->setWrapping(false); +#endif + + connect(m_actionView, SIGNAL(resourceImageDropped(QString,QAction*)), + this, SLOT(resourceImageDropped(QString,QAction*))); + + connect(m_actionView, SIGNAL(currentChanged(QAction*)),this, SLOT(slotCurrentItemChanged(QAction*))); + // make it possible for vs integration to reimplement edit action dialog + connect(m_actionView, SIGNAL(activated(QAction*)), this, SIGNAL(itemActivated(QAction*))); + + connect(m_actionView,SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + this, SLOT(slotSelectionChanged(QItemSelection,QItemSelection))); + + connect(m_actionView, SIGNAL(contextMenuRequested(QContextMenuEvent*,QAction*)), + this, SLOT(slotContextMenuRequested(QContextMenuEvent*,QAction*))); + + connect(this, SIGNAL(itemActivated(QAction*)), this, SLOT(editAction(QAction*))); + + restoreSettings(); + updateViewModeActions(); +} + +// Utility to create a configure button with menu for usage on toolbars +QToolButton *ActionEditor::createConfigureMenuButton(const QString &t, QMenu **ptrToMenu) +{ + QToolButton *configureButton = new QToolButton; + QAction *configureAction = new QAction(t, configureButton); + QIcon configureIcon = QIcon::fromTheme("document-properties", createIconSet(QLatin1String("configure.png"))); + configureAction->setIcon(configureIcon); + QMenu *configureMenu = new QMenu; + configureAction->setMenu(configureMenu); + configureButton->setDefaultAction(configureAction); + configureButton->setPopupMode(QToolButton::InstantPopup); + *ptrToMenu = configureMenu; + return configureButton; +} + +ActionEditor::~ActionEditor() +{ + saveSettings(); +} + +QAction *ActionEditor::actionNew() const +{ + return m_actionNew; +} + +QAction *ActionEditor::actionDelete() const +{ + return m_actionDelete; +} + +QDesignerFormWindowInterface *ActionEditor::formWindow() const +{ + return m_formWindow; +} + +void ActionEditor::setFormWindow(QDesignerFormWindowInterface *formWindow) +{ + if (formWindow != 0 && formWindow->mainContainer() == 0) + formWindow = 0; + + // we do NOT rely on this function to update the action editor + if (m_formWindow == formWindow) + return; + + if (m_formWindow != 0) { + const ActionList actionList = m_formWindow->mainContainer()->findChildren(); + foreach (QAction *action, actionList) + disconnect(action, SIGNAL(changed()), this, SLOT(slotActionChanged())); + } + + m_formWindow = formWindow; + + m_actionView->model()->clearActions(); + + m_actionEdit->setEnabled(false); + m_actionCopy->setEnabled(false); + m_actionCut->setEnabled(false); + m_actionDelete->setEnabled(false); + + if (!formWindow || !formWindow->mainContainer()) { + m_actionNew->setEnabled(false); + m_filterWidget->setEnabled(false); + return; + } + + m_actionNew->setEnabled(true); + m_filterWidget->setEnabled(true); + + const ActionList actionList = formWindow->mainContainer()->findChildren(); + foreach (QAction *action, actionList) + if (!action->isSeparator() && core()->metaDataBase()->item(action) != 0) { + // Show unless it has a menu. However, listen for change on menu actions also as it might be removed + if (!action->menu()) + m_actionView->model()->addAction(action); + connect(action, SIGNAL(changed()), this, SLOT(slotActionChanged())); + } + + setFilter(m_filter); +} + +void ActionEditor::slotSelectionChanged(const QItemSelection& selected, const QItemSelection& /*deselected*/) +{ + const bool hasSelection = !selected.indexes().empty(); + m_actionCopy->setEnabled(hasSelection); + m_actionCut->setEnabled(hasSelection); + m_actionDelete->setEnabled(hasSelection); +} + +void ActionEditor::slotCurrentItemChanged(QAction *action) +{ + QDesignerFormWindowInterface *fw = formWindow(); + if (!fw) + return; + + const bool hasCurrentAction = action != 0; + m_actionEdit->setEnabled(hasCurrentAction); + + if (!action) { + fw->clearSelection(); + return; + } + + QDesignerObjectInspector *oi = qobject_cast(core()->objectInspector()); + + if (action->associatedWidgets().empty()) { + // Special case: action not in object tree. Deselect all and set in property editor + fw->clearSelection(false); + if (oi) + oi->clearSelection(); + core()->propertyEditor()->setObject(action); + } else { + if (oi) + oi->selectObject(action); + } +} + +void ActionEditor::slotActionChanged() +{ + QAction *action = qobject_cast(sender()); + Q_ASSERT(action != 0); + + ActionModel *model = m_actionView->model(); + const int row = model->findAction(action); + if (row == -1) { + if (action->menu() == 0) // action got its menu deleted, create item + model->addAction(action); + } else if (action->menu() != 0) { // action got its menu created, remove item + model->removeRow(row); + } else { + // action text or icon changed, update item + model->update(row); + } +} + +QDesignerFormEditorInterface *ActionEditor::core() const +{ + return m_core; +} + +QString ActionEditor::filter() const +{ + return m_filter; +} + +void ActionEditor::setFilter(const QString &f) +{ + m_filter = f; + m_actionView->filter(m_filter); +} + +// Set changed state of icon property, reset when icon is cleared +static void refreshIconPropertyChanged(const QAction *action, QDesignerPropertySheetExtension *sheet) +{ + sheet->setChanged(sheet->indexOf(QLatin1String(iconPropertyC)), !action->icon().isNull()); +} + +void ActionEditor::manageAction(QAction *action) +{ + action->setParent(formWindow()->mainContainer()); + core()->metaDataBase()->add(action); + + if (action->isSeparator() || action->menu() != 0) + return; + + QDesignerPropertySheetExtension *sheet = qt_extension(core()->extensionManager(), action); + sheet->setChanged(sheet->indexOf(QLatin1String(objectNamePropertyC)), true); + sheet->setChanged(sheet->indexOf(QLatin1String(textPropertyC)), true); + refreshIconPropertyChanged(action, sheet); + + m_actionView->setCurrentIndex(m_actionView->model()->addAction(action)); + connect(action, SIGNAL(changed()), this, SLOT(slotActionChanged())); +} + +void ActionEditor::unmanageAction(QAction *action) +{ + core()->metaDataBase()->remove(action); + action->setParent(0); + + disconnect(action, SIGNAL(changed()), this, SLOT(slotActionChanged())); + + const int row = m_actionView->model()->findAction(action); + if (row != -1) + m_actionView->model()->remove(row); +} + +// Set an initial property and mark it as changed in the sheet +static void setInitialProperty(QDesignerPropertySheetExtension *sheet, const QString &name, const QVariant &value) +{ + const int index = sheet->indexOf(name); + Q_ASSERT(index != -1); + sheet->setProperty(index, value); + sheet->setChanged(index, true); +} + +void ActionEditor::slotNewAction() +{ + NewActionDialog dlg(this); + dlg.setWindowTitle(tr("New action")); + + if (dlg.exec() == QDialog::Accepted) { + const ActionData actionData = dlg.actionData(); + m_actionView->clearSelection(); + QAction *action = new QAction(formWindow()); + action->setObjectName(actionData.name); + formWindow()->ensureUniqueObjectName(action); + action->setText(actionData.text); + + QDesignerPropertySheetExtension *sheet = qt_extension(core()->extensionManager(), action); + if (!actionData.toolTip.isEmpty()) + setInitialProperty(sheet, QLatin1String(toolTipPropertyC), actionData.toolTip); + + if (actionData.checkable) + setInitialProperty(sheet, QLatin1String(checkablePropertyC), QVariant(true)); + + if (!actionData.keysequence.value().isEmpty()) + setInitialProperty(sheet, QLatin1String(shortcutPropertyC), QVariant::fromValue(actionData.keysequence)); + + sheet->setProperty(sheet->indexOf(QLatin1String(iconPropertyC)), QVariant::fromValue(actionData.icon)); + + AddActionCommand *cmd = new AddActionCommand(formWindow()); + cmd->init(action); + formWindow()->commandHistory()->push(cmd); + } +} + +static inline bool isSameIcon(const QIcon &i1, const QIcon &i2) +{ + return i1.serialNumber() == i2.serialNumber(); +} + +// return a FormWindow command to apply an icon or a reset command in case it +// is empty. + +static QDesignerFormWindowCommand *setIconPropertyCommand(const PropertySheetIconValue &newIcon, QAction *action, QDesignerFormWindowInterface *fw) +{ + const QString iconProperty = QLatin1String(iconPropertyC); + if (newIcon.isEmpty()) { + ResetPropertyCommand *cmd = new ResetPropertyCommand(fw); + cmd->init(action, iconProperty); + return cmd; + } + SetPropertyCommand *cmd = new SetPropertyCommand(fw); + cmd->init(action, iconProperty, QVariant::fromValue(newIcon)); + return cmd; +} + +// return a FormWindow command to apply a QKeySequence or a reset command +// in case it is empty. + +static QDesignerFormWindowCommand *setKeySequencePropertyCommand(const PropertySheetKeySequenceValue &ks, QAction *action, QDesignerFormWindowInterface *fw) +{ + const QString shortcutProperty = QLatin1String(shortcutPropertyC); + if (ks.value().isEmpty()) { + ResetPropertyCommand *cmd = new ResetPropertyCommand(fw); + cmd->init(action, shortcutProperty); + return cmd; + } + SetPropertyCommand *cmd = new SetPropertyCommand(fw); + cmd->init(action, shortcutProperty, QVariant::fromValue(ks)); + return cmd; +} + +// return a FormWindow command to apply a POD value or reset command in case +// it is equal to the default value. + +template +QDesignerFormWindowCommand *setPropertyCommand(const QString &name, T value, T defaultValue, + QObject *o, QDesignerFormWindowInterface *fw) +{ + if (value == defaultValue) { + ResetPropertyCommand *cmd = new ResetPropertyCommand(fw); + cmd->init(o, name); + return cmd; + } + SetPropertyCommand *cmd = new SetPropertyCommand(fw); + cmd->init(o, name, QVariant(value)); + return cmd; +} + +// Return the text value of a string property via PropertySheetStringValue +static inline QString textPropertyValue(const QDesignerPropertySheetExtension *sheet, const QString &name) +{ + const int index = sheet->indexOf(name); + Q_ASSERT(index != -1); + const PropertySheetStringValue ps = qvariant_cast(sheet->property(index)); + return ps.value(); +} + +void ActionEditor::editAction(QAction *action) +{ + if (!action) + return; + + NewActionDialog dlg(this); + dlg.setWindowTitle(tr("Edit action")); + + ActionData oldActionData; + QDesignerPropertySheetExtension *sheet = qt_extension(core()->extensionManager(), action); + oldActionData.name = action->objectName(); + oldActionData.text = action->text(); + oldActionData.toolTip = textPropertyValue(sheet, QLatin1String(toolTipPropertyC)); + oldActionData.icon = qvariant_cast(sheet->property(sheet->indexOf(QLatin1String(iconPropertyC)))); + oldActionData.keysequence = ActionModel::actionShortCut(sheet); + oldActionData.checkable = action->isCheckable(); + dlg.setActionData(oldActionData); + + if (!dlg.exec()) + return; + + // figure out changes and whether to start a macro + const ActionData newActionData = dlg.actionData(); + const unsigned changeMask = newActionData.compare(oldActionData); + if (changeMask == 0u) + return; + + const bool severalChanges = (changeMask != ActionData::TextChanged) && (changeMask != ActionData::NameChanged) + && (changeMask != ActionData::ToolTipChanged) && (changeMask != ActionData::IconChanged) + && (changeMask != ActionData::CheckableChanged) && (changeMask != ActionData::KeysequenceChanged); + + QDesignerFormWindowInterface *fw = formWindow(); + QUndoStack *undoStack = fw->commandHistory(); + if (severalChanges) + fw->beginCommand(QLatin1String("Edit action")); + + if (changeMask & ActionData::NameChanged) + undoStack->push(createTextPropertyCommand(QLatin1String(objectNamePropertyC), newActionData.name, action, fw)); + + if (changeMask & ActionData::TextChanged) + undoStack->push(createTextPropertyCommand(QLatin1String(textPropertyC), newActionData.text, action, fw)); + + if (changeMask & ActionData::ToolTipChanged) + undoStack->push(createTextPropertyCommand(QLatin1String(toolTipPropertyC), newActionData.toolTip, action, fw)); + + if (changeMask & ActionData::IconChanged) + undoStack->push(setIconPropertyCommand(newActionData.icon, action, fw)); + + if (changeMask & ActionData::CheckableChanged) + undoStack->push(setPropertyCommand(QLatin1String(checkablePropertyC), newActionData.checkable, false, action, fw)); + + if (changeMask & ActionData::KeysequenceChanged) + undoStack->push(setKeySequencePropertyCommand(newActionData.keysequence, action, fw)); + + if (severalChanges) + fw->endCommand(); +} + +void ActionEditor::editCurrentAction() +{ + if (QAction *a = m_actionView->currentAction()) + editAction(a); +} + +void ActionEditor::navigateToSlotCurrentAction() +{ + if (QAction *a = m_actionView->currentAction()) + QDesignerTaskMenu::navigateToSlot(m_core, a, QLatin1String("triggered()")); +} + +void ActionEditor::deleteActions(QDesignerFormWindowInterface *fw, const ActionList &actions) +{ + // We need a macro even in the case of single action because the commands might cause the + // scheduling of other commands (signal slots connections) + const QString description = actions.size() == 1 ? + tr("Remove action '%1'").arg(actions.front()->objectName()) : tr("Remove actions"); + fw->beginCommand(description); + foreach(QAction *action, actions) { + RemoveActionCommand *cmd = new RemoveActionCommand(fw); + cmd->init(action); + fw->commandHistory()->push(cmd); + } + fw->endCommand(); +} + +void ActionEditor::copyActions(QDesignerFormWindowInterface *fwi, const ActionList &actions) +{ + FormWindowBase *fw = qobject_cast(fwi); + if (!fw ) + return; + + FormBuilderClipboard clipboard; + clipboard.m_actions = actions; + + if (clipboard.empty()) + return; + + QEditorFormBuilder *formBuilder = fw->createFormBuilder(); + Q_ASSERT(formBuilder); + + QBuffer buffer; + if (buffer.open(QIODevice::WriteOnly)) + if (formBuilder->copy(&buffer, clipboard)) + qApp->clipboard()->setText(QString::fromUtf8(buffer.buffer()), QClipboard::Clipboard); + delete formBuilder; +} + +void ActionEditor::slotDelete() +{ + QDesignerFormWindowInterface *fw = formWindow(); + if (!fw) + return; + + const ActionView::ActionList selection = m_actionView->selectedActions(); + if (selection.empty()) + return; + + deleteActions(fw, selection); +} + +QString ActionEditor::actionTextToName(const QString &text, const QString &prefix) +{ + QString name = text; + if (name.isEmpty()) + return QString(); + + name[0] = name.at(0).toUpper(); + name.prepend(prefix); + const QString underscore = QString(QLatin1Char('_')); + name.replace(QRegExp(QString(QLatin1String("[^a-zA-Z_0-9]"))), underscore); + name.replace(QRegExp(QLatin1String("__*")), underscore); + if (name.endsWith(underscore.at(0))) + name.truncate(name.size() - 1); + + return name; +} + +void ActionEditor::resourceImageDropped(const QString &path, QAction *action) +{ + QDesignerFormWindowInterface *fw = formWindow(); + if (!fw) + return; + + QDesignerPropertySheetExtension *sheet = qt_extension(core()->extensionManager(), action); + const PropertySheetIconValue oldIcon = + qvariant_cast(sheet->property(sheet->indexOf(QLatin1String(iconPropertyC)))); + PropertySheetIconValue newIcon; + newIcon.setPixmap(QIcon::Normal, QIcon::Off, PropertySheetPixmapValue(path)); + if (newIcon.paths().isEmpty() || newIcon.paths() == oldIcon.paths()) + return; + + fw->commandHistory()->push(setIconPropertyCommand(newIcon , action, fw)); +} + +void ActionEditor::mainContainerChanged() +{ + // Invalidate references to objects kept in model + if (sender() == formWindow()) + setFormWindow(0); +} + +void ActionEditor::slotViewMode(QAction *a) +{ + m_actionView->setViewMode(a->data().toInt()); + updateViewModeActions(); +} + +void ActionEditor::slotSelectAssociatedWidget(QWidget *w) +{ + QDesignerFormWindowInterface *fw = formWindow(); + if (!fw ) + return; + + QDesignerObjectInspector *oi = qobject_cast(core()->objectInspector()); + if (!oi) + return; + + fw->clearSelection(); // Actually, there are no widgets selected due to focus in event handling. Just to be sure. + oi->selectObject(w); +} + +void ActionEditor::restoreSettings() +{ + QDesignerSettingsInterface *settings = m_core->settingsManager(); + m_actionView->setViewMode(settings->value(QLatin1String(actionEditorViewModeKey), 0).toInt()); + updateViewModeActions(); +} + +void ActionEditor::saveSettings() +{ + QDesignerSettingsInterface *settings = m_core->settingsManager(); + settings->setValue(QLatin1String(actionEditorViewModeKey), m_actionView->viewMode()); +} + +void ActionEditor::updateViewModeActions() +{ + switch (m_actionView->viewMode()) { + case ActionView::IconView: + m_iconViewAction->setChecked(true); + break; + case ActionView::DetailedView: + m_listViewAction->setChecked(true); + break; + } +} + +void ActionEditor::slotCopy() +{ + QDesignerFormWindowInterface *fw = formWindow(); + if (!fw ) + return; + + const ActionView::ActionList selection = m_actionView->selectedActions(); + if (selection.empty()) + return; + + copyActions(fw, selection); +} + +void ActionEditor::slotCut() +{ + QDesignerFormWindowInterface *fw = formWindow(); + if (!fw ) + return; + + const ActionView::ActionList selection = m_actionView->selectedActions(); + if (selection.empty()) + return; + + copyActions(fw, selection); + deleteActions(fw, selection); +} + +void ActionEditor::slotPaste() +{ + FormWindowBase *fw = qobject_cast(formWindow()); + if (!fw) + return; + m_actionView->clearSelection(); + fw->paste(FormWindowBase::PasteActionsOnly); +} + +void ActionEditor::slotContextMenuRequested(QContextMenuEvent *e, QAction *item) +{ + // set up signal mapper + if (!m_selectAssociatedWidgetsMapper) { + m_selectAssociatedWidgetsMapper = new QSignalMapper(this); + connect(m_selectAssociatedWidgetsMapper, SIGNAL(mapped(QWidget*)), this, SLOT(slotSelectAssociatedWidget(QWidget*))); + } + + QMenu menu(this); + menu.addAction(m_actionNew); + menu.addSeparator(); + menu.addAction(m_actionEdit); + if (QDesignerTaskMenu::isSlotNavigationEnabled(m_core)) + menu.addAction(m_actionNavigateToSlot); + + // Associated Widgets + if (QAction *action = m_actionView->currentAction()) { + const QWidgetList associatedWidgets = ActionModel::associatedWidgets(action); + if (!associatedWidgets.empty()) { + QMenu *associatedWidgetsSubMenu = menu.addMenu(tr("Used In")); + foreach (QWidget *w, associatedWidgets) { + QAction *action = associatedWidgetsSubMenu->addAction(w->objectName()); + m_selectAssociatedWidgetsMapper->setMapping(action, w); + connect(action, SIGNAL(triggered()), m_selectAssociatedWidgetsMapper, SLOT(map())); + } + } + } + + menu.addSeparator(); + menu.addAction(m_actionCut); + menu.addAction(m_actionCopy); + menu.addAction(m_actionPaste); + menu.addAction(m_actionSelectAll); + menu.addAction(m_actionDelete); + menu.addSeparator(); + menu.addAction(m_iconViewAction); + menu.addAction(m_listViewAction); + + emit contextMenuRequested(&menu, item); + + menu.exec(e->globalPos()); + e->accept(); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + diff --git a/src/designer/src/lib/shared/actioneditor_p.h b/src/designer/src/lib/shared/actioneditor_p.h new file mode 100644 index 000000000..ffeae5846 --- /dev/null +++ b/src/designer/src/lib/shared/actioneditor_p.h @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef ACTIONEDITOR_H +#define ACTIONEDITOR_H + +#include "shared_global_p.h" +#include + +#include + +QT_BEGIN_NAMESPACE + +class QDesignerPropertyEditorInterface; +class QDesignerSettingsInterface; +class QMenu; +class QActionGroup; +class QSignalMapper; +class QItemSelection; +class QListWidget; +class QPushButton; +class QLineEdit; +class QToolButton; + +namespace qdesigner_internal { + +class ActionView; +class ResourceMimeData; + +class QDESIGNER_SHARED_EXPORT ActionEditor: public QDesignerActionEditorInterface +{ + Q_OBJECT +public: + explicit ActionEditor(QDesignerFormEditorInterface *core, QWidget *parent = 0, Qt::WindowFlags flags = 0); + virtual ~ActionEditor(); + + QDesignerFormWindowInterface *formWindow() const; + virtual void setFormWindow(QDesignerFormWindowInterface *formWindow); + + virtual QDesignerFormEditorInterface *core() const; + + QAction *actionNew() const; + QAction *actionDelete() const; + + QString filter() const; + + virtual void manageAction(QAction *action); + virtual void unmanageAction(QAction *action); + + static QString actionTextToName(const QString &text, const QString &prefix = QLatin1String("action")); + + // Utility to create a configure button with menu for usage on toolbars + static QToolButton *createConfigureMenuButton(const QString &t, QMenu **ptrToMenu); + +public slots: + void setFilter(const QString &filter); + void mainContainerChanged(); + +private slots: + void slotCurrentItemChanged(QAction *item); + void slotSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected); + void editAction(QAction *item); + void editCurrentAction(); + void navigateToSlotCurrentAction(); + void slotActionChanged(); + void slotNewAction(); + void slotDelete(); + void resourceImageDropped(const QString &path, QAction *action); + void slotContextMenuRequested(QContextMenuEvent *, QAction *); + void slotViewMode(QAction *a); + void slotSelectAssociatedWidget(QWidget *w); + void slotCopy(); + void slotCut(); + void slotPaste(); + +signals: + void itemActivated(QAction *item); + // Context menu for item or global menu if item == 0. + void contextMenuRequested(QMenu *menu, QAction *item); + +private: + typedef QList ActionList; + void deleteActions(QDesignerFormWindowInterface *formWindow, const ActionList &); + void copyActions(QDesignerFormWindowInterface *formWindow, const ActionList &); + + void restoreSettings(); + void saveSettings(); + + void updateViewModeActions(); + + QDesignerFormEditorInterface *m_core; + QPointer m_formWindow; + QListWidget *m_actionGroups; + + ActionView *m_actionView; + + QAction *m_actionNew; + QAction *m_actionEdit; + QAction *m_actionNavigateToSlot; + QAction *m_actionCopy; + QAction *m_actionCut; + QAction *m_actionPaste; + QAction *m_actionSelectAll; + QAction *m_actionDelete; + + QActionGroup *m_viewModeGroup; + QAction *m_iconViewAction; + QAction *m_listViewAction; + + QString m_filter; + QWidget *m_filterWidget; + QSignalMapper *m_selectAssociatedWidgetsMapper; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // ACTIONEDITOR_H diff --git a/src/designer/src/lib/shared/actionprovider_p.h b/src/designer/src/lib/shared/actionprovider_p.h new file mode 100644 index 000000000..ce8a1795e --- /dev/null +++ b/src/designer/src/lib/shared/actionprovider_p.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef ACTIONPROVIDER_H +#define ACTIONPROVIDER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QAction; + +class QDesignerActionProviderExtension +{ +public: + virtual ~QDesignerActionProviderExtension() {} + + virtual QRect actionGeometry(QAction *action) const = 0; + virtual QAction *actionAt(const QPoint &pos) const = 0; + + virtual void adjustIndicator(const QPoint &pos) = 0; +}; + +// Find action at the given position for a widget that has actionGeometry() (QToolBar, +// QMenuBar, QMenu). They usually have actionAt(), but that fails since Designer usually sets +// WA_TransparentForMouseEvents on the widgets. +template + int actionIndexAt(const Widget *w, const QPoint &pos, Qt::Orientation orientation) +{ + const QList actions = w->actions(); + const int actionCount = actions.count(); + if (actionCount == 0) + return -1; + // actionGeometry() can be wrong sometimes; it returns a geometry that + // stretches to the end of the toolbar/menu bar. So, check from the beginning + // in the case of a horizontal right-to-left orientation. + const bool checkTopRight = orientation == Qt::Horizontal && w->layoutDirection() == Qt::RightToLeft; + const QPoint topRight = QPoint(w->rect().width(), 0); + for (int index = 0; index < actionCount; ++index) { + QRect g = w->actionGeometry(actions.at(index)); + if (checkTopRight) + g.setTopRight(topRight); + else + g.setTopLeft(QPoint(0, 0)); + + if (g.contains(pos)) + return index; + } + return -1; +} + +Q_DECLARE_EXTENSION_INTERFACE(QDesignerActionProviderExtension, "com.trolltech.Qt.Designer.ActionProvider") + +QT_END_NAMESPACE + +#endif // ACTIONPROVIDER_H diff --git a/src/designer/src/lib/shared/actionrepository.cpp b/src/designer/src/lib/shared/actionrepository.cpp new file mode 100644 index 000000000..d7701cb9c --- /dev/null +++ b/src/designer/src/lib/shared/actionrepository.cpp @@ -0,0 +1,665 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "actionrepository_p.h" +#include "qtresourceview_p.h" +#include "iconloader_p.h" +#include "qdesigner_utils_p.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +Q_DECLARE_METATYPE(QAction*) + +QT_BEGIN_NAMESPACE + +namespace { + enum { listModeIconSize = 16, iconModeIconSize = 24 }; +} + +static const char *actionMimeType = "action-repository/actions"; +static const char *plainTextMimeType = "text/plain"; + +static inline QAction *actionOfItem(const QStandardItem* item) +{ + return qvariant_cast(item->data(qdesigner_internal::ActionModel::ActionRole)); +} + +namespace qdesigner_internal { + +// ----------- ActionModel +ActionModel::ActionModel(QWidget *parent ) : + QStandardItemModel(parent), + m_emptyIcon(emptyIcon()), + m_core(0) +{ + QStringList headers; + headers += tr("Name"); + headers += tr("Used"); + headers += tr("Text"); + headers += tr("Shortcut"); + headers += tr("Checkable"); + headers += tr("ToolTip"); + Q_ASSERT(NumColumns == headers.size()); + setHorizontalHeaderLabels(headers); +} + +void ActionModel::clearActions() +{ + removeRows(0, rowCount()); +} + +int ActionModel::findAction(QAction *action) const +{ + const int rows = rowCount(); + for (int i = 0; i < rows; i++) + if (action == actionOfItem(item(i))) + return i; + return -1; +} + +void ActionModel::update(int row) +{ + Q_ASSERT(m_core); + // need to create the row list ... grrr.. + if (row >= rowCount()) + return; + + QStandardItemList list; + for (int i = 0; i < NumColumns; i++) + list += item(row, i); + + setItems(m_core, actionOfItem(list.front()), m_emptyIcon, list); +} + +void ActionModel::remove(int row) +{ + qDeleteAll(takeRow(row)); +} + +QModelIndex ActionModel::addAction(QAction *action) +{ + Q_ASSERT(m_core); + QStandardItemList items; + const Qt::ItemFlags flags = Qt::ItemIsSelectable|Qt::ItemIsDropEnabled|Qt::ItemIsDragEnabled|Qt::ItemIsEnabled; + + QVariant itemData; + itemData.setValue(action); + + for (int i = 0; i < NumColumns; i++) { + QStandardItem *item = new QStandardItem; + item->setData(itemData, ActionRole); + item->setFlags(flags); + items.push_back(item); + } + setItems(m_core, action, m_emptyIcon, items); + appendRow(items); + return indexFromItem(items.front()); +} + +// Find the associated menus and toolbars, ignore toolbuttons +QWidgetList ActionModel::associatedWidgets(const QAction *action) +{ + QWidgetList rc = action->associatedWidgets(); + for (QWidgetList::iterator it = rc.begin(); it != rc.end(); ) + if (qobject_cast(*it) || qobject_cast(*it)) { + ++it; + } else { + it = rc.erase(it); + } + return rc; +} + +// shortcut is a fake property, need to retrieve it via property sheet. +PropertySheetKeySequenceValue ActionModel::actionShortCut(QDesignerFormEditorInterface *core, QAction *action) +{ + QDesignerPropertySheetExtension *sheet = qt_extension(core->extensionManager(), action); + if (!sheet) + return PropertySheetKeySequenceValue(); + return actionShortCut(sheet); +} + +PropertySheetKeySequenceValue ActionModel::actionShortCut(const QDesignerPropertySheetExtension *sheet) +{ + const int index = sheet->indexOf(QLatin1String("shortcut")); + if (index == -1) + return PropertySheetKeySequenceValue(); + return qvariant_cast(sheet->property(index)); +} + +void ActionModel::setItems(QDesignerFormEditorInterface *core, QAction *action, + const QIcon &defaultIcon, + QStandardItemList &sl) +{ + + // Tooltip, mostly for icon view mode + QString firstTooltip = action->objectName(); + const QString text = action->text(); + if (!text.isEmpty()) { + firstTooltip += QLatin1Char('\n'); + firstTooltip += text; + } + + Q_ASSERT(sl.size() == NumColumns); + + QStandardItem *item = sl[NameColumn]; + item->setText(action->objectName()); + QIcon icon = action->icon(); + if (icon.isNull()) + icon = defaultIcon; + item->setIcon(icon); + item->setToolTip(firstTooltip); + item->setWhatsThis(firstTooltip); + // Used + const QWidgetList associatedDesignerWidgets = associatedWidgets(action); + const bool used = !associatedDesignerWidgets.empty(); + item = sl[UsedColumn]; + item->setCheckState(used ? Qt::Checked : Qt::Unchecked); + if (used) { + QString usedToolTip; + const QString separator = QLatin1String(", "); + const int count = associatedDesignerWidgets.size(); + for (int i = 0; i < count; i++) { + if (i) + usedToolTip += separator; + usedToolTip += associatedDesignerWidgets.at(i)->objectName(); + } + item->setToolTip(usedToolTip); + } else { + item->setToolTip(QString()); + } + // text + item = sl[TextColumn]; + item->setText(action->text()); + item->setToolTip(action->text()); + // shortcut + const QString shortcut = actionShortCut(core, action).value().toString(QKeySequence::NativeText); + item = sl[ShortCutColumn]; + item->setText(shortcut); + item->setToolTip(shortcut); + // checkable + sl[CheckedColumn]->setCheckState(action->isCheckable() ? Qt::Checked : Qt::Unchecked); + // ToolTip. This might be multi-line, rich text + QString toolTip = action->toolTip(); + item = sl[ToolTipColumn]; + item->setToolTip(toolTip); + item->setText(toolTip.replace(QLatin1Char('\n'), QLatin1Char(' '))); +} + +QMimeData *ActionModel::mimeData(const QModelIndexList &indexes ) const +{ + ActionRepositoryMimeData::ActionList actionList; + + QSet actions; + foreach (const QModelIndex &index, indexes) + if (QStandardItem *item = itemFromIndex(index)) + if (QAction *action = actionOfItem(item)) + actions.insert(action); + return new ActionRepositoryMimeData(actions.toList(), Qt::CopyAction); +} + +// Resource images are plain text. The drag needs to be restricted, however. +QStringList ActionModel::mimeTypes() const +{ + return QStringList(QLatin1String(plainTextMimeType)); +} + +QString ActionModel::actionName(int row) const +{ + return item(row, NameColumn)->text(); +} + +bool ActionModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &) +{ + if (action != Qt::CopyAction) + return false; + + QStandardItem *droppedItem = item(row, column); + if (!droppedItem) + return false; + + + QtResourceView::ResourceType type; + QString path; + if (!QtResourceView::decodeMimeData(data, &type, &path) || type != QtResourceView::ResourceImage) + return false; + + emit resourceImageDropped(path, actionOfItem(droppedItem)); + return true; +} + +QAction *ActionModel::actionAt(const QModelIndex &index) const +{ + if (!index.isValid()) + return 0; + QStandardItem *i = itemFromIndex(index); + if (!i) + return 0; + return actionOfItem(i); +} + +// helpers + +static bool handleImageDragEnterMoveEvent(QDropEvent *event) +{ + QtResourceView::ResourceType type; + const bool rc = QtResourceView::decodeMimeData(event->mimeData(), &type) && type == QtResourceView::ResourceImage; + if (rc) + event->acceptProposedAction(); + else + event->ignore(); + return rc; +} + +static void handleImageDropEvent(const QAbstractItemView *iv, QDropEvent *event, ActionModel *am) +{ + const QModelIndex index = iv->indexAt(event->pos()); + if (!index.isValid()) { + event->ignore(); + return; + } + + if (!handleImageDragEnterMoveEvent(event)) + return; + + am->dropMimeData(event->mimeData(), event->proposedAction(), index.row(), 0, iv->rootIndex()); +} + +// Basically mimic QAbstractItemView's startDrag routine, except that +// another pixmap is used, we don't want the whole row. + +void startActionDrag(QWidget *dragParent, ActionModel *model, const QModelIndexList &indexes, Qt::DropActions supportedActions) +{ + if (indexes.empty()) + return; + + QDrag *drag = new QDrag(dragParent); + QMimeData *data = model->mimeData(indexes); + drag->setMimeData(data); + if (ActionRepositoryMimeData *actionMimeData = qobject_cast(data)) + drag->setPixmap(ActionRepositoryMimeData::actionDragPixmap(actionMimeData->actionList().front())); + + drag->start(supportedActions); +} + +// ---------------- ActionTreeView: +ActionTreeView::ActionTreeView(ActionModel *model, QWidget *parent) : + QTreeView(parent), + m_model(model) +{ + setDragEnabled(true); + setAcceptDrops(true); + setDropIndicatorShown(true); + setDragDropMode(DragDrop); + setModel(model); + setRootIsDecorated(false); + setTextElideMode(Qt::ElideMiddle); + + setModel(model); + connect(this, SIGNAL(activated(QModelIndex)), this, SLOT(slotActivated(QModelIndex))); + connect(header(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(resizeColumnToContents(int))); + + setIconSize(QSize(listModeIconSize, listModeIconSize)); + +} + +QAction *ActionTreeView::currentAction() const +{ + return m_model->actionAt(currentIndex()); +} + +void ActionTreeView::filter(const QString &text) +{ + const int rowCount = m_model->rowCount(); + const bool empty = text.isEmpty(); + const QModelIndex parent = rootIndex(); + for (int i = 0; i < rowCount; i++) + setRowHidden(i, parent, !empty && !m_model->actionName(i).contains(text, Qt::CaseInsensitive)); +} + +void ActionTreeView::dragEnterEvent(QDragEnterEvent *event) +{ + handleImageDragEnterMoveEvent(event); +} + +void ActionTreeView::dragMoveEvent(QDragMoveEvent *event) +{ + handleImageDragEnterMoveEvent(event); +} + +void ActionTreeView::dropEvent(QDropEvent *event) +{ + handleImageDropEvent(this, event, m_model); +} + +void ActionTreeView::focusInEvent(QFocusEvent *event) +{ + QTreeView::focusInEvent(event); + // Make property editor display current action + if (QAction *a = currentAction()) + emit currentChanged(a); +} + +void ActionTreeView::contextMenuEvent(QContextMenuEvent *event) +{ + emit contextMenuRequested(event, m_model->actionAt(indexAt(event->pos()))); +} + +void ActionTreeView::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) +{ + emit currentChanged(m_model->actionAt(current)); + QTreeView::currentChanged(current, previous); +} + +void ActionTreeView::slotActivated(const QModelIndex &index) +{ + emit activated(m_model->actionAt(index)); +} + +void ActionTreeView::startDrag(Qt::DropActions supportedActions) +{ + startActionDrag(this, m_model, selectedIndexes(), supportedActions); +} + +// ---------------- ActionListView: +ActionListView::ActionListView(ActionModel *model, QWidget *parent) : + QListView(parent), + m_model(model) +{ + setDragEnabled(true); + setAcceptDrops(true); + setDropIndicatorShown(true); + setDragDropMode(DragDrop); + setModel(model); + setTextElideMode(Qt::ElideMiddle); + connect(this, SIGNAL(activated(QModelIndex)), this, SLOT(slotActivated(QModelIndex))); + + // We actually want 'Static' as the user should be able to + // drag away actions only (not to rearrange icons). + // We emulate that by not accepting our own + // drag data. 'Static' causes the list view to disable drag and drop + // on the viewport. + setMovement(Snap); + setViewMode(IconMode); + setIconSize(QSize(iconModeIconSize, iconModeIconSize)); + setGridSize(QSize(4 * iconModeIconSize, 2 * iconModeIconSize)); + setSpacing(iconModeIconSize / 3); +} + +QAction *ActionListView::currentAction() const +{ + return m_model->actionAt(currentIndex()); +} + +void ActionListView::filter(const QString &text) +{ + const int rowCount = m_model->rowCount(); + const bool empty = text.isEmpty(); + for (int i = 0; i < rowCount; i++) + setRowHidden(i, !empty && !m_model->actionName(i).contains(text, Qt::CaseInsensitive)); +} + +void ActionListView::dragEnterEvent(QDragEnterEvent *event) +{ + handleImageDragEnterMoveEvent(event); +} + +void ActionListView::dragMoveEvent(QDragMoveEvent *event) +{ + handleImageDragEnterMoveEvent(event); +} + +void ActionListView::dropEvent(QDropEvent *event) +{ + handleImageDropEvent(this, event, m_model); +} + +void ActionListView::focusInEvent(QFocusEvent *event) +{ + QListView::focusInEvent(event); + // Make property editor display current action + if (QAction *a = currentAction()) + emit currentChanged(a); +} + +void ActionListView::contextMenuEvent(QContextMenuEvent *event) +{ + emit contextMenuRequested(event, m_model->actionAt(indexAt(event->pos()))); +} + +void ActionListView::currentChanged(const QModelIndex ¤t, const QModelIndex &previous) +{ + emit currentChanged(m_model->actionAt(current)); + QListView::currentChanged(current, previous); +} + +void ActionListView::slotActivated(const QModelIndex &index) +{ + emit activated(m_model->actionAt(index)); +} + +void ActionListView::startDrag(Qt::DropActions supportedActions) +{ + startActionDrag(this, m_model, selectedIndexes(), supportedActions); +} + +// ActionView +ActionView::ActionView(QWidget *parent) : + QStackedWidget(parent), + m_model(new ActionModel(this)), + m_actionTreeView(new ActionTreeView(m_model)), + m_actionListView(new ActionListView(m_model)) +{ + addWidget(m_actionListView); + addWidget(m_actionTreeView); + // Wire signals + connect(m_actionTreeView, SIGNAL(contextMenuRequested(QContextMenuEvent*,QAction*)), + this, SIGNAL(contextMenuRequested(QContextMenuEvent*,QAction*))); + connect(m_actionListView, SIGNAL(contextMenuRequested(QContextMenuEvent*,QAction*)), + this, SIGNAL(contextMenuRequested(QContextMenuEvent*,QAction*))); + + // make it possible for vs integration to reimplement edit action dialog + // [which it shouldn't do actually] + connect(m_actionListView, SIGNAL(activated(QAction*)), this, SIGNAL(activated(QAction*))); + connect(m_actionTreeView, SIGNAL(activated(QAction*)), this, SIGNAL(activated(QAction*))); + + connect(m_actionListView, SIGNAL(currentChanged(QAction*)),this, SLOT(slotCurrentChanged(QAction*))); + connect(m_actionTreeView, SIGNAL(currentChanged(QAction*)),this, SLOT(slotCurrentChanged(QAction*))); + + connect(m_model, SIGNAL(resourceImageDropped(QString,QAction*)), + this, SIGNAL(resourceImageDropped(QString,QAction*))); + + // sync selection models + QItemSelectionModel *selectionModel = m_actionTreeView->selectionModel(); + m_actionListView->setSelectionModel(selectionModel); + connect(selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + this, SIGNAL(selectionChanged(QItemSelection,QItemSelection))); +} + +int ActionView::viewMode() const +{ + return currentWidget() == m_actionListView ? IconView : DetailedView; +} + +void ActionView::setViewMode(int lm) +{ + if (viewMode() == lm) + return; + + switch (lm) { + case IconView: + setCurrentWidget(m_actionListView); + break; + case DetailedView: + setCurrentWidget(m_actionTreeView); + break; + default: + break; + } +} + +void ActionView::slotCurrentChanged(QAction *action) +{ + // emit only for currently visible + if (sender() == currentWidget()) + emit currentChanged(action); +} + +void ActionView::filter(const QString &text) +{ + m_actionTreeView->filter(text); + m_actionListView->filter(text); +} + +void ActionView::selectAll() +{ + m_actionTreeView->selectAll(); +} + +void ActionView::clearSelection() +{ + m_actionTreeView->selectionModel()->clearSelection(); +} + +void ActionView::setCurrentIndex(const QModelIndex &index) +{ + m_actionTreeView->setCurrentIndex(index); +} + +QAction *ActionView::currentAction() const +{ + return m_actionListView->currentAction(); +} + +void ActionView::setSelectionMode(QAbstractItemView::SelectionMode sm) +{ + m_actionTreeView->setSelectionMode(sm); + m_actionListView->setSelectionMode(sm); +} + +QAbstractItemView::SelectionMode ActionView::selectionMode() const +{ + return m_actionListView->selectionMode(); +} + +QItemSelection ActionView::selection() const +{ + return m_actionListView->selectionModel()->selection(); +} + +ActionView::ActionList ActionView::selectedActions() const +{ + ActionList rc; + foreach (const QModelIndex &index, selection().indexes()) + if (index.column() == 0) + rc += actionOfItem(m_model->itemFromIndex(index)); + return rc; +} +// ---------- ActionRepositoryMimeData +ActionRepositoryMimeData::ActionRepositoryMimeData(QAction *a, Qt::DropAction dropAction) : + m_dropAction(dropAction) +{ + m_actionList += a; +} + +ActionRepositoryMimeData::ActionRepositoryMimeData(const ActionList &al, Qt::DropAction dropAction) : + m_dropAction(dropAction), + m_actionList(al) +{ +} + +QStringList ActionRepositoryMimeData::formats() const +{ + return QStringList(QLatin1String(actionMimeType)); +} + +QPixmap ActionRepositoryMimeData::actionDragPixmap(const QAction *action) +{ + + // Try to find a suitable pixmap. Grab either widget or icon. + const QIcon icon = action->icon(); + if (!icon.isNull()) + return icon.pixmap(QSize(22, 22)); + + foreach (QWidget *w, action->associatedWidgets()) + if (QToolButton *tb = qobject_cast(w)) + return QPixmap::grabWidget(tb); + + // Create a QToolButton + QToolButton *tb = new QToolButton; + tb->setText(action->text()); + tb->setToolButtonStyle(Qt::ToolButtonTextOnly); +#ifdef Q_WS_WIN // Force alien off to make adjustSize() take the system minimumsize into account. + tb->createWinId(); +#endif + tb->adjustSize(); + const QPixmap rc = QPixmap::grabWidget(tb); + tb->deleteLater(); + return rc; +} + +void ActionRepositoryMimeData::accept(QDragMoveEvent *event) const +{ + if (event->proposedAction() == m_dropAction) { + event->acceptProposedAction(); + } else { + event->setDropAction(m_dropAction); + event->accept(); + } +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/actionrepository_p.h b/src/designer/src/lib/shared/actionrepository_p.h new file mode 100644 index 000000000..c2393cb0b --- /dev/null +++ b/src/designer/src/lib/shared/actionrepository_p.h @@ -0,0 +1,269 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef ACTIONREPOSITORY_H +#define ACTIONREPOSITORY_H + +#include "shared_global_p.h" +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QPixmap; + +class QDesignerFormEditorInterface; +class QDesignerPropertySheetExtension; + +namespace qdesigner_internal { + +class PropertySheetKeySequenceValue; + +// Shared model of actions, to be used for several views (detailed/icon view). +class QDESIGNER_SHARED_EXPORT ActionModel: public QStandardItemModel +{ + Q_OBJECT +public: + enum Columns { NameColumn, UsedColumn, TextColumn, ShortCutColumn, CheckedColumn, ToolTipColumn, NumColumns }; + enum { ActionRole = Qt::UserRole + 1000 }; + + explicit ActionModel(QWidget *parent = 0); + void initialize(QDesignerFormEditorInterface *core) { m_core = core; } + + void clearActions(); + QModelIndex addAction(QAction *a); + // remove row + void remove(int row); + // update the row from the underlying action + void update(int row); + + // return row of action or -1. + int findAction(QAction *) const; + + QString actionName(int row) const; + QAction *actionAt(const QModelIndex &index) const; + + virtual QMimeData *mimeData(const QModelIndexList &indexes) const; + virtual QStringList mimeTypes() const; + virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); + + // Find the associated menus and toolbars, ignore toolbuttons + static QWidgetList associatedWidgets(const QAction *action); + + // Retrieve shortcut via property sheet as it is a fake property + static PropertySheetKeySequenceValue actionShortCut(QDesignerFormEditorInterface *core, QAction *action); + static PropertySheetKeySequenceValue actionShortCut(const QDesignerPropertySheetExtension *ps); + +signals: + void resourceImageDropped(const QString &path, QAction *action); + +private: + typedef QList QStandardItemList; + + void initializeHeaders(); + static void setItems(QDesignerFormEditorInterface *core, QAction *a, + const QIcon &defaultIcon, + QStandardItemList &sl); + + const QIcon m_emptyIcon; + + QDesignerFormEditorInterface *m_core; +}; + +// Internal class that provides the detailed view of actions. +class ActionTreeView: public QTreeView +{ + Q_OBJECT +public: + explicit ActionTreeView(ActionModel *model, QWidget *parent = 0); + QAction *currentAction() const; + +public slots: + void filter(const QString &text); + +signals: + void contextMenuRequested(QContextMenuEvent *event, QAction *); + void currentChanged(QAction *action); + void activated(QAction *action); + +protected slots: + virtual void currentChanged(const QModelIndex ¤t, const QModelIndex &previous); + +protected: + virtual void dragEnterEvent(QDragEnterEvent *event); + virtual void dragMoveEvent(QDragMoveEvent *event); + virtual void dropEvent(QDropEvent *event); + virtual void focusInEvent(QFocusEvent *event); + virtual void contextMenuEvent(QContextMenuEvent *event); + virtual void startDrag(Qt::DropActions supportedActions); + +private slots: + void slotActivated(const QModelIndex &); + +private: + ActionModel *m_model; +}; + +// Internal class that provides the icon view of actions. +class ActionListView: public QListView +{ + Q_OBJECT +public: + explicit ActionListView(ActionModel *model, QWidget *parent = 0); + QAction *currentAction() const; + +public slots: + void filter(const QString &text); + +signals: + void contextMenuRequested(QContextMenuEvent *event, QAction *); + void currentChanged(QAction *action); + void activated(QAction *action); + +protected slots: + virtual void currentChanged(const QModelIndex ¤t, const QModelIndex &previous); + +protected: + virtual void dragEnterEvent(QDragEnterEvent *event); + virtual void dragMoveEvent(QDragMoveEvent *event); + virtual void dropEvent(QDropEvent *event); + virtual void focusInEvent(QFocusEvent *event); + virtual void contextMenuEvent(QContextMenuEvent *event); + virtual void startDrag(Qt::DropActions supportedActions); + +private slots: + void slotActivated(const QModelIndex &); + +private: + ActionModel *m_model; +}; + +// Action View that can be switched between detailed and icon view +// using a QStackedWidget of ActionListView / ActionTreeView +// that share the item model and the selection model. + +class ActionView : public QStackedWidget { + Q_OBJECT +public: + // Separate initialize() function takes core argument to make this + // thing usable as promoted widget. + explicit ActionView(QWidget *parent = 0); + void initialize(QDesignerFormEditorInterface *core) { m_model->initialize(core); } + + // View mode + enum { DetailedView, IconView }; + int viewMode() const; + void setViewMode(int lm); + + void setSelectionMode(QAbstractItemView::SelectionMode sm); + QAbstractItemView::SelectionMode selectionMode() const; + + ActionModel *model() const { return m_model; } + + QAction *currentAction() const; + void setCurrentIndex(const QModelIndex &index); + + typedef QList ActionList; + ActionList selectedActions() const; + QItemSelection selection() const; + +public slots: + void filter(const QString &text); + void selectAll(); + void clearSelection(); + +signals: + void contextMenuRequested(QContextMenuEvent *event, QAction *); + void currentChanged(QAction *action); + void activated(QAction *action); + void selectionChanged(const QItemSelection& selected, const QItemSelection& deselected); + void resourceImageDropped(const QString &data, QAction *action); + +private slots: + void slotCurrentChanged(QAction *action); + +private: + ActionModel *m_model; + ActionTreeView *m_actionTreeView; + ActionListView *m_actionListView; +}; + +class QDESIGNER_SHARED_EXPORT ActionRepositoryMimeData: public QMimeData +{ + Q_OBJECT +public: + typedef QList ActionList; + + ActionRepositoryMimeData(const ActionList &, Qt::DropAction dropAction); + ActionRepositoryMimeData(QAction *, Qt::DropAction dropAction); + + const ActionList &actionList() const { return m_actionList; } + virtual QStringList formats() const; + + static QPixmap actionDragPixmap(const QAction *action); + + // Utility to accept with right action + void accept(QDragMoveEvent *event) const; +private: + const Qt::DropAction m_dropAction; + ActionList m_actionList; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // ACTIONREPOSITORY_H diff --git a/src/designer/src/lib/shared/addlinkdialog.ui b/src/designer/src/lib/shared/addlinkdialog.ui new file mode 100644 index 000000000..3171159f9 --- /dev/null +++ b/src/designer/src/lib/shared/addlinkdialog.ui @@ -0,0 +1,112 @@ + + AddLinkDialog + + + Insert Link + + + false + + + true + + + + + + + + Title: + + + + + + + + 337 + 0 + + + + + + + + URL: + + + + + + + + + + + + Qt::Vertical + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + AddLinkDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + AddLinkDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/designer/src/lib/shared/codedialog.cpp b/src/designer/src/lib/shared/codedialog.cpp new file mode 100644 index 000000000..2420aa54a --- /dev/null +++ b/src/designer/src/lib/shared/codedialog.cpp @@ -0,0 +1,262 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "codedialog_p.h" +#include "qdesigner_utils_p.h" +#include "iconloader_p.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { +// ----------------- CodeDialogPrivate +struct CodeDialog::CodeDialogPrivate { + CodeDialogPrivate(); + + QTextEdit *m_textEdit; + TextEditFindWidget *m_findWidget; + QString m_formFileName; +}; + +CodeDialog::CodeDialogPrivate::CodeDialogPrivate() + : m_textEdit(new QTextEdit) + , m_findWidget(new TextEditFindWidget) +{ +} + +// ----------------- CodeDialog +CodeDialog::CodeDialog(QWidget *parent) : + QDialog(parent), + m_impl(new CodeDialogPrivate) +{ + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + QVBoxLayout *vBoxLayout = new QVBoxLayout; + + // Edit tool bar + QToolBar *toolBar = new QToolBar; + + const QIcon saveIcon = createIconSet(QLatin1String("filesave.png")); + QAction *saveAction = toolBar->addAction(saveIcon, tr("Save...")); + connect(saveAction, SIGNAL(triggered()), this, SLOT(slotSaveAs())); + + const QIcon copyIcon = createIconSet(QLatin1String("editcopy.png")); + QAction *copyAction = toolBar->addAction(copyIcon, tr("Copy All")); + connect(copyAction, SIGNAL(triggered()), this, SLOT(copyAll())); + + QAction *findAction = toolBar->addAction( + TextEditFindWidget::findIconSet(), + tr("&Find in Text..."), + m_impl->m_findWidget, SLOT(activate())); + findAction->setShortcut(QKeySequence::Find); + + vBoxLayout->addWidget(toolBar); + + // Edit + m_impl->m_textEdit->setReadOnly(true); + m_impl->m_textEdit->setMinimumSize(QSize( + m_impl->m_findWidget->minimumSize().width(), + 500)); + vBoxLayout->addWidget(m_impl->m_textEdit); + + // Find + m_impl->m_findWidget->setTextEdit(m_impl->m_textEdit); + vBoxLayout->addWidget(m_impl->m_findWidget); + + // Button box + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + + // Disable auto default + QPushButton *closeButton = buttonBox->button(QDialogButtonBox::Close); + closeButton->setAutoDefault(false); + vBoxLayout->addWidget(buttonBox); + + setLayout(vBoxLayout); +} + +CodeDialog::~CodeDialog() +{ + delete m_impl; +} + +void CodeDialog::setCode(const QString &code) +{ + m_impl->m_textEdit->setPlainText(code); +} + +QString CodeDialog::code() const +{ + return m_impl->m_textEdit->toPlainText(); +} + +void CodeDialog::setFormFileName(const QString &f) +{ + m_impl->m_formFileName = f; +} + +QString CodeDialog::formFileName() const +{ + return m_impl->m_formFileName; +} + +bool CodeDialog::generateCode(const QDesignerFormWindowInterface *fw, + QString *code, + QString *errorMessage) +{ + // Generate temporary file name similar to form file name + // (for header guards) + QString tempPattern = QDir::tempPath(); + if (!tempPattern.endsWith(QDir::separator())) // platform-dependant + tempPattern += QDir::separator(); + const QString fileName = fw->fileName(); + if (fileName.isEmpty()) { + tempPattern += QLatin1String("designer"); + } else { + tempPattern += QFileInfo(fileName).baseName(); + } + tempPattern += QLatin1String("XXXXXX.ui"); + // Write to temp file + QTemporaryFile tempFormFile(tempPattern); + + tempFormFile.setAutoRemove(true); + if (!tempFormFile.open()) { + *errorMessage = tr("A temporary form file could not be created in %1.").arg(QDir::tempPath()); + return false; + } + const QString tempFormFileName = tempFormFile.fileName(); + tempFormFile.write(fw->contents().toUtf8()); + if (!tempFormFile.flush()) { + *errorMessage = tr("The temporary form file %1 could not be written.").arg(tempFormFileName); + return false; + } + tempFormFile.close(); + // Run uic + QByteArray rc; + if (!runUIC(tempFormFileName, UIC_GenerateCode, rc, *errorMessage)) + return false; + *code = QString::fromUtf8(rc); + return true; +} + +bool CodeDialog::showCodeDialog(const QDesignerFormWindowInterface *fw, + QWidget *parent, + QString *errorMessage) +{ + QString code; + if (!generateCode(fw, &code, errorMessage)) + return false; + + CodeDialog dialog(parent); + dialog.setWindowTitle(tr("%1 - [Code]").arg(fw->mainContainer()->windowTitle())); + dialog.setCode(code); + dialog.setFormFileName(fw->fileName()); + dialog.exec(); + return true; +} + +void CodeDialog::slotSaveAs() +{ + // build the default relative name 'ui_sth.h' + const QString headerSuffix = QString(QLatin1Char('h')); + QString filter; + const QString uiFile = formFileName(); + + if (!uiFile.isEmpty()) { + filter = QLatin1String("ui_"); + filter += QFileInfo(uiFile).baseName(); + filter += QLatin1Char('.'); + filter += headerSuffix; + } + // file dialog + while (true) { + const QString fileName = + QFileDialog::getSaveFileName (this, tr("Save Code"), filter, tr("Header Files (*.%1)").arg(headerSuffix)); + if (fileName.isEmpty()) + break; + + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly|QIODevice::Text)) { + warning(tr("The file %1 could not be opened: %2").arg(fileName).arg(file.errorString())); + continue; + } + file.write(code().toUtf8()); + if (!file.flush()) { + warning(tr("The file %1 could not be written: %2").arg(fileName).arg(file.errorString())); + continue; + } + file.close(); + break; + } +} + +void CodeDialog::warning(const QString &msg) +{ + QMessageBox::warning( + this, tr("%1 - Error").arg(windowTitle()), + msg, QMessageBox::Close); +} + +void CodeDialog::copyAll() +{ + QApplication::clipboard()->setText(code()); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/codedialog_p.h b/src/designer/src/lib/shared/codedialog_p.h new file mode 100644 index 000000000..bed7e224f --- /dev/null +++ b/src/designer/src/lib/shared/codedialog_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef CODEPREVIEWDIALOG_H +#define CODEPREVIEWDIALOG_H + +#include "shared_global_p.h" +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { +// Dialog for viewing code. +class QDESIGNER_SHARED_EXPORT CodeDialog : public QDialog +{ + Q_OBJECT + explicit CodeDialog(QWidget *parent = 0); +public: + virtual ~CodeDialog(); + + static bool generateCode(const QDesignerFormWindowInterface *fw, + QString *code, + QString *errorMessage); + + static bool showCodeDialog(const QDesignerFormWindowInterface *fw, + QWidget *parent, + QString *errorMessage); + +private slots: + void slotSaveAs(); + void copyAll(); + +private: + void setCode(const QString &code); + QString code() const; + void setFormFileName(const QString &f); + QString formFileName() const; + + void warning(const QString &msg); + + struct CodeDialogPrivate; + CodeDialogPrivate *m_impl; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // CODEPREVIEWDIALOG_H diff --git a/src/designer/src/lib/shared/connectionedit.cpp b/src/designer/src/lib/shared/connectionedit.cpp new file mode 100644 index 000000000..5f5085c17 --- /dev/null +++ b/src/designer/src/lib/shared/connectionedit.cpp @@ -0,0 +1,1612 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "connectionedit_p.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +static const int BG_ALPHA = 32; +static const int LINE_PROXIMITY_RADIUS = 3; +static const int LOOP_MARGIN = 20; +static const int VLABEL_MARGIN = 1; +static const int HLABEL_MARGIN = 3; +static const int GROUND_W = 20; +static const int GROUND_H = 25; + +/******************************************************************************* +** Tools +*/ + +static QRect fixRect(const QRect &r) +{ + return QRect(r.x(), r.y(), r.width() - 1, r.height() - 1); +} + +static QRect expand(const QRect &r, int i) +{ + return QRect(r.x() - i, r.y() - i, r.width() + 2*i, r.height() + 2*i); +} + +static QRect endPointRectHelper(const QPoint &pos) +{ + const QRect r(pos + QPoint(-LINE_PROXIMITY_RADIUS, -LINE_PROXIMITY_RADIUS), + QSize(2*LINE_PROXIMITY_RADIUS, 2*LINE_PROXIMITY_RADIUS)); + return r; +} + +static void paintGround(QPainter *p, QRect r) +{ + const QPoint mid = r.center(); + p->drawLine(mid.x(), r.top(), mid.x(), mid.y()); + p->drawLine(r.left(), mid.y(), r.right(), mid.y()); + int y = r.top() + 4*r.height()/6; + int x = GROUND_W/6; + p->drawLine(r.left() + x, y, r.right() - x, y); + y = r.top() + 5*r.height()/6; + x = 2*GROUND_W/6; + p->drawLine(r.left() + x, y, r.right() - x, y); + p->drawLine(mid.x(), r.bottom(), mid.x() + 1, r.bottom()); +} + +static void paintEndPoint(QPainter *p, const QPoint &pos) +{ + const QRect r(pos + QPoint(-LINE_PROXIMITY_RADIUS, -LINE_PROXIMITY_RADIUS), + QSize(2*LINE_PROXIMITY_RADIUS, 2*LINE_PROXIMITY_RADIUS)); + p->fillRect(fixRect(r), p->pen().color()); +} + +static qdesigner_internal::CETypes::LineDir classifyLine(const QPoint &p1, const QPoint &p2) +{ + if (p1.x() == p2.x()) + return p1.y() < p2.y() ? qdesigner_internal::CETypes::DownDir : qdesigner_internal::CETypes::UpDir; + Q_ASSERT(p1.y() == p2.y()); + return p1.x() < p2.x() ? qdesigner_internal::CETypes::RightDir : qdesigner_internal::CETypes::LeftDir; +} + +static QPoint pointInsideRect(const QRect &r, QPoint p) +{ + if (p.x() < r.left()) + p.setX(r.left()); + else if (p.x() > r.right()) + p.setX(r.right()); + + if (p.y() < r.top()) + p.setY(r.top()); + else if (p.y() > r.bottom()) + p.setY(r.bottom()); + + return p; +} + +namespace qdesigner_internal { + +/******************************************************************************* +** Commands +*/ + +AddConnectionCommand::AddConnectionCommand(ConnectionEdit *edit, Connection *con) + : CECommand(edit), m_con(con) +{ + setText(QApplication::translate("Command", "Add connection")); +} + +void AddConnectionCommand::redo() +{ + edit()->selectNone(); + emit edit()->aboutToAddConnection(edit()->m_con_list.size()); + edit()->m_con_list.append(m_con); + m_con->inserted(); + edit()->setSelected(m_con, true); + emit edit()->connectionAdded(m_con); +} + +void AddConnectionCommand::undo() +{ + const int idx = edit()->indexOfConnection(m_con); + emit edit()->aboutToRemoveConnection(m_con); + edit()->setSelected(m_con, false); + m_con->update(); + m_con->removed(); + edit()->m_con_list.removeAll(m_con); + emit edit()->connectionRemoved(idx); +} + +class AdjustConnectionCommand : public CECommand +{ +public: + AdjustConnectionCommand(ConnectionEdit *edit, Connection *con, + const QPoint &old_source_pos, + const QPoint &old_target_pos, + const QPoint &new_source_pos, + const QPoint &new_target_pos); + virtual void redo(); + virtual void undo(); +private: + Connection *m_con; + const QPoint m_old_source_pos; + const QPoint m_old_target_pos; + const QPoint m_new_source_pos; + const QPoint m_new_target_pos; +}; + +AdjustConnectionCommand::AdjustConnectionCommand(ConnectionEdit *edit, Connection *con, + const QPoint &old_source_pos, + const QPoint &old_target_pos, + const QPoint &new_source_pos, + const QPoint &new_target_pos) : + CECommand(edit), + m_con(con), + m_old_source_pos(old_source_pos), + m_old_target_pos(old_target_pos), + m_new_source_pos(new_source_pos), + m_new_target_pos(new_target_pos) +{ + setText(QApplication::translate("Command", "Adjust connection")); +} + +void AdjustConnectionCommand::undo() +{ + m_con->setEndPoint(EndPoint::Source, m_con->widget(EndPoint::Source), m_old_source_pos); + m_con->setEndPoint(EndPoint::Target, m_con->widget(EndPoint::Target), m_old_target_pos); +} + +void AdjustConnectionCommand::redo() +{ + m_con->setEndPoint(EndPoint::Source, m_con->widget(EndPoint::Source), m_new_source_pos); + m_con->setEndPoint(EndPoint::Target, m_con->widget(EndPoint::Target), m_new_target_pos); +} + +DeleteConnectionsCommand::DeleteConnectionsCommand(ConnectionEdit *edit, + const ConnectionList &con_list) + : CECommand(edit), m_con_list(con_list) +{ + setText(QApplication::translate("Command", "Delete connections")); +} + +void DeleteConnectionsCommand::redo() +{ + foreach (Connection *con, m_con_list) { + const int idx = edit()->indexOfConnection(con); + emit edit()->aboutToRemoveConnection(con); + Q_ASSERT(edit()->m_con_list.contains(con)); + edit()->setSelected(con, false); + con->update(); + con->removed(); + edit()->m_con_list.removeAll(con); + emit edit()->connectionRemoved(idx); + } +} + +void DeleteConnectionsCommand::undo() +{ + foreach (Connection *con, m_con_list) { + Q_ASSERT(!edit()->m_con_list.contains(con)); + emit edit()->aboutToAddConnection(edit()->m_con_list.size()); + edit()->m_con_list.append(con); + edit()->setSelected(con, true); + con->update(); + con->inserted(); + emit edit()->connectionAdded(con); + } +} + +class SetEndPointCommand : public CECommand +{ +public: + SetEndPointCommand(ConnectionEdit *edit, Connection *con, EndPoint::Type type, QObject *object); + virtual void redo(); + virtual void undo(); +private: + Connection *m_con; + const EndPoint::Type m_type; + QObject *m_old_widget, *m_new_widget; + const QPoint m_old_pos; + QPoint m_new_pos; +}; + +SetEndPointCommand::SetEndPointCommand(ConnectionEdit *edit, Connection *con, + EndPoint::Type type, QObject *object) : + CECommand(edit), + m_con(con), + m_type(type), + m_old_widget(con->object(type)), + m_new_widget(object), + m_old_pos(con->endPointPos(type)) +{ + if (QWidget *widget = qobject_cast(object)) { + m_new_pos = edit->widgetRect(widget).center(); + } + + if (m_type == EndPoint::Source) + setText(QApplication::translate("Command", "Change source")); + else + setText(QApplication::translate("Command", "Change target")); +} + +void SetEndPointCommand::redo() +{ + m_con->setEndPoint(m_type, m_new_widget, m_new_pos); + emit edit()->connectionChanged(m_con); +} + +void SetEndPointCommand::undo() +{ + m_con->setEndPoint(m_type, m_old_widget, m_old_pos); + emit edit()->connectionChanged(m_con); +} + +/******************************************************************************* +** Connection +*/ + +Connection::Connection(ConnectionEdit *edit) : + m_source_pos(QPoint(-1, -1)), + m_target_pos(QPoint(-1, -1)), + m_source(0), + m_target(0), + m_edit(edit), + m_visible(true) +{ + +} + +Connection::Connection(ConnectionEdit *edit, QObject *source, QObject *target) : + m_source_pos(QPoint(-1, -1)), + m_target_pos(QPoint(-1, -1)), + m_source(source), + m_target(target), + m_edit(edit), + m_visible(true) +{ +} + +void Connection::setVisible(bool b) +{ + m_visible = b; +} + +void Connection::updateVisibility() +{ + QWidget *source = widget(EndPoint::Source); + QWidget *target = widget(EndPoint::Target); + + if (source == 0 || target == 0) { + setVisible(false); + return; + } + + QWidget *w = source; + while (w && w->parentWidget()) { + if (!w->isVisibleTo(w->parentWidget())) { + setVisible(false); + return; + } + w = w->parentWidget(); + } + + w = target; + while (w && w->parentWidget()) { + if (!w->isVisibleTo(w->parentWidget())) { + setVisible(false); + return; + } + w = w->parentWidget(); + } + + setVisible(true); +} + +bool Connection::isVisible() const +{ + return m_visible; +} + +bool Connection::ground() const +{ + return m_target != 0 && m_target == m_edit->m_bg_widget; +} + +QPoint Connection::endPointPos(EndPoint::Type type) const +{ + if (type == EndPoint::Source) + return m_source_pos; + else + return m_target_pos; +} + +static QPoint lineEntryPos(const QPoint &p1, const QPoint &p2, const QRect &rect) +{ + QPoint result; + + switch (classifyLine(p1, p2)) { + case CETypes::UpDir: + result = QPoint(p1.x(), rect.bottom()); + break; + case CETypes::DownDir: + result = QPoint(p1.x(), rect.top()); + break; + case CETypes::LeftDir: + result = QPoint(rect.right(), p1.y()); + break; + case CETypes::RightDir: + result = QPoint(rect.left(), p1.y()); + break; + } + + return result; +} + +static QPolygonF arrowHead(const QPoint &p1, const QPoint &p2) +{ + QPolygonF result; + + switch (classifyLine(p1, p2)) { + case CETypes::UpDir: + result.append(p2 + QPoint(0, 1)); + result.append(p2 + QPoint(LINE_PROXIMITY_RADIUS, LINE_PROXIMITY_RADIUS*2 + 1)); + result.append(p2 + QPoint(-LINE_PROXIMITY_RADIUS, LINE_PROXIMITY_RADIUS*2 + 1)); + break; + case CETypes::DownDir: + result.append(p2); + result.append(p2 + QPoint(LINE_PROXIMITY_RADIUS, -LINE_PROXIMITY_RADIUS*2)); + result.append(p2 + QPoint(-LINE_PROXIMITY_RADIUS, -LINE_PROXIMITY_RADIUS*2)); + break; + case CETypes::LeftDir: + result.append(p2 + QPoint(1, 0)); + result.append(p2 + QPoint(2*LINE_PROXIMITY_RADIUS + 1, -LINE_PROXIMITY_RADIUS)); + result.append(p2 + QPoint(2*LINE_PROXIMITY_RADIUS + 1, LINE_PROXIMITY_RADIUS)); + break; + case CETypes::RightDir: + result.append(p2); + result.append(p2 + QPoint(-2*LINE_PROXIMITY_RADIUS, -LINE_PROXIMITY_RADIUS)); + result.append(p2 + QPoint(-2*LINE_PROXIMITY_RADIUS, LINE_PROXIMITY_RADIUS)); + break; + } + + return result; +} + +static CETypes::LineDir closestEdge(const QPoint &p, const QRect &r) +{ + CETypes::LineDir result = CETypes::UpDir; + int min = p.y() - r.top(); + + int d = p.x() - r.left(); + if (d < min) { + min = d; + result = CETypes::LeftDir; + } + + d = r.bottom() - p.y(); + if (d < min) { + min = d; + result = CETypes::DownDir; + } + + d = r.right() - p.x(); + if (d < min) { + min = d; + result = CETypes::RightDir; + } + + return result; +} + +static bool pointAboveLine(const QPoint &l1, const QPoint &l2, const QPoint &p) +{ + if (l1.x() == l2.x()) + return p.x() >= l1.x(); + return p.y() <= l1.y() + (p.x() - l1.x())*(l2.y() - l1.y())/(l2.x() - l1.x()); +} + +void Connection::updateKneeList() +{ + const LineDir old_source_label_dir = labelDir(EndPoint::Source); + const LineDir old_target_label_dir = labelDir(EndPoint::Target); + + QPoint s = endPointPos(EndPoint::Source); + QPoint t = endPointPos(EndPoint::Target); + const QRect sr = m_source_rect; + const QRect tr = m_target_rect; + + m_knee_list.clear(); + m_arrow_head.clear(); + + if (m_source == 0 || s == QPoint(-1, -1) || t == QPoint(-1, -1)) + return; + + const QRect r = sr | tr; + + m_knee_list.append(s); + if (m_target == 0) { + m_knee_list.append(QPoint(t.x(), s.y())); + } else if (m_target == m_edit->m_bg_widget) { + m_knee_list.append(QPoint(s.x(), t.y())); + } else if (tr.contains(sr) || sr.contains(tr)) { +/* + +------------------+ + | +----------+ | + | | | | + | | o | | + | +---|------+ | + | | x | + +-----|-----|------+ + +-----+ + + We find out which edge of the outer rectangle is closest to the target + point, and make a loop which exits and re-enters through that edge. +*/ + const LineDir dir = closestEdge(t, tr); + switch (dir) { + case UpDir: + m_knee_list.append(QPoint(s.x(), r.top() - LOOP_MARGIN)); + m_knee_list.append(QPoint(t.x(), r.top() - LOOP_MARGIN)); + break; + case DownDir: + m_knee_list.append(QPoint(s.x(), r.bottom() + LOOP_MARGIN)); + m_knee_list.append(QPoint(t.x(), r.bottom() + LOOP_MARGIN)); + break; + case LeftDir: + m_knee_list.append(QPoint(r.left() - LOOP_MARGIN, s.y())); + m_knee_list.append(QPoint(r.left() - LOOP_MARGIN, t.y())); + break; + case RightDir: + m_knee_list.append(QPoint(r.right() + LOOP_MARGIN, s.y())); + m_knee_list.append(QPoint(r.right() + LOOP_MARGIN, t.y())); + break; + } + } else { + if (r.height() < sr.height() + tr.height()) { + if ((s.y() >= tr.top() && s.y() <= tr.bottom()) || (t.y() >= sr.bottom() || t.y() <= sr.top())) { +/* + +--------+ + | | +--------+ + | o--+---+--x | + | o | | | + +-----|--+ | | + +------+--x | + +--------+ + + When dragging one end point, move the other end point to the same y position, + if that does not cause it to exit it's rectangle. +*/ + if (m_edit->state() == ConnectionEdit::Dragging) { + if (m_edit->m_drag_end_point.type == EndPoint::Source) { + const QPoint p(t.x(), s.y()); + m_knee_list.append(p); + if (tr.contains(p)) + t = m_target_pos = p; + } else { + const QPoint p(s.x(), t.y()); + m_knee_list.append(p); + if (sr.contains(p)) + s = m_source_pos = p; + } + } else { + m_knee_list.append(QPoint(s.x(), t.y())); + } + } else { +/* + +--------+ + | o----+-------+ + | | +---|----+ + +--------+ | | | + | x | + +--------+ +*/ + m_knee_list.append(QPoint(t.x(), s.y())); + } + } else if (r.width() < sr.width() + tr.width()) { + if ((s.x() >= tr.left() && s.x() <= tr.right()) || t.x() >= sr.right() || t.x() <= sr.left()) { +/* + +--------+ + | | + | o o+--+ + +----|---+ | + +-|------|-+ + | x x | + | | + +----------+ + + When dragging one end point, move the other end point to the same x position, + if that does not cause it to exit it's rectangle. +*/ + if (m_edit->state() == ConnectionEdit::Dragging) { + if (m_edit->m_drag_end_point.type == EndPoint::Source) { + const QPoint p(s.x(), t.y()); + m_knee_list.append(p); + if (tr.contains(p)) + t = m_target_pos = p; + } else { + const QPoint p(t.x(), s.y()); + m_knee_list.append(p); + if (sr.contains(p)) + s = m_source_pos = p; + } + } else { + m_knee_list.append(QPoint(t.x(), s.y())); + } + } else { +/* + +--------+ + | | + | o | + +--|-----+ + | +--------+ + +---+-x | + | | + +--------+ + +*/ + m_knee_list.append(QPoint(s.x(), t.y())); + } + } else { +/* + +--------+ + | | + | o o-+--------+ + +--|-----+ | + | +-----|--+ + | | x | + +--------+-x | + +--------+ + + The line enters the target rectangle through the closest edge. +*/ + if (sr.topLeft() == r.topLeft()) { + if (pointAboveLine(tr.topLeft(), tr.bottomRight(), t)) + m_knee_list.append(QPoint(t.x(), s.y())); + else + m_knee_list.append(QPoint(s.x(), t.y())); + } else if (sr.topRight() == r.topRight()) { + if (pointAboveLine(tr.bottomLeft(), tr.topRight(), t)) + m_knee_list.append(QPoint(t.x(), s.y())); + else + m_knee_list.append(QPoint(s.x(), t.y())); + } else if (sr.bottomRight() == r.bottomRight()) { + if (pointAboveLine(tr.topLeft(), tr.bottomRight(), t)) + m_knee_list.append(QPoint(s.x(), t.y())); + else + m_knee_list.append(QPoint(t.x(), s.y())); + } else { + if (pointAboveLine(tr.bottomLeft(), tr.topRight(), t)) + m_knee_list.append(QPoint(s.x(), t.y())); + else + m_knee_list.append(QPoint(t.x(), s.y())); + } + } + } + m_knee_list.append(t); + + if (m_knee_list.size() == 2) + m_knee_list.clear(); + + trimLine(); + + const LineDir new_source_label_dir = labelDir(EndPoint::Source); + const LineDir new_target_label_dir = labelDir(EndPoint::Target); + if (new_source_label_dir != old_source_label_dir) + updatePixmap(EndPoint::Source); + if (new_target_label_dir != old_target_label_dir) + updatePixmap(EndPoint::Target); +} + +void Connection::trimLine() +{ + if (m_source == 0 || m_source_pos == QPoint(-1, -1) || m_target_pos == QPoint(-1, -1)) + return; + int cnt = m_knee_list.size(); + if (cnt < 2) + return; + + const QRect sr = m_source_rect; + const QRect tr = m_target_rect; + + if (sr.contains(m_knee_list.at(1))) + m_knee_list.removeFirst(); + + cnt = m_knee_list.size(); + if (cnt < 2) + return; + + if (!tr.contains(sr) && tr.contains(m_knee_list.at(cnt - 2))) + m_knee_list.removeLast(); + + cnt = m_knee_list.size(); + if (cnt < 2) + return; + + if (sr.contains(m_knee_list.at(0)) && !sr.contains(m_knee_list.at(1))) + m_knee_list[0] = lineEntryPos(m_knee_list.at(1), m_knee_list.at(0), sr); + + if (tr.contains(m_knee_list.at(cnt - 1)) && !tr.contains(m_knee_list.at(cnt - 2))) { + m_knee_list[cnt - 1] + = lineEntryPos(m_knee_list.at(cnt - 2), m_knee_list.at(cnt - 1), tr); + m_arrow_head = arrowHead(m_knee_list.at(cnt - 2), m_knee_list.at(cnt - 1)); + } +} + +void Connection::setSource(QObject *source, const QPoint &pos) +{ + if (source == m_source && m_source_pos == pos) + return; + + update(false); + + m_source = source; + if (QWidget *widget = qobject_cast(source)) { + m_source_pos = pos; + m_source_rect = m_edit->widgetRect(widget); + updateKneeList(); + } + + update(false); +} + +void Connection::setTarget(QObject *target, const QPoint &pos) +{ + if (target == m_target && m_target_pos == pos) + return; + + update(false); + + m_target = target; + if (QWidget *widget = qobject_cast(target)) { + m_target_pos = pos; + m_target_rect = m_edit->widgetRect(widget); + updateKneeList(); + } + + update(false); +} + +static QRect lineRect(const QPoint &a, const QPoint &b) +{ + const QPoint c(qMin(a.x(), b.x()), qMin(a.y(), b.y())); + const QPoint d(qMax(a.x(), b.x()), qMax(a.y(), b.y())); + + QRect result(c, d); + return expand(result, LINE_PROXIMITY_RADIUS); +} + +QRect Connection::groundRect() const +{ + if (!ground()) + return QRect(); + if (m_knee_list.isEmpty()) + return QRect(); + + const QPoint p = m_knee_list.last(); + return QRect(p.x() - GROUND_W/2, p.y(), GROUND_W, GROUND_H); +} + +QRegion Connection::region() const +{ + QRegion result; + + for (int i = 0; i < m_knee_list.size() - 1; ++i) + result = result.unite(lineRect(m_knee_list.at(i), m_knee_list.at(i + 1))); + + if (!m_arrow_head.isEmpty()) { + QRect r = m_arrow_head.boundingRect().toRect(); + r = expand(r, 1); + result = result.unite(r); + } else if (ground()) { + result = result.unite(groundRect()); + } + + result = result.unite(labelRect(EndPoint::Source)); + result = result.unite(labelRect(EndPoint::Target)); + + return result; +} + +void Connection::update(bool update_widgets) const +{ + m_edit->update(region()); + if (update_widgets) { + if (m_source != 0) + m_edit->update(m_source_rect); + if (m_target != 0) + m_edit->update(m_target_rect); + } + + m_edit->update(endPointRect(EndPoint::Source)); + m_edit->update(endPointRect(EndPoint::Target)); +} + +void Connection::paint(QPainter *p) const +{ + for (int i = 0; i < m_knee_list.size() - 1; ++i) + p->drawLine(m_knee_list.at(i), m_knee_list.at(i + 1)); + + if (!m_arrow_head.isEmpty()) { + p->save(); + p->setBrush(p->pen().color()); + p->drawPolygon(m_arrow_head); + p->restore(); + } else if (ground()) { + paintGround(p, groundRect()); + } +} + +bool Connection::contains(const QPoint &pos) const +{ + return region().contains(pos); +} + +QRect Connection::endPointRect(EndPoint::Type type) const +{ + if (type == EndPoint::Source) { + if (m_source_pos != QPoint(-1, -1)) + return endPointRectHelper(m_source_pos); + } else { + if (m_target_pos != QPoint(-1, -1)) + return endPointRectHelper(m_target_pos); + } + return QRect(); +} + +CETypes::LineDir Connection::labelDir(EndPoint::Type type) const +{ + const int cnt = m_knee_list.size(); + if (cnt < 2) + return RightDir; + + LineDir dir; + if (type == EndPoint::Source) + dir = classifyLine(m_knee_list.at(0), m_knee_list.at(1)); + else + dir = classifyLine(m_knee_list.at(cnt - 2), m_knee_list.at(cnt - 1)); + + if (dir == LeftDir) + dir = RightDir; + if (dir == UpDir) + dir = DownDir; + + return dir; +} + +QRect Connection::labelRect(EndPoint::Type type) const +{ + const int cnt = m_knee_list.size(); + if (cnt < 2) + return QRect(); + const QString text = label(type); + if (text.isEmpty()) + return QRect(); + + const QSize size = labelPixmap(type).size(); + QPoint p1, p2; + if (type == EndPoint::Source) { + p1 = m_knee_list.at(0); + p2 = m_knee_list.at(1); + } else { + p1 = m_knee_list.at(cnt - 1); + p2 = m_knee_list.at(cnt - 2); + } + const LineDir dir = classifyLine(p1, p2); + + QRect result; + switch (dir) { + case UpDir: + result = QRect(p1 + QPoint(-size.width()/2, 0), size); + break; + case DownDir: + result = QRect(p1 + QPoint(-size.width()/2, -size.height()), size); + break; + case LeftDir: + result = QRect(p1 + QPoint(0, -size.height()/2), size); + break; + case RightDir: + result = QRect(p1 + QPoint(-size.width(), -size.height()/2), size); + break; + } + + return result; +} + +void Connection::setLabel(EndPoint::Type type, const QString &text) +{ + if (text == label(type)) + return; + + if (type == EndPoint::Source) + m_source_label = text; + else + m_target_label = text; + + updatePixmap(type); +} + +void Connection::updatePixmap(EndPoint::Type type) +{ + QPixmap *pm = type == EndPoint::Source ? &m_source_label_pm : &m_target_label_pm; + + const QString text = label(type); + if (text.isEmpty()) { + *pm = QPixmap(); + return; + } + + const QFontMetrics fm = m_edit->fontMetrics(); + const QSize size = fm.size(Qt::TextSingleLine, text) + QSize(HLABEL_MARGIN*2, VLABEL_MARGIN*2); + *pm = QPixmap(size); + QColor color = m_edit->palette().color(QPalette::Normal, QPalette::Base); + color.setAlpha(190); + pm->fill(color); + + QPainter p(pm); + p.setPen(m_edit->palette().color(QPalette::Normal, QPalette::Text)); + p.drawText(-fm.leftBearing(text.at(0)) + HLABEL_MARGIN, fm.ascent() + VLABEL_MARGIN, text); + p.end(); + + const LineDir dir = labelDir(type); + + if (dir == DownDir) + *pm = pm->transformed(QMatrix(0.0, -1.0, 1.0, 0.0, 0.0, 0.0)); +} + +void Connection::checkWidgets() +{ + bool changed = false; + + if (QWidget *sourceWidget = qobject_cast(m_source)) { + const QRect r = m_edit->widgetRect(sourceWidget); + if (r != m_source_rect) { + if (m_source_pos != QPoint(-1, -1) && !r.contains(m_source_pos)) { + QPoint offset = m_source_pos - m_source_rect.topLeft(); + QPoint old_pos = m_source_pos; + m_source_pos = pointInsideRect(r, r.topLeft() + offset); + } + m_edit->update(m_source_rect); + m_source_rect = r; + changed = true; + } + } + + if (QWidget *targetWidget = qobject_cast(m_target)) { + const QRect r = m_edit->widgetRect(targetWidget); + if (r != m_target_rect) { + if (m_target_pos != QPoint(-1, -1) && !r.contains(m_target_pos)) { + const QPoint offset = m_target_pos - m_target_rect.topLeft(); + const QPoint old_pos = m_target_pos; + m_target_pos = pointInsideRect(r, r.topLeft() + offset); + } + m_edit->update(m_target_rect); + m_target_rect = r; + changed = true; + } + } + + if (changed) { + update(); + updateKneeList(); + update(); + } +} + +/******************************************************************************* +** ConnectionEdit +*/ + +ConnectionEdit::ConnectionEdit(QWidget *parent, QDesignerFormWindowInterface *form) : + QWidget(parent), + m_bg_widget(0), + m_undo_stack(form->commandHistory()), + m_enable_update_background(false), + m_tmp_con(0), + m_start_connection_on_drag(true), + m_widget_under_mouse(0), + m_inactive_color(Qt::blue), + m_active_color(Qt::red) +{ + setAttribute(Qt::WA_MouseTracking, true); + setFocusPolicy(Qt::ClickFocus); + + connect(form, SIGNAL(widgetRemoved(QWidget*)), this, SLOT(widgetRemoved(QWidget*))); + connect(form, SIGNAL(objectRemoved(QObject*)), this, SLOT(objectRemoved(QObject*))); +} + +ConnectionEdit::~ConnectionEdit() +{ + qDeleteAll(m_con_list); +} + +void ConnectionEdit::clear() +{ + m_con_list.clear(); + m_sel_con_set.clear(); + m_bg_widget = 0; + m_widget_under_mouse = 0; + m_tmp_con = 0; +} + +void ConnectionEdit::setBackground(QWidget *background) +{ + if (background == m_bg_widget) { + // nothing to do + return; + } + + m_bg_widget = background; + updateBackground(); +} + +void ConnectionEdit::enableUpdateBackground(bool enable) +{ + m_enable_update_background = enable; + if (enable) + updateBackground(); +} + +void ConnectionEdit::updateBackground() +{ + // Might happen while reloading a form. + if (m_bg_widget == 0) + return; + + if (!m_enable_update_background) + return; + + foreach(Connection *c, m_con_list) + c->updateVisibility(); + + updateLines(); + update(); +} + +QWidget *ConnectionEdit::widgetAt(const QPoint &pos) const +{ + if (m_bg_widget == 0) + return 0; + QWidget *widget = m_bg_widget->childAt(pos); + if (widget == 0) + widget = m_bg_widget; + + return widget; +} + + +QRect ConnectionEdit::widgetRect(QWidget *w) const +{ + if (w == 0) + return QRect(); + QRect r = w->geometry(); + QPoint pos = w->mapToGlobal(QPoint(0, 0)); + pos = mapFromGlobal(pos); + r.moveTopLeft(pos); + return r; +} + +ConnectionEdit::State ConnectionEdit::state() const +{ + if (m_tmp_con != 0) + return Connecting; + if (!m_drag_end_point.isNull()) + return Dragging; + return Editing; +} + +void ConnectionEdit::paintLabel(QPainter *p, EndPoint::Type type, Connection *con) +{ + if (con->label(type).isEmpty()) + return; + + const bool heavy = selected(con) || con == m_tmp_con; + p->setPen(heavy ? m_active_color : m_inactive_color); + p->setBrush(Qt::NoBrush); + const QRect r = con->labelRect(type); + p->drawPixmap(r.topLeft(), con->labelPixmap(type)); + p->drawRect(fixRect(r)); +} + +void ConnectionEdit::paintConnection(QPainter *p, Connection *con, + WidgetSet *heavy_highlight_set, + WidgetSet *light_highlight_set) const +{ + QWidget *source = con->widget(EndPoint::Source); + QWidget *target = con->widget(EndPoint::Target); + + const bool heavy = selected(con) || con == m_tmp_con; + WidgetSet *set = heavy ? heavy_highlight_set : light_highlight_set; + p->setPen(heavy ? m_active_color : m_inactive_color); + con->paint(p); + + if (source != 0 && source != m_bg_widget) + set->insert(source, source); + + if (target != 0 && target != m_bg_widget) + set->insert(target, target); +} + +void ConnectionEdit::paintEvent(QPaintEvent *e) +{ + QPainter p(this); + p.setClipRegion(e->region()); + + WidgetSet heavy_highlight_set, light_highlight_set; + + foreach (Connection *con, m_con_list) { + if (!con->isVisible()) + continue; + + paintConnection(&p, con, &heavy_highlight_set, &light_highlight_set); + } + + if (m_tmp_con != 0) + paintConnection(&p, m_tmp_con, &heavy_highlight_set, &light_highlight_set); + + if (!m_widget_under_mouse.isNull() && m_widget_under_mouse != m_bg_widget) + heavy_highlight_set.insert(m_widget_under_mouse, m_widget_under_mouse); + + QColor c = m_active_color; + p.setPen(c); + c.setAlpha(BG_ALPHA); + p.setBrush(c); + + foreach (QWidget *w, heavy_highlight_set) { + p.drawRect(fixRect(widgetRect(w))); + light_highlight_set.remove(w); + } + + c = m_inactive_color; + p.setPen(c); + c.setAlpha(BG_ALPHA); + p.setBrush(c); + + foreach (QWidget *w, light_highlight_set) + p.drawRect(fixRect(widgetRect(w))); + + p.setBrush(palette().color(QPalette::Base)); + p.setPen(palette().color(QPalette::Text)); + foreach (Connection *con, m_con_list) { + if (!con->isVisible()) + continue; + + paintLabel(&p, EndPoint::Source, con); + paintLabel(&p, EndPoint::Target, con); + } + + p.setPen(m_active_color); + p.setBrush(m_active_color); + + foreach (Connection *con, m_con_list) { + if (!selected(con) || !con->isVisible()) + continue; + + paintEndPoint(&p, con->endPointPos(EndPoint::Source)); + + if (con->widget(EndPoint::Target) != 0) + paintEndPoint(&p, con->endPointPos(EndPoint::Target)); + } +} + +void ConnectionEdit::abortConnection() +{ + m_tmp_con->update(); + delete m_tmp_con; + m_tmp_con = 0; +#ifndef QT_NO_CURSOR + setCursor(QCursor()); +#endif + if (m_widget_under_mouse == m_bg_widget) + m_widget_under_mouse = 0; +} + +void ConnectionEdit::mousePressEvent(QMouseEvent *e) +{ + // Right click only to cancel + const Qt::MouseButton button = e->button(); + const State cstate = state(); + if (button != Qt::LeftButton && !(button == Qt::RightButton && cstate == Connecting)) { + QWidget::mousePressEvent(e); + return; + } + + e->accept(); + // Prefer a non-background widget over the connection, + // otherwise, widgets covered by the connection labels cannot be accessed + Connection *con_under_mouse = 0; + if (!m_widget_under_mouse || m_widget_under_mouse == m_bg_widget) + con_under_mouse = connectionAt(e->pos()); + + m_start_connection_on_drag = false; + switch (cstate) { + case Connecting: + if (button == Qt::RightButton) + abortConnection(); + break; + case Dragging: + break; + case Editing: + if (!m_end_point_under_mouse.isNull()) { + if (!(e->modifiers() & Qt::ShiftModifier)) { + startDrag(m_end_point_under_mouse, e->pos()); + } + } else if (con_under_mouse != 0) { + if (!(e->modifiers() & Qt::ShiftModifier)) { + selectNone(); + setSelected(con_under_mouse, true); + } else { + setSelected(con_under_mouse, !selected(con_under_mouse)); + } + } else { + if (!(e->modifiers() & Qt::ShiftModifier)) { + selectNone(); + if (!m_widget_under_mouse.isNull()) + m_start_connection_on_drag = true; + } + } + break; + } +} + +void ConnectionEdit::mouseDoubleClickEvent(QMouseEvent *e) +{ + if (e->button() != Qt::LeftButton) { + QWidget::mouseDoubleClickEvent(e); + return; + } + + e->accept(); + switch (state()) { + case Connecting: + abortConnection(); + break; + case Dragging: + break; + case Editing: + if (!m_widget_under_mouse.isNull()) { + emit widgetActivated(m_widget_under_mouse); + } else if (m_sel_con_set.size() == 1) { + Connection *con = m_sel_con_set.keys().first(); + modifyConnection(con); + } + break; + } + +} + +void ConnectionEdit::mouseReleaseEvent(QMouseEvent *e) +{ + if (e->button() != Qt::LeftButton) { + QWidget::mouseReleaseEvent(e); + return; + } + e->accept(); + + switch (state()) { + case Connecting: + if (m_widget_under_mouse.isNull()) + abortConnection(); + else + endConnection(m_widget_under_mouse, e->pos()); +#ifndef QT_NO_CURSOR + setCursor(QCursor()); +#endif + break; + case Editing: + break; + case Dragging: + endDrag(e->pos()); + break; + } +} + + +void ConnectionEdit::findObjectsUnderMouse(const QPoint &pos) +{ + Connection *con_under_mouse = connectionAt(pos); + + QWidget *w = widgetAt(pos); + // Prefer a non-background widget over the connection, + // otherwise, widgets covered by the connection labels cannot be accessed + if (w == m_bg_widget && con_under_mouse) + w = 0; + else + con_under_mouse = 0; + + if (w != m_widget_under_mouse) { + if (!m_widget_under_mouse.isNull()) + update(widgetRect(m_widget_under_mouse)); + m_widget_under_mouse = w; + if (!m_widget_under_mouse.isNull()) + update(widgetRect(m_widget_under_mouse)); + } + + const EndPoint hs = endPointAt(pos); + if (hs != m_end_point_under_mouse) { +#ifndef QT_NO_CURSOR + if (m_end_point_under_mouse.isNull()) + setCursor(Qt::PointingHandCursor); + else + setCursor(QCursor()); +#endif + m_end_point_under_mouse = hs; + } +} + +void ConnectionEdit::mouseMoveEvent(QMouseEvent *e) +{ + findObjectsUnderMouse(e->pos()); + switch (state()) { + case Connecting: + continueConnection(m_widget_under_mouse, e->pos()); + break; + case Editing: + if ((e->buttons() & Qt::LeftButton) + && m_start_connection_on_drag + && !m_widget_under_mouse.isNull()) { + m_start_connection_on_drag = false; + startConnection(m_widget_under_mouse, e->pos()); +#ifndef QT_NO_CURSOR + setCursor(Qt::CrossCursor); +#endif + } + break; + case Dragging: + continueDrag(e->pos()); + break; + } + + e->accept(); +} + +void ConnectionEdit::keyPressEvent(QKeyEvent *e) +{ + switch (e->key()) { + case Qt::Key_Delete: + if (state() == Editing) + deleteSelected(); + break; + case Qt::Key_Escape: + if (state() == Connecting) + abortConnection(); + break; + } + + e->accept(); +} + +void ConnectionEdit::startConnection(QWidget *source, const QPoint &pos) +{ + Q_ASSERT(m_tmp_con == 0); + + m_tmp_con = new Connection(this); + m_tmp_con->setEndPoint(EndPoint::Source, source, pos); +} + +void ConnectionEdit::endConnection(QWidget *target, const QPoint &pos) +{ + Q_ASSERT(m_tmp_con != 0); + + m_tmp_con->setEndPoint(EndPoint::Target, target, pos); + + QWidget *source = m_tmp_con->widget(EndPoint::Source); + Q_ASSERT(source != 0); + Q_ASSERT(target != 0); + setEnabled(false); + Connection *new_con = createConnection(source, target); + setEnabled(true); + if (new_con != 0) { + new_con->setEndPoint(EndPoint::Source, source, m_tmp_con->endPointPos(EndPoint::Source)); + new_con->setEndPoint(EndPoint::Target, target, m_tmp_con->endPointPos(EndPoint::Target)); + m_undo_stack->push(new AddConnectionCommand(this, new_con)); + emit connectionChanged(new_con); + } + + delete m_tmp_con; + m_tmp_con = 0; + + findObjectsUnderMouse(mapFromGlobal(QCursor::pos())); +} + +void ConnectionEdit::continueConnection(QWidget *target, const QPoint &pos) +{ + Q_ASSERT(m_tmp_con != 0); + + m_tmp_con->setEndPoint(EndPoint::Target, target, pos); +} + +void ConnectionEdit::modifyConnection(Connection *) +{ +} + +Connection *ConnectionEdit::createConnection(QWidget *source, QWidget *target) +{ + Connection *con = new Connection(this, source, target); + return con; +} + +// Find all connections which in which a sequence of objects is involved +template +static ConnectionEdit::ConnectionSet findConnectionsOf(const ConnectionEdit::ConnectionList &cl, ObjectIterator oi1, const ObjectIterator &oi2) +{ + ConnectionEdit::ConnectionSet rc; + + const ConnectionEdit::ConnectionList::const_iterator ccend = cl.constEnd(); + for ( ; oi1 != oi2; ++oi1) { + for (ConnectionEdit::ConnectionList::const_iterator cit = cl.constBegin(); cit != ccend; ++cit) { + Connection *con = *cit; + if (con->object(ConnectionEdit::EndPoint::Source) == *oi1 || con->object(ConnectionEdit::EndPoint::Target) == *oi1) + rc.insert(con, con); + } + } + return rc; +} + +void ConnectionEdit::widgetRemoved(QWidget *widget) +{ + // Remove all connections of that widget and its children. + if (m_con_list.empty()) + return; + + QWidgetList child_list = widget->findChildren(); + child_list.prepend(widget); + + const ConnectionSet remove_set = findConnectionsOf(m_con_list, child_list.constBegin(), child_list.constEnd()); + + if (!remove_set.isEmpty()) + m_undo_stack->push(new DeleteConnectionsCommand(this, remove_set.keys())); + + updateBackground(); +} + +void ConnectionEdit::objectRemoved(QObject *o) +{ + // Remove all connections of that object and its children (in case of action groups). + if (m_con_list.empty()) + return; + + QObjectList child_list = o->children(); + child_list.prepend(o); + const ConnectionSet remove_set = findConnectionsOf(m_con_list, child_list.constBegin(), child_list.constEnd()); + if (!remove_set.isEmpty()) + m_undo_stack->push(new DeleteConnectionsCommand(this, remove_set.keys())); + + updateBackground(); +} + +void ConnectionEdit::setSelected(Connection *con, bool sel) +{ + if (!con || sel == m_sel_con_set.contains(con)) + return; + + if (sel) { + m_sel_con_set.insert(con, con); + emit connectionSelected(con); + } else { + m_sel_con_set.remove(con); + } + + con->update(); +} + +bool ConnectionEdit::selected(const Connection *con) const +{ + return m_sel_con_set.contains(const_cast(con)); +} + +void ConnectionEdit::selectNone() +{ + foreach (Connection *con, m_sel_con_set) + con->update(); + + m_sel_con_set.clear(); +} + +void ConnectionEdit::selectAll() +{ + if (m_sel_con_set.size() == m_con_list.size()) + return; + foreach (Connection *con, m_con_list) + setSelected(con, true); +} + +Connection *ConnectionEdit::connectionAt(const QPoint &pos) const +{ + foreach (Connection *con, m_con_list) { + if (con->contains(pos)) + return con; + } + return 0; +} + +CETypes::EndPoint ConnectionEdit::endPointAt(const QPoint &pos) const +{ + foreach (Connection *con, m_con_list) { + if (!selected(con)) + continue; + const QRect sr = con->endPointRect(EndPoint::Source); + const QRect tr = con->endPointRect(EndPoint::Target); + + if (sr.contains(pos)) + return EndPoint(con, EndPoint::Source); + if (tr.contains(pos)) + return EndPoint(con, EndPoint::Target); + } + return EndPoint(); +} + +void ConnectionEdit::startDrag(const EndPoint &end_point, const QPoint &pos) +{ + Q_ASSERT(m_drag_end_point.isNull()); + m_drag_end_point = end_point; + m_old_source_pos = m_drag_end_point.con->endPointPos(EndPoint::Source); + m_old_target_pos = m_drag_end_point.con->endPointPos(EndPoint::Target); + adjustHotSopt(m_drag_end_point, pos); +} + +void ConnectionEdit::continueDrag(const QPoint &pos) +{ + Q_ASSERT(!m_drag_end_point.isNull()); + adjustHotSopt(m_drag_end_point, pos); +} + +void ConnectionEdit::endDrag(const QPoint &pos) +{ + Q_ASSERT(!m_drag_end_point.isNull()); + adjustHotSopt(m_drag_end_point, pos); + + Connection *con = m_drag_end_point.con; + const QPoint new_source_pos = con->endPointPos(EndPoint::Source); + const QPoint new_target_pos = con->endPointPos(EndPoint::Target); + m_undo_stack->push(new AdjustConnectionCommand(this, con, m_old_source_pos, m_old_target_pos, + new_source_pos, new_target_pos)); + + m_drag_end_point = EndPoint(); +} + +void ConnectionEdit::adjustHotSopt(const EndPoint &end_point, const QPoint &pos) +{ + QWidget *w = end_point.con->widget(end_point.type); + end_point.con->setEndPoint(end_point.type, w, pointInsideRect(widgetRect(w), pos)); +} + +void ConnectionEdit::deleteSelected() +{ + if (m_sel_con_set.isEmpty()) + return; + m_undo_stack->push(new DeleteConnectionsCommand(this, m_sel_con_set.keys())); +} + +void ConnectionEdit::addConnection(Connection *con) +{ + m_con_list.append(con); +} + +void ConnectionEdit::updateLines() +{ + foreach (Connection *con, m_con_list) + con->checkWidgets(); +} + +void ConnectionEdit::resizeEvent(QResizeEvent *e) +{ + updateBackground(); + QWidget::resizeEvent(e); +} + +void ConnectionEdit::setSource(Connection *con, const QString &obj_name) +{ + QObject *object = 0; + if (!obj_name.isEmpty()) { + object = m_bg_widget->findChild(obj_name); + if (object == 0 && m_bg_widget->objectName() == obj_name) + object = m_bg_widget; + + if (object == con->object(EndPoint::Source)) + return; + } + m_undo_stack->push(new SetEndPointCommand(this, con, EndPoint::Source, object)); +} + +void ConnectionEdit::setTarget(Connection *con, const QString &obj_name) +{ + QObject *object = 0; + if (!obj_name.isEmpty()) { + object = m_bg_widget->findChild(obj_name); + if (object == 0 && m_bg_widget->objectName() == obj_name) + object = m_bg_widget; + + if (object == con->object(EndPoint::Target)) + return; + } + m_undo_stack->push(new SetEndPointCommand(this, con, EndPoint::Target, object)); +} + +Connection *ConnectionEdit::takeConnection(Connection *con) +{ + if (!m_con_list.contains(con)) + return 0; + m_con_list.removeAll(con); + return con; +} + +void ConnectionEdit::clearNewlyAddedConnection() +{ + delete m_tmp_con; + m_tmp_con = 0; +} + +void ConnectionEdit::createContextMenu(QMenu &menu) +{ + // Select + QAction *selectAllAction = menu.addAction(tr("Select All")); + selectAllAction->setEnabled(connectionList().size()); + connect(selectAllAction, SIGNAL(triggered()), this, SLOT(selectAll())); + QAction *deselectAllAction = menu.addAction(tr("Deselect All")); + deselectAllAction->setEnabled(selection().size()); + connect(deselectAllAction, SIGNAL(triggered()), this, SLOT(selectNone())); + menu.addSeparator(); + // Delete + QAction *deleteAction = menu.addAction(tr("Delete")); + deleteAction->setShortcut(QKeySequence::Delete); + deleteAction->setEnabled(!selection().isEmpty()); + connect(deleteAction, SIGNAL(triggered()), this, SLOT(deleteSelected())); +} + +void ConnectionEdit::contextMenuEvent(QContextMenuEvent * event) +{ + QMenu menu; + createContextMenu(menu); + menu.exec(event->globalPos()); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/connectionedit_p.h b/src/designer/src/lib/shared/connectionedit_p.h new file mode 100644 index 000000000..553fbe188 --- /dev/null +++ b/src/designer/src/lib/shared/connectionedit_p.h @@ -0,0 +1,324 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef CONNECTIONEDIT_H +#define CONNECTIONEDIT_H + +#include "shared_global_p.h" + +#include +#include +#include + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QUndoStack; +class QMenu; + +namespace qdesigner_internal { + +class Connection; +class ConnectionEdit; + +class QDESIGNER_SHARED_EXPORT CETypes +{ +public: + typedef QList ConnectionList; + typedef QMap ConnectionSet; + typedef QMap WidgetSet; + + class EndPoint { + public: + enum Type { Source, Target }; + explicit EndPoint(Connection *_con = 0, Type _type = Source) : con(_con), type(_type) {} + bool isNull() const { return con == 0; } + bool operator == (const EndPoint &other) const { return con == other.con && type == other.type; } + bool operator != (const EndPoint &other) const { return !operator == (other); } + Connection *con; + Type type; + }; + enum LineDir { UpDir = 0, DownDir, RightDir, LeftDir }; +}; + +class QDESIGNER_SHARED_EXPORT Connection : public CETypes +{ +public: + explicit Connection(ConnectionEdit *edit); + explicit Connection(ConnectionEdit *edit, QObject *source, QObject *target); + virtual ~Connection() {} + + QObject *object(EndPoint::Type type) const + { + return (type == EndPoint::Source ? m_source : m_target); + } + + QWidget *widget(EndPoint::Type type) const + { + return qobject_cast(object(type)); + } + + QPoint endPointPos(EndPoint::Type type) const; + QRect endPointRect(EndPoint::Type) const; + void setEndPoint(EndPoint::Type type, QObject *w, const QPoint &pos) + { type == EndPoint::Source ? setSource(w, pos) : setTarget(w, pos); } + + bool isVisible() const; + virtual void updateVisibility(); + void setVisible(bool b); + + virtual QRegion region() const; + bool contains(const QPoint &pos) const; + virtual void paint(QPainter *p) const; + + void update(bool update_widgets = true) const; + void checkWidgets(); + + QString label(EndPoint::Type type) const + { return type == EndPoint::Source ? m_source_label : m_target_label; } + void setLabel(EndPoint::Type type, const QString &text); + QRect labelRect(EndPoint::Type type) const; + QPixmap labelPixmap(EndPoint::Type type) const + { return type == EndPoint::Source ? m_source_label_pm : m_target_label_pm; } + + ConnectionEdit *edit() const { return m_edit; } + + virtual void inserted() {} + virtual void removed() {} + +private: + QPoint m_source_pos, m_target_pos; + QObject *m_source, *m_target; + QList m_knee_list; + QPolygonF m_arrow_head; + ConnectionEdit *m_edit; + QString m_source_label, m_target_label; + QPixmap m_source_label_pm, m_target_label_pm; + QRect m_source_rect, m_target_rect; + bool m_visible; + + void setSource(QObject *source, const QPoint &pos); + void setTarget(QObject *target, const QPoint &pos); + void updateKneeList(); + void trimLine(); + void updatePixmap(EndPoint::Type type); + LineDir labelDir(EndPoint::Type type) const; + bool ground() const; + QRect groundRect() const; +}; + +class QDESIGNER_SHARED_EXPORT ConnectionEdit : public QWidget, public CETypes +{ + Q_OBJECT +public: + ConnectionEdit(QWidget *parent, QDesignerFormWindowInterface *form); + virtual ~ConnectionEdit(); + + inline const QPointer &background() const { return m_bg_widget; } + + void setSelected(Connection *con, bool sel); + bool selected(const Connection *con) const; + + int connectionCount() const { return m_con_list.size(); } + Connection *connection(int i) const { return m_con_list.at(i); } + int indexOfConnection(Connection *con) const { return m_con_list.indexOf(con); } + + virtual void setSource(Connection *con, const QString &obj_name); + virtual void setTarget(Connection *con, const QString &obj_name); + + QUndoStack *undoStack() const { return m_undo_stack; } + + void clear(); + + void showEvent(QShowEvent * /*e*/) + { + updateBackground(); + } + +signals: + void aboutToAddConnection(int idx); + void connectionAdded(Connection *con); + void aboutToRemoveConnection(Connection *con); + void connectionRemoved(int idx); + void connectionSelected(Connection *con); + void widgetActivated(QWidget *wgt); + void connectionChanged(Connection *con); + +public slots: + void selectNone(); + void selectAll(); + virtual void deleteSelected(); + virtual void setBackground(QWidget *background); + virtual void updateBackground(); + virtual void widgetRemoved(QWidget *w); + virtual void objectRemoved(QObject *o); + + void updateLines(); + void enableUpdateBackground(bool enable); + +protected: + virtual void paintEvent(QPaintEvent *e); + virtual void mouseMoveEvent(QMouseEvent *e); + virtual void mousePressEvent(QMouseEvent *e); + virtual void mouseReleaseEvent(QMouseEvent *e); + virtual void keyPressEvent(QKeyEvent *e); + virtual void mouseDoubleClickEvent(QMouseEvent *e); + virtual void resizeEvent(QResizeEvent *e); + virtual void contextMenuEvent(QContextMenuEvent * event); + + virtual Connection *createConnection(QWidget *source, QWidget *target); + virtual void modifyConnection(Connection *con); + + virtual QWidget *widgetAt(const QPoint &pos) const; + virtual void createContextMenu(QMenu &menu); + void addConnection(Connection *con); + QRect widgetRect(QWidget *w) const; + + enum State { Editing, Connecting, Dragging }; + State state() const; + + virtual void endConnection(QWidget *target, const QPoint &pos); + + const ConnectionList &connectionList() const { return m_con_list; } + const ConnectionSet &selection() const { return m_sel_con_set; } + Connection *takeConnection(Connection *con); + Connection *newlyAddedConnection() { return m_tmp_con; } + void clearNewlyAddedConnection(); + + void findObjectsUnderMouse(const QPoint &pos); + +private: + void startConnection(QWidget *source, const QPoint &pos); + void continueConnection(QWidget *target, const QPoint &pos); + void abortConnection(); + + void startDrag(const EndPoint &end_point, const QPoint &pos); + void continueDrag(const QPoint &pos); + void endDrag(const QPoint &pos); + void adjustHotSopt(const EndPoint &end_point, const QPoint &pos); + Connection *connectionAt(const QPoint &pos) const; + EndPoint endPointAt(const QPoint &pos) const; + void paintConnection(QPainter *p, Connection *con, + WidgetSet *heavy_highlight_set, + WidgetSet *light_highlight_set) const; + void paintLabel(QPainter *p, EndPoint::Type type, Connection *con); + + + QPointer m_bg_widget; + QUndoStack *m_undo_stack; + bool m_enable_update_background; + + Connection *m_tmp_con; // the connection we are currently editing + ConnectionList m_con_list; + bool m_start_connection_on_drag; + EndPoint m_end_point_under_mouse; + QPointer m_widget_under_mouse; + + EndPoint m_drag_end_point; + QPoint m_old_source_pos, m_old_target_pos; + ConnectionSet m_sel_con_set; + const QColor m_inactive_color; + const QColor m_active_color; + +private: + friend class Connection; + friend class AddConnectionCommand; + friend class DeleteConnectionsCommand; + friend class SetEndPointCommand; +}; + +class QDESIGNER_SHARED_EXPORT CECommand : public QUndoCommand, public CETypes +{ +public: + explicit CECommand(ConnectionEdit *edit) + : m_edit(edit) {} + + virtual bool mergeWith(const QUndoCommand *) { return false; } + + ConnectionEdit *edit() const { return m_edit; } + +private: + ConnectionEdit *m_edit; +}; + +class QDESIGNER_SHARED_EXPORT AddConnectionCommand : public CECommand +{ +public: + AddConnectionCommand(ConnectionEdit *edit, Connection *con); + virtual void redo(); + virtual void undo(); +private: + Connection *m_con; +}; + +class QDESIGNER_SHARED_EXPORT DeleteConnectionsCommand : public CECommand +{ +public: + DeleteConnectionsCommand(ConnectionEdit *edit, const ConnectionList &con_list); + virtual void redo(); + virtual void undo(); +private: + ConnectionList m_con_list; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // CONNECTIONEDIT_H diff --git a/src/designer/src/lib/shared/csshighlighter.cpp b/src/designer/src/lib/shared/csshighlighter.cpp new file mode 100644 index 000000000..4d833b2ab --- /dev/null +++ b/src/designer/src/lib/shared/csshighlighter.cpp @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "csshighlighter_p.h" + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +CssHighlighter::CssHighlighter(QTextDocument *document) +: QSyntaxHighlighter(document) +{ +} + +void CssHighlighter::highlightBlock(const QString& text) +{ + enum Token { ALNUM, LBRACE, RBRACE, COLON, SEMICOLON, COMMA, QUOTE, SLASH, STAR }; + static const int transitions[10][9] = { + { Selector, Property, Selector, Pseudo, Property, Selector, Quote, MaybeComment, Selector }, // Selector + { Property, Property, Selector, Value, Property, Property, Quote, MaybeComment, Property }, // Property + { Value, Property, Selector, Value, Property, Value, Quote, MaybeComment, Value }, // Value + { Pseudo1, Property, Selector, Pseudo2, Selector, Selector, Quote, MaybeComment, Pseudo }, // Pseudo + { Pseudo1, Property, Selector, Pseudo, Selector, Selector, Quote, MaybeComment, Pseudo1 }, // Pseudo1 + { Pseudo2, Property, Selector, Pseudo, Selector, Selector, Quote, MaybeComment, Pseudo2 }, // Pseudo2 + { Quote, Quote, Quote, Quote, Quote, Quote, -1, Quote, Quote }, // Quote + { -1, -1, -1, -1, -1, -1, -1, -1, Comment }, // MaybeComment + { Comment, Comment, Comment, Comment, Comment, Comment, Comment, Comment, MaybeCommentEnd }, // Comment + { Comment, Comment, Comment, Comment, Comment, Comment, Comment, -1, MaybeCommentEnd } // MaybeCommentEnd + }; + + int lastIndex = 0; + bool lastWasSlash = false; + int state = previousBlockState(), save_state; + if (state == -1) { + // As long as the text is empty, leave the state undetermined + if (text.isEmpty()) { + setCurrentBlockState(-1); + return; + } + // The initial state is based on the precense of a : and the absense of a {. + // This is because Qt style sheets support both a full stylesheet as well as + // an inline form with just properties. + state = save_state = (text.indexOf(QLatin1Char(':')) > -1 && + text.indexOf(QLatin1Char('{')) == -1) ? Property : Selector; + } else { + save_state = state>>16; + state &= 0x00ff; + } + + if (state == MaybeCommentEnd) { + state = Comment; + } else if (state == MaybeComment) { + state = save_state; + } + + for (int i = 0; i < text.length(); i++) { + int token = ALNUM; + const QChar c = text.at(i); + const char a = c.toAscii(); + + if (state == Quote) { + if (a == '\\') { + lastWasSlash = true; + } else { + if (a == '\"' && !lastWasSlash) { + token = QUOTE; + } + lastWasSlash = false; + } + } else { + switch (a) { + case '{': token = LBRACE; break; + case '}': token = RBRACE; break; + case ':': token = COLON; break; + case ';': token = SEMICOLON; break; + case ',': token = COMMA; break; + case '\"': token = QUOTE; break; + case '/': token = SLASH; break; + case '*': token = STAR; break; + default: break; + } + } + + int new_state = transitions[state][token]; + + if (new_state != state) { + bool include_token = new_state == MaybeCommentEnd || (state == MaybeCommentEnd && new_state!= Comment) + || state == Quote; + highlight(text, lastIndex, i-lastIndex+include_token, state); + + if (new_state == Comment) { + lastIndex = i-1; // include the slash and star + } else { + lastIndex = i + ((token == ALNUM || new_state == Quote) ? 0 : 1); + } + } + + if (new_state == -1) { + state = save_state; + } else if (state <= Pseudo2) { + save_state = state; + state = new_state; + } else { + state = new_state; + } + } + + highlight(text, lastIndex, text.length() - lastIndex, state); + setCurrentBlockState(state + (save_state<<16)); +} + +void CssHighlighter::highlight(const QString &text, int start, int length, int state) +{ + if (start >= text.length() || length <= 0) + return; + + QTextCharFormat format; + + switch (state) { + case Selector: + setFormat(start, length, Qt::darkRed); + break; + case Property: + setFormat(start, length, Qt::blue); + break; + case Value: + setFormat(start, length, Qt::black); + break; + case Pseudo1: + setFormat(start, length, Qt::darkRed); + break; + case Pseudo2: + setFormat(start, length, Qt::darkRed); + break; + case Quote: + setFormat(start, length, Qt::darkMagenta); + break; + case Comment: + case MaybeCommentEnd: + format.setForeground(Qt::darkGreen); + setFormat(start, length, format); + break; + default: + break; + } +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/csshighlighter_p.h b/src/designer/src/lib/shared/csshighlighter_p.h new file mode 100644 index 000000000..f8be2f2c0 --- /dev/null +++ b/src/designer/src/lib/shared/csshighlighter_p.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef CSSHIGHLIGHTER_H +#define CSSHIGHLIGHTER_H + +#include +#include "shared_global_p.h" + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QDESIGNER_SHARED_EXPORT CssHighlighter : public QSyntaxHighlighter +{ + Q_OBJECT +public: + explicit CssHighlighter(QTextDocument *document); + +protected: + void highlightBlock(const QString&); + void highlight(const QString&, int, int, int/*State*/); + +private: + enum State { Selector, Property, Value, Pseudo, Pseudo1, Pseudo2, Quote, + MaybeComment, Comment, MaybeCommentEnd }; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // CSSHIGHLIGHTER_H diff --git a/src/designer/src/lib/shared/defaultgradients.xml b/src/designer/src/lib/shared/defaultgradients.xml new file mode 100644 index 000000000..70559ad12 --- /dev/null +++ b/src/designer/src/lib/shared/defaultgradients.xml @@ -0,0 +1,498 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/designer/src/lib/shared/deviceprofile.cpp b/src/designer/src/lib/shared/deviceprofile.cpp new file mode 100644 index 000000000..3228cab5f --- /dev/null +++ b/src/designer/src/lib/shared/deviceprofile.cpp @@ -0,0 +1,467 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "deviceprofile_p.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +static const char *dpiXPropertyC = "_q_customDpiX"; +static const char *dpiYPropertyC = "_q_customDpiY"; + +// XML serialization +static const char *xmlVersionC="1.0"; +static const char *rootElementC="deviceprofile"; +static const char *nameElementC = "name"; +static const char *fontFamilyElementC = "fontfamily"; +static const char *fontPointSizeElementC = "fontpointsize"; +static const char *dPIXElementC = "dpix"; +static const char *dPIYElementC = "dpiy"; +static const char *styleElementC = "style"; + +/* DeviceProfile: + * For preview purposes (preview, widget box, new form dialog), the + * QDesignerFormBuilder applies the settings to the form main container + * (Point being here that the DPI must be set directly for size calculations + * to be correct). + * For editing purposes, FormWindow applies the settings to the form container + * as not to interfere with the font settings of the form main container. + * In addition, the widgetfactory maintains the system settings style + * and applies it when creating widgets. */ + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// ---------------- DeviceProfileData +class DeviceProfileData : public QSharedData { +public: + DeviceProfileData(); + void fromSystem(); + void clear(); + + QString m_fontFamily; + int m_fontPointSize; + QString m_style; + int m_dpiX; + int m_dpiY; + QString m_name; +}; + +DeviceProfileData::DeviceProfileData() : + m_fontPointSize(-1), + m_dpiX(-1), + m_dpiY(-1) +{ +} + +void DeviceProfileData::clear() +{ + m_fontPointSize = -1; + m_dpiX = 0; + m_dpiY = 0; + m_name.clear(); + m_style.clear(); +} + +void DeviceProfileData::fromSystem() +{ + const QFont appFont = QApplication::font(); + m_fontFamily = appFont.family(); + m_fontPointSize = appFont.pointSize(); + DeviceProfile::systemResolution(&m_dpiX, &m_dpiY); + m_style.clear(); +} + +// ---------------- DeviceProfile +DeviceProfile::DeviceProfile() : + m_d(new DeviceProfileData) +{ +} + +DeviceProfile::DeviceProfile(const DeviceProfile &o) : + m_d(o.m_d) + +{ +} + +DeviceProfile& DeviceProfile::operator=(const DeviceProfile &o) +{ + m_d.operator=(o.m_d); + return *this; +} + +DeviceProfile::~DeviceProfile() +{ +} + +void DeviceProfile::clear() +{ + m_d->clear(); +} + +bool DeviceProfile::isEmpty() const +{ + return m_d->m_name.isEmpty(); +} + +QString DeviceProfile::fontFamily() const +{ + return m_d->m_fontFamily; +} + +void DeviceProfile::setFontFamily(const QString &f) +{ + m_d->m_fontFamily = f; +} + +int DeviceProfile::fontPointSize() const +{ + return m_d->m_fontPointSize; +} + +void DeviceProfile::setFontPointSize(int p) +{ + m_d->m_fontPointSize = p; +} + +QString DeviceProfile::style() const +{ + return m_d->m_style; +} + +void DeviceProfile::setStyle(const QString &s) +{ + m_d->m_style = s; +} + +int DeviceProfile::dpiX() const +{ + return m_d->m_dpiX; +} + +void DeviceProfile::setDpiX(int d) +{ + m_d->m_dpiX = d; +} + +int DeviceProfile::dpiY() const +{ + return m_d->m_dpiY; +} + +void DeviceProfile::setDpiY(int d) +{ + m_d->m_dpiY = d; +} + +void DeviceProfile::fromSystem() +{ + m_d->fromSystem(); +} + +QString DeviceProfile::name() const +{ + return m_d->m_name; +} + +void DeviceProfile::setName(const QString &n) +{ + m_d->m_name = n; +} + +void DeviceProfile::systemResolution(int *dpiX, int *dpiY) +{ + const QDesktopWidget *dw = qApp->desktop(); + *dpiX = dw->logicalDpiX(); + *dpiY = dw->logicalDpiY(); +} + +class FriendlyWidget : public QWidget { + friend class DeviceProfile; +}; + +void DeviceProfile::widgetResolution(const QWidget *w, int *dpiX, int *dpiY) +{ + const FriendlyWidget *fw = static_cast(w); + *dpiX = fw->metric(QPaintDevice::PdmDpiX); + *dpiY = fw->metric(QPaintDevice::PdmDpiY); +} + +QString DeviceProfile::toString() const +{ + const DeviceProfileData &d = *m_d; + QString rc; + QTextStream(&rc) << "DeviceProfile:name=" << d.m_name << " Font=" << d.m_fontFamily << ' ' + << d.m_fontPointSize << " Style=" << d.m_style << " DPI=" << d.m_dpiX << ',' << d.m_dpiY; + return rc; +} + +// Apply font to widget +static void applyFont(const QString &family, int size, DeviceProfile::ApplyMode am, QWidget *widget) +{ + QFont currentFont = widget->font(); + if (currentFont.pointSize() == size && currentFont.family() == family) + return; + switch (am) { + case DeviceProfile::ApplyFormParent: + // Invisible form parent: Apply all + widget->setFont(QFont(family, size)); + break; + case DeviceProfile::ApplyPreview: { + // Preview: Apply only subproperties that have not been changed by designer properties + bool apply = false; + const uint resolve = currentFont.resolve(); + if (!(resolve & QFont::FamilyResolved)) { + currentFont.setFamily(family); + apply = true; + } + if (!(resolve & QFont::SizeResolved)) { + currentFont.setPointSize(size); + apply = true; + } + if (apply) + widget->setFont(currentFont); + } + break; + } +} + +void DeviceProfile::applyDPI(int dpiX, int dpiY, QWidget *widget) +{ + int sysDPIX, sysDPIY; // Set dynamic variables in case values are different from system DPI + systemResolution(&sysDPIX, &sysDPIY); + if (dpiX != sysDPIX && dpiY != sysDPIY) { + widget->setProperty(dpiXPropertyC, QVariant(dpiX)); + widget->setProperty(dpiYPropertyC, QVariant(dpiY)); + } +} + +void DeviceProfile::apply(const QDesignerFormEditorInterface *core, QWidget *widget, ApplyMode am) const +{ + if (isEmpty()) + return; + + const DeviceProfileData &d = *m_d; + + if (!d.m_fontFamily.isEmpty()) + applyFont(d.m_fontFamily, d.m_fontPointSize, am, widget); + + applyDPI(d.m_dpiX, d.m_dpiY, widget); + + if (!d.m_style.isEmpty()) { + if (WidgetFactory *wf = qobject_cast(core->widgetFactory())) + wf->applyStyleTopLevel(d.m_style, widget); + } +} + +bool DeviceProfile::equals(const DeviceProfile& rhs) const +{ + const DeviceProfileData &d = *m_d; + const DeviceProfileData &rhs_d = *rhs.m_d; + return d.m_fontPointSize == rhs_d.m_fontPointSize && + d.m_dpiX == rhs_d.m_dpiX && d.m_dpiY == rhs_d.m_dpiY && d.m_fontFamily == rhs_d.m_fontFamily && + d.m_style == rhs_d.m_style && d.m_name == rhs_d.m_name; +} + +static inline void writeElement(QXmlStreamWriter &writer, const QString &element, const QString &cdata) +{ + writer.writeStartElement(element); + writer.writeCharacters(cdata); + writer.writeEndElement(); +} + +QString DeviceProfile::toXml() const +{ + const DeviceProfileData &d = *m_d; + QString rc; + QXmlStreamWriter writer(&rc); + writer.writeStartDocument(QLatin1String(xmlVersionC)); + writer.writeStartElement(QLatin1String(rootElementC)); + writeElement(writer, QLatin1String(nameElementC), d.m_name); + + if (!d.m_fontFamily.isEmpty()) + writeElement(writer, QLatin1String(fontFamilyElementC), d.m_fontFamily); + if (d.m_fontPointSize >= 0) + writeElement(writer, QLatin1String(fontPointSizeElementC), QString::number(d.m_fontPointSize)); + if (d.m_dpiX > 0) + writeElement(writer, QLatin1String(dPIXElementC), QString::number(d.m_dpiX)); + if (d.m_dpiY > 0) + writeElement(writer, QLatin1String(dPIYElementC), QString::number(d.m_dpiY)); + if (!d.m_style.isEmpty()) + writeElement(writer, QLatin1String(styleElementC), d.m_style); + + writer.writeEndElement(); + writer.writeEndDocument(); + return rc; +} + +/* Switch stages when encountering a start element (state table) */ +enum ParseStage { ParseBeginning, ParseWithinRoot, + ParseName, ParseFontFamily, ParseFontPointSize, ParseDPIX, ParseDPIY, ParseStyle, + ParseError }; + +static ParseStage nextStage(ParseStage currentStage, const QStringRef &startElement) +{ + switch (currentStage) { + case ParseBeginning: + if (startElement == QLatin1String(rootElementC)) + return ParseWithinRoot; + break; + case ParseWithinRoot: + case ParseName: + case ParseFontFamily: + case ParseFontPointSize: + case ParseDPIX: + case ParseDPIY: + case ParseStyle: + if (startElement == QLatin1String(nameElementC)) + return ParseName; + if (startElement == QLatin1String(fontFamilyElementC)) + return ParseFontFamily; + if (startElement == QLatin1String(fontPointSizeElementC)) + return ParseFontPointSize; + if (startElement == QLatin1String(dPIXElementC)) + return ParseDPIX; + if (startElement == QLatin1String(dPIYElementC)) + return ParseDPIY; + if (startElement == QLatin1String(styleElementC)) + return ParseStyle; + break; + case ParseError: + break; + } + return ParseError; +} + +static bool readIntegerElement(QXmlStreamReader &reader, int *v) +{ + const QString e = reader.readElementText(); + bool ok; + *v = e.toInt(&ok); + //: Reading a number for an embedded device profile + if (!ok) + reader.raiseError(QApplication::translate("DeviceProfile", "'%1' is not a number.").arg(e)); + return ok; +} + +bool DeviceProfile::fromXml(const QString &xml, QString *errorMessage) +{ + DeviceProfileData &d = *m_d; + d.fromSystem(); + + QXmlStreamReader reader(xml); + + ParseStage ps = ParseBeginning; + QXmlStreamReader::TokenType tt = QXmlStreamReader::NoToken; + int iv = 0; + do { + tt = reader.readNext(); + if (tt == QXmlStreamReader::StartElement) { + ps = nextStage(ps, reader.name()); + switch (ps) { + case ParseBeginning: + case ParseWithinRoot: + break; + case ParseError: + reader.raiseError(QApplication::translate("DeviceProfile", "An invalid tag <%1> was encountered.").arg(reader.name().toString())); + tt = QXmlStreamReader::Invalid; + break; + case ParseName: + d.m_name = reader.readElementText(); + break; + case ParseFontFamily: + d.m_fontFamily = reader.readElementText(); + break; + case ParseFontPointSize: + if (readIntegerElement(reader, &iv)) { + d.m_fontPointSize = iv; + } else { + tt = QXmlStreamReader::Invalid; + } + break; + case ParseDPIX: + if (readIntegerElement(reader, &iv)) { + d.m_dpiX = iv; + } else { + tt = QXmlStreamReader::Invalid; + } + break; + case ParseDPIY: + if (readIntegerElement(reader, &iv)) { + d.m_dpiY = iv; + } else { + tt = QXmlStreamReader::Invalid; + } + break; + case ParseStyle: + d.m_style = reader.readElementText(); + break; + } + } + } while (tt != QXmlStreamReader::Invalid && tt != QXmlStreamReader::EndDocument); + + if (reader.hasError()) { + *errorMessage = reader.errorString(); + return false; + } + + return true; +} +} + +QT_END_NAMESPACE + diff --git a/src/designer/src/lib/shared/deviceprofile_p.h b/src/designer/src/lib/shared/deviceprofile_p.h new file mode 100644 index 000000000..9d0cdbd51 --- /dev/null +++ b/src/designer/src/lib/shared/deviceprofile_p.h @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef DEVICEPROFILE_H +#define DEVICEPROFILE_H + +#include "shared_global_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QWidget; +class QStyle; + +namespace qdesigner_internal { + +class DeviceProfileData; + +/* DeviceProfile for embedded design. They influence + * default properties (for example, fonts), dpi and + * style of the form. This class represents a device + * profile. */ + +class QDESIGNER_SHARED_EXPORT DeviceProfile { +public: + DeviceProfile(); + + DeviceProfile(const DeviceProfile&); + DeviceProfile& operator=(const DeviceProfile&); + ~DeviceProfile(); + + void clear(); + + // Device name + QString name() const; + void setName(const QString &); + + // System settings active + bool isEmpty() const; + + // Default font family of the embedded system + QString fontFamily() const; + void setFontFamily(const QString &); + + // Default font size of the embedded system + int fontPointSize() const; + void setFontPointSize(int p); + + // Display resolution of the embedded system + int dpiX() const; + void setDpiX(int d); + int dpiY() const; + void setDpiY(int d); + + // Style + QString style() const; + void setStyle(const QString &); + + // Initialize from desktop system + void fromSystem(); + + static void systemResolution(int *dpiX, int *dpiY); + static void widgetResolution(const QWidget *w, int *dpiX, int *dpiY); + + bool equals(const DeviceProfile& rhs) const; + + // Apply to form/preview (using font inheritance) + enum ApplyMode { + /* Pre-Apply to parent widget of form being edited: Apply font + * and make use of property inheritance to be able to modify the + * font property freely. */ + ApplyFormParent, + /* Post-Apply to preview widget: Change only inherited font + * sub properties. */ + ApplyPreview + }; + void apply(const QDesignerFormEditorInterface *core, QWidget *widget, ApplyMode am) const; + + static void applyDPI(int dpiX, int dpiY, QWidget *widget); + + QString toString() const; + + QString toXml() const; + bool fromXml(const QString &xml, QString *errorMessage); + +private: + QSharedDataPointer m_d; +}; + +inline bool operator==(const DeviceProfile &s1, const DeviceProfile &s2) + { return s1.equals(s2); } +inline bool operator!=(const DeviceProfile &s1, const DeviceProfile &s2) + { return !s1.equals(s2); } + +} + + +QT_END_NAMESPACE + +#endif // DEVICEPROFILE_H diff --git a/src/designer/src/lib/shared/dialoggui.cpp b/src/designer/src/lib/shared/dialoggui.cpp new file mode 100644 index 000000000..3aa4c796d --- /dev/null +++ b/src/designer/src/lib/shared/dialoggui.cpp @@ -0,0 +1,265 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "dialoggui_p.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +// QFileDialog on X11 does not provide an image preview. Display icons. +#ifdef Q_WS_X11 +# define IMAGE_PREVIEW +#endif + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// Icon provider that reads out the known image formats +class IconProvider : public QFileIconProvider { + Q_DISABLE_COPY(IconProvider) + +public: + IconProvider(); + virtual QIcon icon (const QFileInfo &info) const; + + inline bool loadCheck(const QFileInfo &info) const; + QImage loadImage(const QString &fileName) const; + +private: + QSet m_imageFormats; +}; + +IconProvider::IconProvider() +{ + // Determine a list of readable extensions (upper and lower case) + typedef QList ByteArrayList; + const ByteArrayList fmts = QImageReader::supportedImageFormats(); + const ByteArrayList::const_iterator cend = fmts.constEnd(); + for (ByteArrayList::const_iterator it = fmts.constBegin(); it != cend; ++it) { + const QString suffix = QString::fromUtf8(it->constData()); + m_imageFormats.insert(suffix.toLower()); + m_imageFormats.insert(suffix.toUpper()); + + } +} + +// Check by extension and type if this appears to be a loadable image +bool IconProvider::loadCheck(const QFileInfo &info) const +{ + if (info.isFile() && info.isReadable()) { + const QString suffix = info.suffix(); + if (!suffix.isEmpty()) + return m_imageFormats.contains(suffix); + } + return false; +} + +QImage IconProvider::loadImage(const QString &fileName) const +{ + QFile file(fileName); + if (file.open(QIODevice::ReadOnly)) { + QImageReader imgReader(&file); + if (imgReader.canRead()) { + QImage image; + if (imgReader.read(&image)) + return image; + } + } + return QImage(); +} + +QIcon IconProvider::icon (const QFileInfo &info) const +{ + // Don't get stuck on large images. + const qint64 maxSize = 131072; + if (loadCheck(info) && info.size() < maxSize) { + const QImage image = loadImage(info.absoluteFilePath()); + if (!image.isNull()) + return QIcon(QPixmap::fromImage(image, Qt::ThresholdDither|Qt::AutoColor)); + } + return QFileIconProvider::icon(info); +} + +// ---------------- DialogGui +DialogGui::DialogGui() : + m_iconProvider(0) +{ +} + +DialogGui::~DialogGui() +{ + delete m_iconProvider; +} + +QFileIconProvider *DialogGui::ensureIconProvider() +{ + if (!m_iconProvider) + m_iconProvider = new IconProvider; + return m_iconProvider; +} + +QMessageBox::StandardButton + DialogGui::message(QWidget *parent, Message /*context*/, QMessageBox::Icon icon, + const QString &title, const QString &text, QMessageBox::StandardButtons buttons, + QMessageBox::StandardButton defaultButton) +{ + QMessageBox::StandardButton rc = QMessageBox::NoButton; + switch (icon) { + case QMessageBox::Information: + rc = QMessageBox::information(parent, title, text, buttons, defaultButton); + break; + case QMessageBox::Warning: + rc = QMessageBox::warning(parent, title, text, buttons, defaultButton); + break; + case QMessageBox::Critical: + rc = QMessageBox::critical(parent, title, text, buttons, defaultButton); + break; + case QMessageBox::Question: + rc = QMessageBox::question(parent, title, text, buttons, defaultButton); + break; + case QMessageBox::NoIcon: + break; + } + return rc; +} + +QMessageBox::StandardButton + DialogGui::message(QWidget *parent, Message /*context*/, QMessageBox::Icon icon, + const QString &title, const QString &text, const QString &informativeText, + QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) +{ + QMessageBox msgBox(icon, title, text, buttons, parent); + msgBox.setDefaultButton(defaultButton); + msgBox.setInformativeText(informativeText); + return static_cast(msgBox.exec()); +} + +QMessageBox::StandardButton + DialogGui::message(QWidget *parent, Message /*context*/, QMessageBox::Icon icon, + const QString &title, const QString &text, const QString &informativeText, const QString &detailedText, + QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) +{ + QMessageBox msgBox(icon, title, text, buttons, parent); + msgBox.setDefaultButton(defaultButton); + msgBox.setInformativeText(informativeText); + msgBox.setDetailedText(detailedText); + return static_cast(msgBox.exec()); +} + +QString DialogGui::getExistingDirectory(QWidget *parent, const QString &caption, const QString &dir, QFileDialog::Options options) +{ + return QFileDialog::getExistingDirectory(parent, caption, dir, options); +} + +QString DialogGui::getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options) +{ + return QFileDialog::getOpenFileName(parent, caption, dir, filter, selectedFilter, options); +} + +QStringList DialogGui::getOpenFileNames(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options) +{ + return QFileDialog::getOpenFileNames(parent, caption, dir, filter, selectedFilter, options); +} + +QString DialogGui::getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options) +{ + return QFileDialog::getSaveFileName(parent, caption, dir, filter, selectedFilter, options); +} + +void DialogGui::initializeImageFileDialog(QFileDialog &fileDialog, QFileDialog::Options options, QFileDialog::FileMode fm) +{ + fileDialog.setConfirmOverwrite( !(options & QFileDialog::DontConfirmOverwrite) ); + fileDialog.setResolveSymlinks( !(options & QFileDialog::DontResolveSymlinks) ); + fileDialog.setIconProvider(ensureIconProvider()); + fileDialog.setFileMode(fm); +} + +QString DialogGui::getOpenImageFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options ) +{ + +#ifdef IMAGE_PREVIEW + QFileDialog fileDialog(parent, caption, dir, filter); + initializeImageFileDialog(fileDialog, options, QFileDialog::ExistingFile); + if (fileDialog.exec() != QDialog::Accepted) + return QString(); + + const QStringList selectedFiles = fileDialog.selectedFiles(); + if (selectedFiles.empty()) + return QString(); + + if (selectedFilter) + *selectedFilter = fileDialog.selectedFilter(); + + return selectedFiles.front(); +#else + return getOpenFileName(parent, caption, dir, filter, selectedFilter, options); +#endif +} + +QStringList DialogGui::getOpenImageFileNames(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options ) +{ +#ifdef IMAGE_PREVIEW + QFileDialog fileDialog(parent, caption, dir, filter); + initializeImageFileDialog(fileDialog, options, QFileDialog::ExistingFiles); + if (fileDialog.exec() != QDialog::Accepted) + return QStringList(); + + const QStringList selectedFiles = fileDialog.selectedFiles(); + if (!selectedFiles.empty() && selectedFilter) + *selectedFilter = fileDialog.selectedFilter(); + + return selectedFiles; +#else + return getOpenFileNames(parent, caption, dir, filter, selectedFilter, options); +#endif +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/dialoggui_p.h b/src/designer/src/lib/shared/dialoggui_p.h new file mode 100644 index 000000000..c78eea2ef --- /dev/null +++ b/src/designer/src/lib/shared/dialoggui_p.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DIALOGGUI +#define DIALOGGUI + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#include "shared_global_p.h" +#include + +QT_BEGIN_NAMESPACE + +class QFileIconProvider; + +namespace qdesigner_internal { + +class QDESIGNER_SHARED_EXPORT DialogGui : public QDesignerDialogGuiInterface +{ +public: + DialogGui(); + virtual ~DialogGui(); + + virtual QMessageBox::StandardButton + message(QWidget *parent, Message context, QMessageBox::Icon icon, + const QString &title, const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); + + virtual QMessageBox::StandardButton + message(QWidget *parent, Message context, QMessageBox::Icon icon, + const QString &title, const QString &text, const QString &informativeText, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); + + virtual QMessageBox::StandardButton + message(QWidget *parent, Message context, QMessageBox::Icon icon, + const QString &title, const QString &text, const QString &informativeText, const QString &detailedText, + QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); + + virtual QString getExistingDirectory(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), QFileDialog::Options options = QFileDialog::ShowDirsOnly); + virtual QString getOpenFileName(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0); + virtual QStringList getOpenFileNames(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0); + virtual QString getSaveFileName(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0); + + virtual QString getOpenImageFileName(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0); + virtual QStringList getOpenImageFileNames(QWidget *parent = 0, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = 0, QFileDialog::Options options = 0); + +private: + QFileIconProvider *ensureIconProvider(); + void initializeImageFileDialog(QFileDialog &fd, QFileDialog::Options options, QFileDialog::FileMode); + + QFileIconProvider *m_iconProvider; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // DIALOGGUI diff --git a/src/designer/src/lib/shared/extensionfactory_p.h b/src/designer/src/lib/shared/extensionfactory_p.h new file mode 100644 index 000000000..3b918c292 --- /dev/null +++ b/src/designer/src/lib/shared/extensionfactory_p.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef SHARED_EXTENSIONFACTORY_H +#define SHARED_EXTENSIONFACTORY_H + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// Extension factory for registering an extension for an object type. +template +class ExtensionFactory: public QExtensionFactory +{ +public: + explicit ExtensionFactory(const QString &iid, QExtensionManager *parent = 0); + + // Convenience for registering the extension. Do not use for derived classes. + static void registerExtension(QExtensionManager *mgr, const QString &iid); + +protected: + virtual QObject *createExtension(QObject *qObject, const QString &iid, QObject *parent) const; + +private: + // Can be overwritten to perform checks on the object. + // Default does a qobject_cast to the desired class. + virtual Object *checkObject(QObject *qObject) const; + + const QString m_iid; +}; + +template +ExtensionFactory::ExtensionFactory(const QString &iid, QExtensionManager *parent) : + QExtensionFactory(parent), + m_iid(iid) +{ +} + +template +Object *ExtensionFactory::checkObject(QObject *qObject) const +{ + return qobject_cast(qObject); +} + +template +QObject *ExtensionFactory::createExtension(QObject *qObject, const QString &iid, QObject *parent) const +{ + if (iid != m_iid) + return 0; + + Object *object = checkObject(qObject); + if (!object) + return 0; + + return new Extension(object, parent); +} + +template +void ExtensionFactory::registerExtension(QExtensionManager *mgr, const QString &iid) +{ + ExtensionFactory *factory = new ExtensionFactory(iid, mgr); + mgr->registerExtensions(factory, iid); +} +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // SHARED_EXTENSIONFACTORY_H diff --git a/src/designer/src/lib/shared/filterwidget.cpp b/src/designer/src/lib/shared/filterwidget.cpp new file mode 100644 index 000000000..e6c826cf8 --- /dev/null +++ b/src/designer/src/lib/shared/filterwidget.cpp @@ -0,0 +1,252 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "filterwidget_p.h" +#include "iconloader_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +enum { debugFilter = 0 }; + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +HintLineEdit::HintLineEdit(QWidget *parent) : + QLineEdit(parent), + m_defaultFocusPolicy(focusPolicy()), + m_refuseFocus(false) +{ +} + +IconButton::IconButton(QWidget *parent) + : QToolButton(parent) +{ + setCursor(Qt::ArrowCursor); +} + +void IconButton::paintEvent(QPaintEvent *) +{ + QPainter painter(this); + // Note isDown should really use the active state but in most styles + // this has no proper feedback + QIcon::Mode state = QIcon::Disabled; + if (isEnabled()) + state = isDown() ? QIcon::Selected : QIcon::Normal; + QPixmap iconpixmap = icon().pixmap(QSize(ICONBUTTON_SIZE, ICONBUTTON_SIZE), + state, QIcon::Off); + QRect pixmapRect = QRect(0, 0, iconpixmap.width(), iconpixmap.height()); + pixmapRect.moveCenter(rect().center()); + painter.setOpacity(m_fader); + painter.drawPixmap(pixmapRect, iconpixmap); +} + +void IconButton::animateShow(bool visible) +{ + if (visible) { + QPropertyAnimation *animation = new QPropertyAnimation(this, "fader"); + animation->setDuration(160); + animation->setEndValue(1.0); + animation->start(QAbstractAnimation::DeleteWhenStopped); + } else { + QPropertyAnimation *animation = new QPropertyAnimation(this, "fader"); + animation->setDuration(160); + animation->setEndValue(0.0); + animation->start(QAbstractAnimation::DeleteWhenStopped); + } +} + +bool HintLineEdit::refuseFocus() const +{ + return m_refuseFocus; +} + +void HintLineEdit::setRefuseFocus(bool v) +{ + if (v == m_refuseFocus) + return; + m_refuseFocus = v; + setFocusPolicy(m_refuseFocus ? Qt::NoFocus : m_defaultFocusPolicy); +} + +void HintLineEdit::mousePressEvent(QMouseEvent *e) +{ + if (debugFilter) + qDebug() << Q_FUNC_INFO; + // Explicitly focus on click. + if (m_refuseFocus && !hasFocus()) + setFocus(Qt::OtherFocusReason); + QLineEdit::mousePressEvent(e); +} + +void HintLineEdit::focusInEvent(QFocusEvent *e) +{ + if (debugFilter) + qDebug() << Q_FUNC_INFO; + if (m_refuseFocus) { + // Refuse the focus if the mouse it outside. In addition to the mouse + // press logic, this prevents a re-focussing which occurs once + // we actually had focus + const Qt::FocusReason reason = e->reason(); + if (reason == Qt::ActiveWindowFocusReason || reason == Qt::PopupFocusReason) { + const QPoint mousePos = mapFromGlobal(QCursor::pos()); + const bool refuse = !geometry().contains(mousePos); + if (debugFilter) + qDebug() << Q_FUNC_INFO << refuse ; + if (refuse) { + e->ignore(); + return; + } + } + } + + QLineEdit::focusInEvent(e); +} + +// ------------------- FilterWidget +FilterWidget::FilterWidget(QWidget *parent, LayoutMode lm) : + QWidget(parent), + m_editor(new HintLineEdit(this)), + m_button(new IconButton(m_editor)), + m_buttonwidth(0) +{ + m_editor->setPlaceholderText(tr("Filter")); + + // Let the style determine minimum height for our widget + QSize size(ICONBUTTON_SIZE + 6, ICONBUTTON_SIZE + 2); + + // Note KDE does not reserve space for the highlight color + if (style()->inherits("OxygenStyle")) { + size = size.expandedTo(QSize(24, 0)); + } + + // Make room for clear icon + QMargins margins = m_editor->textMargins(); + if (layoutDirection() == Qt::LeftToRight) + margins.setRight(size.width()); + else + margins.setLeft(size.width()); + + m_editor->setTextMargins(margins); + + QHBoxLayout *l = new QHBoxLayout(this); + l->setMargin(0); + l->setSpacing(0); + if (lm == LayoutAlignRight) + l->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum)); + + l->addWidget(m_editor); + + // KDE has custom icons for this. Notice that icon namings are counter intuitive + // If these icons are not avaiable we use the freedesktop standard name before + // falling back to a bundled resource + QIcon icon = QIcon::fromTheme(layoutDirection() == Qt::LeftToRight ? + QLatin1String("edit-clear-locationbar-rtl") : + QLatin1String("edit-clear-locationbar-ltr"), + QIcon::fromTheme("edit-clear", createIconSet(QLatin1String("cleartext.png")))); + + m_button->setIcon(icon); + m_button->setToolTip(tr("Clear text")); + connect(m_button, SIGNAL(clicked()), this, SLOT(reset())); + connect(m_editor, SIGNAL(textChanged(QString)), this, SLOT(checkButton(QString))); + connect(m_editor, SIGNAL(textEdited(QString)), this, SIGNAL(filterChanged(QString))); +} + +QString FilterWidget::text() const +{ + return m_editor->text(); +} + +void FilterWidget::checkButton(const QString &text) +{ + if (m_oldText.isEmpty() || text.isEmpty()) + m_button->animateShow(!m_editor->text().isEmpty()); + m_oldText = text; +} + +void FilterWidget::reset() +{ + if (debugFilter) + qDebug() << Q_FUNC_INFO; + + if (!m_editor->text().isEmpty()) { + // Editor has lost focus once this is pressed + m_editor->clear(); + emit filterChanged(QString()); + } +} + +void FilterWidget::resizeEvent(QResizeEvent *) +{ + QRect contentRect = m_editor->rect(); + if (layoutDirection() == Qt::LeftToRight) { + const int iconoffset = m_editor->textMargins().right() + 4; + m_button->setGeometry(contentRect.adjusted(m_editor->width() - iconoffset, 0, 0, 0)); + } else { + const int iconoffset = m_editor->textMargins().left() + 4; + m_button->setGeometry(contentRect.adjusted(0, 0, -m_editor->width() + iconoffset, 0)); + } +} + +bool FilterWidget::refuseFocus() const +{ + return m_editor->refuseFocus(); +} + +void FilterWidget::setRefuseFocus(bool v) +{ + m_editor->setRefuseFocus(v); +} +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/filterwidget_p.h b/src/designer/src/lib/shared/filterwidget_p.h new file mode 100644 index 000000000..5b5edcd7c --- /dev/null +++ b/src/designer/src/lib/shared/filterwidget_p.h @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef FILTERWIDGET_H +#define FILTERWIDGET_H + +#include "shared_global_p.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QToolButton; + +namespace qdesigner_internal { + +/* This widget should never have initial focus + * (ie, be the first widget of a dialog, else, the hint cannot be displayed. + * For situations, where it is the only focusable control (widget box), + * there is a special "refuseFocus()" mode, in which it clears the focus + * policy and focusses explicitly on click (note that setting Qt::ClickFocus + * is not sufficient for that as an ActivationFocus will occur). */ + +#define ICONBUTTON_SIZE 16 + +class QDESIGNER_SHARED_EXPORT HintLineEdit : public QLineEdit { + Q_OBJECT +public: + explicit HintLineEdit(QWidget *parent = 0); + + bool refuseFocus() const; + void setRefuseFocus(bool v); + +protected: + virtual void mousePressEvent(QMouseEvent *event); + virtual void focusInEvent(QFocusEvent *e); + +private: + const Qt::FocusPolicy m_defaultFocusPolicy; + bool m_refuseFocus; +}; + +// IconButton: This is a simple helper class that represents clickable icons + +class IconButton: public QToolButton +{ + Q_OBJECT + Q_PROPERTY(float fader READ fader WRITE setFader) +public: + IconButton(QWidget *parent); + void paintEvent(QPaintEvent *event); + float fader() { return m_fader; } + void setFader(float value) { m_fader = value; update(); } + void animateShow(bool visible); + +private: + float m_fader; +}; + +// FilterWidget: For filtering item views, with reset button Uses HintLineEdit. + +class QDESIGNER_SHARED_EXPORT FilterWidget : public QWidget +{ + Q_OBJECT +public: + enum LayoutMode { + // For use in toolbars: Expand to the right + LayoutAlignRight, + // No special alignment + LayoutAlignNone + }; + + explicit FilterWidget(QWidget *parent = 0, LayoutMode lm = LayoutAlignRight); + + QString text() const; + void resizeEvent(QResizeEvent *); + bool refuseFocus() const; // see HintLineEdit + void setRefuseFocus(bool v); + +signals: + void filterChanged(const QString &); + +public slots: + void reset(); + +private slots: + void checkButton(const QString &text); + +private: + HintLineEdit *m_editor; + IconButton *m_button; + int m_buttonwidth; + QString m_oldText; +}; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif diff --git a/src/designer/src/lib/shared/formlayoutmenu.cpp b/src/designer/src/lib/shared/formlayoutmenu.cpp new file mode 100644 index 000000000..d52bb53f5 --- /dev/null +++ b/src/designer/src/lib/shared/formlayoutmenu.cpp @@ -0,0 +1,534 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "formlayoutmenu_p.h" +#include "layoutinfo_p.h" +#include "qdesigner_command_p.h" +#include "qdesigner_utils_p.h" +#include "qdesigner_propertycommand_p.h" +#include "ui_formlayoutrowdialog.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +static const char *buddyPropertyC = "buddy"; +static const char *fieldWidgetBaseClasses[] = { + "QLineEdit", "QComboBox", "QSpinBox", "QDoubleSpinBox", "QCheckBox", + "QDateEdit", "QTimeEdit", "QDateTimeEdit", "QDial", "QWidget" +}; + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// Struct that describes a row of controls (descriptive label and control) to +// be added to a form layout. +struct FormLayoutRow { + FormLayoutRow() : buddy(false) {} + + QString labelName; + QString labelText; + QString fieldClassName; + QString fieldName; + bool buddy; +}; + +// A Dialog to edit a FormLayoutRow. Lets the user input a label text, label +// name, field widget type, field object name and buddy setting. As the +// user types the label text; the object names to be used for label and field +// are updated. It also checks the buddy setting depending on whether the +// label text contains a buddy marker. +class FormLayoutRowDialog : public QDialog { + Q_DISABLE_COPY(FormLayoutRowDialog) + Q_OBJECT +public: + explicit FormLayoutRowDialog(QDesignerFormEditorInterface *core, + QWidget *parent); + + FormLayoutRow formLayoutRow() const; + + bool buddy() const; + void setBuddy(bool); + + // Accessors for form layout row numbers using 0..[n-1] convention + int row() const; + void setRow(int); + void setRowRange(int, int); + + QString fieldClass() const; + QString labelText() const; + + static QStringList fieldWidgetClasses(QDesignerFormEditorInterface *core); + +private slots: + void labelTextEdited(const QString &text); + void labelNameEdited(const QString &text); + void fieldNameEdited(const QString &text); + void buddyClicked(); + void fieldClassChanged(int); + +private: + bool isValid() const; + void updateObjectNames(bool updateLabel, bool updateField); + void updateOkButton(); + + // Check for buddy marker in string + const QRegExp m_buddyMarkerRegexp; + + Ui::FormLayoutRowDialog m_ui; + bool m_labelNameEdited; + bool m_fieldNameEdited; + bool m_buddyClicked; +}; + +FormLayoutRowDialog::FormLayoutRowDialog(QDesignerFormEditorInterface *core, + QWidget *parent) : + QDialog(parent), + m_buddyMarkerRegexp(QLatin1String("\\&[^&]")), + m_labelNameEdited(false), + m_fieldNameEdited(false), + m_buddyClicked(false) +{ + Q_ASSERT(m_buddyMarkerRegexp.isValid()); + + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + setModal(true); + m_ui.setupUi(this); + connect(m_ui.labelTextLineEdit, SIGNAL(textEdited(QString)), this, SLOT(labelTextEdited(QString))); + + QRegExpValidator *nameValidator = new QRegExpValidator(QRegExp(QLatin1String("^[a-zA-Z0-9_]+$")), this); + Q_ASSERT(nameValidator->regExp().isValid()); + + m_ui.labelNameLineEdit->setValidator(nameValidator); + connect(m_ui.labelNameLineEdit, SIGNAL(textEdited(QString)), + this, SLOT(labelNameEdited(QString))); + + m_ui.fieldNameLineEdit->setValidator(nameValidator); + connect(m_ui.fieldNameLineEdit, SIGNAL(textEdited(QString)), + this, SLOT(fieldNameEdited(QString))); + + connect(m_ui.buddyCheckBox, SIGNAL(clicked()), this, SLOT(buddyClicked())); + + m_ui.fieldClassComboBox->addItems(fieldWidgetClasses(core)); + m_ui.fieldClassComboBox->setCurrentIndex(0); + connect(m_ui.fieldClassComboBox, SIGNAL(currentIndexChanged(int)), + this, SLOT(fieldClassChanged(int))); + + updateOkButton(); +} + +FormLayoutRow FormLayoutRowDialog::formLayoutRow() const +{ + FormLayoutRow rc; + rc.labelText = labelText(); + rc.labelName = m_ui.labelNameLineEdit->text(); + rc.fieldClassName = fieldClass(); + rc.fieldName = m_ui.fieldNameLineEdit->text(); + rc.buddy = buddy(); + return rc; +} + +bool FormLayoutRowDialog::buddy() const +{ + return m_ui.buddyCheckBox->checkState() == Qt::Checked; +} + +void FormLayoutRowDialog::setBuddy(bool b) +{ + m_ui.buddyCheckBox->setCheckState(b ? Qt::Checked : Qt::Unchecked); +} + +// Convert rows to 1..n convention for users +int FormLayoutRowDialog::row() const +{ + return m_ui.rowSpinBox->value() - 1; +} + +void FormLayoutRowDialog::setRow(int row) +{ + m_ui.rowSpinBox->setValue(row + 1); +} + +void FormLayoutRowDialog::setRowRange(int from, int to) +{ + m_ui.rowSpinBox->setMinimum(from + 1); + m_ui.rowSpinBox->setMaximum(to + 1); + m_ui.rowSpinBox->setEnabled(to - from > 0); +} + +QString FormLayoutRowDialog::fieldClass() const +{ + return m_ui.fieldClassComboBox->itemText(m_ui.fieldClassComboBox->currentIndex()); +} + +QString FormLayoutRowDialog::labelText() const +{ + return m_ui.labelTextLineEdit->text(); +} + +bool FormLayoutRowDialog::isValid() const +{ + // Check for non-empty names and presence of buddy marker if checked + const QString name = labelText(); + if (name.isEmpty() || m_ui.labelNameLineEdit->text().isEmpty() || m_ui.fieldNameLineEdit->text().isEmpty()) + return false; + if (buddy() && !name.contains(m_buddyMarkerRegexp)) + return false; + return true; +} + +void FormLayoutRowDialog::updateOkButton() +{ + m_ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(isValid()); +} + +void FormLayoutRowDialog::labelTextEdited(const QString &text) +{ + updateObjectNames(true, true); + // Set buddy if '&' is present unless the user changed it + if (!m_buddyClicked) + setBuddy(text.contains(m_buddyMarkerRegexp)); + + updateOkButton(); +} + +// Get a suitable object name postfix from a class name: +// "namespace::QLineEdit"->"LineEdit" +static inline QString postFixFromClassName(QString className) +{ + const int index = className.lastIndexOf(QLatin1String("::")); + if (index != -1) + className.remove(0, index + 2); + if (className.size() > 2) + if (className.at(0) == QLatin1Char('Q') || className.at(0) == QLatin1Char('K')) + if (className.at(1).isUpper()) + className.remove(0, 1); + return className; +} + +// Helper routines to filter out characters for converting texts into +// class name prefixes. Only accepts ASCII characters/digits and underscores. + +enum PrefixCharacterKind { PC_Digit, PC_UpperCaseLetter, PC_LowerCaseLetter, + PC_Other, PC_Invalid }; + +static inline PrefixCharacterKind prefixCharacterKind(const QChar &c) +{ + switch (c.category()) { + case QChar::Number_DecimalDigit: + return PC_Digit; + case QChar::Letter_Lowercase: { + const char a = c.toAscii(); + if (a >= 'a' && a <= 'z') + return PC_LowerCaseLetter; + } + break; + case QChar::Letter_Uppercase: { + const char a = c.toAscii(); + if (a >= 'A' && a <= 'Z') + return PC_UpperCaseLetter; + } + break; + case QChar::Punctuation_Connector: + if (c.toAscii() == '_') + return PC_Other; + break; + default: + break; + } + return PC_Invalid; +} + +// Convert the text the user types into a usable class name prefix by filtering +// characters, lower-casing the first character and camel-casing subsequent +// words. ("zip code:") --> ("zipCode"). + +static QString prefixFromLabel(const QString &prefix) +{ + QString rc; + const int length = prefix.size(); + bool lastWasAcceptable = false; + for (int i = 0 ; i < length; i++) { + const QChar c = prefix.at(i); + const PrefixCharacterKind kind = prefixCharacterKind(c); + const bool acceptable = kind != PC_Invalid; + if (acceptable) { + if (rc.isEmpty()) { + // Lower-case first character + rc += kind == PC_UpperCaseLetter ? c.toLower() : c; + } else { + // Camel-case words + rc += !lastWasAcceptable && kind == PC_LowerCaseLetter ? c.toUpper() : c; + } + } + lastWasAcceptable = acceptable; + } + return rc; +} + +void FormLayoutRowDialog::updateObjectNames(bool updateLabel, bool updateField) +{ + // Generate label + field object names from the label text, that is, + // "&Zip code:" -> "zipcodeLabel", "zipcodeLineEdit" unless the user + // edited it. + const bool doUpdateLabel = !m_labelNameEdited && updateLabel; + const bool doUpdateField = !m_fieldNameEdited && updateField; + if (!doUpdateLabel && !doUpdateField) + return; + + const QString prefix = prefixFromLabel(labelText()); + // Set names + if (doUpdateLabel) + m_ui.labelNameLineEdit->setText(prefix + QLatin1String("Label")); + if (doUpdateField) + m_ui.fieldNameLineEdit->setText(prefix + postFixFromClassName(fieldClass())); +} + +void FormLayoutRowDialog::fieldClassChanged(int) +{ + updateObjectNames(false, true); +} + +void FormLayoutRowDialog::labelNameEdited(const QString & /*text*/) +{ + m_labelNameEdited = true; // stop auto-updating after user change + updateOkButton(); +} + +void FormLayoutRowDialog::fieldNameEdited(const QString & /*text*/) +{ + m_fieldNameEdited = true; // stop auto-updating after user change + updateOkButton(); +} + +void FormLayoutRowDialog::buddyClicked() +{ + m_buddyClicked = true; // stop auto-updating after user change + updateOkButton(); +} + +/* Create a list of classes suitable for field widgets. Take the fixed base + * classes provided and look in the widget database for custom widgets derived + * from them ("QLineEdit", "CustomLineEdit", "QComboBox"...). */ +QStringList FormLayoutRowDialog::fieldWidgetClasses(QDesignerFormEditorInterface *core) +{ + // Base class -> custom widgets map + typedef QMultiHash ClassMap; + + static QStringList rc; + if (rc.empty()) { + const int fwCount = sizeof(fieldWidgetBaseClasses)/sizeof(const char*); + // Turn known base classes into list + QStringList baseClasses; + for (int i = 0; i < fwCount; i++) + baseClasses.push_back(QLatin1String(fieldWidgetBaseClasses[i])); + // Scan for custom widgets that inherit them and store them in a + // multimap of base class->custom widgets unless we have a language + // extension installed which might do funny things with custom widgets. + ClassMap customClassMap; + if (qt_extension(core->extensionManager(), core) == 0) { + const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase(); + const int wdbCount = wdb->count(); + for (int w = 0; w < wdbCount; ++w) { + // Check for non-container custom types that extend the + // respective base class. + const QDesignerWidgetDataBaseItemInterface *dbItem = wdb->item(w); + if (!dbItem->isPromoted() && !dbItem->isContainer() && dbItem->isCustom()) { + const int index = baseClasses.indexOf(dbItem->extends()); + if (index != -1) + customClassMap.insert(baseClasses.at(index), dbItem->name()); + } + } + } + // Compile final list, taking each base class and append custom widgets + // based on it. + for (int i = 0; i < fwCount; i++) { + rc.push_back(baseClasses.at(i)); + rc += customClassMap.values(baseClasses.at(i)); + } + } + return rc; +} + +// ------------------ Utilities + +static QFormLayout *managedFormLayout(const QDesignerFormEditorInterface *core, const QWidget *w) +{ + QLayout *l = 0; + if (LayoutInfo::managedLayoutType(core, w, &l) == LayoutInfo::Form) + return qobject_cast(l); + return 0; +} + +// Create the widgets of a control row and apply text properties contained +// in the struct, called by addFormLayoutRow() +static QPair + createWidgets(const FormLayoutRow &row, QWidget *parent, + QDesignerFormWindowInterface *formWindow) +{ + QDesignerFormEditorInterface *core = formWindow->core(); + QDesignerWidgetFactoryInterface *wf = core->widgetFactory(); + + QPair rc = QPair(wf->createWidget(QLatin1String("QLabel"), parent), + wf->createWidget(row.fieldClassName, parent)); + // Set up properties of the label + const QString objectNameProperty = QLatin1String("objectName"); + QDesignerPropertySheetExtension *labelSheet = qt_extension(core->extensionManager(), rc.first); + int nameIndex = labelSheet->indexOf(objectNameProperty); + labelSheet->setProperty(nameIndex, QVariant::fromValue(PropertySheetStringValue(row.labelName))); + labelSheet->setChanged(nameIndex, true); + formWindow->ensureUniqueObjectName(rc.first); + const int textIndex = labelSheet->indexOf(QLatin1String("text")); + labelSheet->setProperty(textIndex, QVariant::fromValue(PropertySheetStringValue(row.labelText))); + labelSheet->setChanged(textIndex, true); + // Set up properties of the control + QDesignerPropertySheetExtension *controlSheet = qt_extension(core->extensionManager(), rc.second); + nameIndex = controlSheet->indexOf(objectNameProperty); + controlSheet->setProperty(nameIndex, QVariant::fromValue(PropertySheetStringValue(row.fieldName))); + controlSheet->setChanged(nameIndex, true); + formWindow->ensureUniqueObjectName(rc.second); + return rc; +} + +// Create a command sequence on the undo stack of the form window that creates +// the widgets of the row and inserts them into the form layout. +static void addFormLayoutRow(const FormLayoutRow &formLayoutRow, int row, QWidget *w, + QDesignerFormWindowInterface *formWindow) +{ + QFormLayout *formLayout = managedFormLayout(formWindow->core(), w); + Q_ASSERT(formLayout); + QUndoStack *undoStack = formWindow->commandHistory(); + const QString macroName = QCoreApplication::translate("Command", "Add '%1' to '%2'").arg(formLayoutRow.labelText, formLayout->objectName()); + undoStack->beginMacro(macroName); + + // Create a list of widget insertion commands and pass them a cell position + const QPair widgetPair = createWidgets(formLayoutRow, w, formWindow); + + InsertWidgetCommand *labelCmd = new InsertWidgetCommand(formWindow); + labelCmd->init(widgetPair.first, false, row, 0); + undoStack->push(labelCmd); + InsertWidgetCommand *controlCmd = new InsertWidgetCommand(formWindow); + controlCmd->init(widgetPair.second, false, row, 1); + undoStack->push(controlCmd); + if (formLayoutRow.buddy) { + SetPropertyCommand *buddyCommand = new SetPropertyCommand(formWindow); + buddyCommand->init(widgetPair.first, QLatin1String(buddyPropertyC), widgetPair.second->objectName()); + undoStack->push(buddyCommand); + } + undoStack->endMacro(); +} + +// ---------------- FormLayoutMenu +FormLayoutMenu::FormLayoutMenu(QObject *parent) : + QObject(parent), + m_separator1(new QAction(this)), + m_populateFormAction(new QAction(tr("Add form layout row..."), this)), + m_separator2(new QAction(this)) +{ + m_separator1->setSeparator(true); + connect(m_populateFormAction, SIGNAL(triggered()), this, SLOT(slotAddRow())); + m_separator2->setSeparator(true); +} + +void FormLayoutMenu::populate(QWidget *w, QDesignerFormWindowInterface *fw, ActionList &actions) +{ + switch (LayoutInfo::managedLayoutType(fw->core(), w)) { + case LayoutInfo::Form: + if (!actions.empty() && !actions.back()->isSeparator()) + actions.push_back(m_separator1); + actions.push_back(m_populateFormAction); + actions.push_back(m_separator2); + m_widget = w; + break; + default: + m_widget = 0; + break; + } +} + +void FormLayoutMenu::slotAddRow() +{ + QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(m_widget); + Q_ASSERT(m_widget && fw); + const int rowCount = managedFormLayout(fw->core(), m_widget)->rowCount(); + + FormLayoutRowDialog dialog(fw->core(), fw); + dialog.setRowRange(0, rowCount); + dialog.setRow(rowCount); + + if (dialog.exec() != QDialog::Accepted) + return; + addFormLayoutRow(dialog.formLayoutRow(), dialog.row(), m_widget, fw); +} + +QAction *FormLayoutMenu::preferredEditAction(QWidget *w, QDesignerFormWindowInterface *fw) +{ + if (LayoutInfo::managedLayoutType(fw->core(), w) == LayoutInfo::Form) { + m_widget = w; + return m_populateFormAction; + } + return 0; +} +} + +QT_END_NAMESPACE + +#include "formlayoutmenu.moc" + diff --git a/src/designer/src/lib/shared/formlayoutmenu_p.h b/src/designer/src/lib/shared/formlayoutmenu_p.h new file mode 100644 index 000000000..86f8575bd --- /dev/null +++ b/src/designer/src/lib/shared/formlayoutmenu_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FORMLAYOUTMENU +#define FORMLAYOUTMENU + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#include "shared_global_p.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +class QAction; +class QWidget; + +namespace qdesigner_internal { + +// Task menu to be used for form layouts. Offers an options "Add row" which +// pops up a dialog in which the user can specify label name, text and buddy. +class QDESIGNER_SHARED_EXPORT FormLayoutMenu : public QObject +{ + Q_DISABLE_COPY(FormLayoutMenu) + Q_OBJECT +public: + typedef QList ActionList; + + explicit FormLayoutMenu(QObject *parent); + + // Populate a list of actions with the form layout actions. + void populate(QWidget *w, QDesignerFormWindowInterface *fw, ActionList &actions); + // For implementing QDesignerTaskMenuExtension::preferredEditAction(): + // Return appropriate action for double clicking. + QAction *preferredEditAction(QWidget *w, QDesignerFormWindowInterface *fw); + +private slots: + void slotAddRow(); + +private: + QAction *m_separator1; + QAction *m_populateFormAction; + QAction *m_separator2; + QPointer m_widget; +}; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // FORMLAYOUTMENU diff --git a/src/designer/src/lib/shared/formlayoutrowdialog.ui b/src/designer/src/lib/shared/formlayoutrowdialog.ui new file mode 100644 index 000000000..c0e0cfe2b --- /dev/null +++ b/src/designer/src/lib/shared/formlayoutrowdialog.ui @@ -0,0 +1,166 @@ + + + FormLayoutRowDialog + + + Add Form Layout Row + + + + + + QFormLayout::ExpandingFieldsGrow + + + + + &Label text: + + + labelTextLineEdit + + + + + + + + 180 + 0 + + + + + + + + + + + Field &type: + + + fieldClassComboBox + + + + + + + + 0 + 0 + + + + + + + + &Field name: + + + fieldNameLineEdit + + + + + + + &Buddy: + + + buddyCheckBox + + + + + + + + + + + + + + &Row: + + + rowSpinBox + + + + + + + + + + + + + Label &name: + + + labelNameLineEdit + + + + + + + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + FormLayoutRowDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + FormLayoutRowDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/designer/src/lib/shared/formwindowbase.cpp b/src/designer/src/lib/shared/formwindowbase.cpp new file mode 100644 index 000000000..7c87eaf59 --- /dev/null +++ b/src/designer/src/lib/shared/formwindowbase.cpp @@ -0,0 +1,502 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "formwindowbase_p.h" +#include "connectionedit_p.h" +#include "qdesigner_command_p.h" +#include "qdesigner_propertysheet_p.h" +#include "qdesigner_propertyeditor_p.h" +#include "qdesigner_menu_p.h" +#include "qdesigner_menubar_p.h" +#include "shared_settings_p.h" +#include "grid_p.h" +#include "deviceprofile_p.h" +#include "qdesigner_utils_p.h" + +#include "qsimpleresource_p.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class FormWindowBasePrivate { +public: + explicit FormWindowBasePrivate(QDesignerFormEditorInterface *core); + + static Grid m_defaultGrid; + + QDesignerFormWindowInterface::Feature m_feature; + Grid m_grid; + bool m_hasFormGrid; + DesignerPixmapCache *m_pixmapCache; + DesignerIconCache *m_iconCache; + QtResourceSet *m_resourceSet; + QMap > m_reloadableResources; // bool is dummy, QMap used as QSet + QMap m_reloadablePropertySheets; + const DeviceProfile m_deviceProfile; + FormWindowBase::LineTerminatorMode m_lineTerminatorMode; + FormWindowBase::SaveResourcesBehaviour m_saveResourcesBehaviour; +}; + +FormWindowBasePrivate::FormWindowBasePrivate(QDesignerFormEditorInterface *core) : + m_feature(QDesignerFormWindowInterface::DefaultFeature), + m_grid(m_defaultGrid), + m_hasFormGrid(false), + m_pixmapCache(0), + m_iconCache(0), + m_resourceSet(0), + m_deviceProfile(QDesignerSharedSettings(core).currentDeviceProfile()), + m_lineTerminatorMode(FormWindowBase::NativeLineTerminator), + m_saveResourcesBehaviour(FormWindowBase::SaveAll) +{ +} + +Grid FormWindowBasePrivate::m_defaultGrid; + +FormWindowBase::FormWindowBase(QDesignerFormEditorInterface *core, QWidget *parent, Qt::WindowFlags flags) : + QDesignerFormWindowInterface(parent, flags), + m_d(new FormWindowBasePrivate(core)) +{ + syncGridFeature(); + m_d->m_pixmapCache = new DesignerPixmapCache(this); + m_d->m_iconCache = new DesignerIconCache(m_d->m_pixmapCache, this); +} + +FormWindowBase::~FormWindowBase() +{ + delete m_d; +} + +DesignerPixmapCache *FormWindowBase::pixmapCache() const +{ + return m_d->m_pixmapCache; +} + +DesignerIconCache *FormWindowBase::iconCache() const +{ + return m_d->m_iconCache; +} + +QtResourceSet *FormWindowBase::resourceSet() const +{ + return m_d->m_resourceSet; +} + +void FormWindowBase::setResourceSet(QtResourceSet *resourceSet) +{ + m_d->m_resourceSet = resourceSet; +} + +void FormWindowBase::addReloadableProperty(QDesignerPropertySheet *sheet, int index) +{ + m_d->m_reloadableResources[sheet][index] = true; +} + +void FormWindowBase::removeReloadableProperty(QDesignerPropertySheet *sheet, int index) +{ + m_d->m_reloadableResources[sheet].remove(index); + if (m_d->m_reloadableResources[sheet].count() == 0) + m_d->m_reloadableResources.remove(sheet); +} + +void FormWindowBase::addReloadablePropertySheet(QDesignerPropertySheet *sheet, QObject *object) +{ + if (qobject_cast(object) || + qobject_cast(object) || + qobject_cast(object) || + qobject_cast(object)) + m_d->m_reloadablePropertySheets[sheet] = object; +} + +void FormWindowBase::removeReloadablePropertySheet(QDesignerPropertySheet *sheet) +{ + m_d->m_reloadablePropertySheets.remove(sheet); +} + +void FormWindowBase::reloadProperties() +{ + pixmapCache()->clear(); + iconCache()->clear(); + QMapIterator > itSheet(m_d->m_reloadableResources); + while (itSheet.hasNext()) { + QDesignerPropertySheet *sheet = itSheet.next().key(); + QMapIterator itIndex(itSheet.value()); + while (itIndex.hasNext()) { + const int index = itIndex.next().key(); + const QVariant newValue = sheet->property(index); + if (qobject_cast(sheet->object()) && sheet->propertyName(index) == QLatin1String("text")) { + const PropertySheetStringValue newString = qvariant_cast(newValue); + // optimize a bit, reset only if the text value might contain a reference to qt resources + // (however reloading of icons other than taken from resources might not work here) + if (newString.value().contains(QLatin1String(":/"))) { + const QVariant resetValue = QVariant::fromValue(PropertySheetStringValue()); + sheet->setProperty(index, resetValue); + } + } + sheet->setProperty(index, newValue); + } + if (QTabWidget *tabWidget = qobject_cast(sheet->object())) { + const int count = tabWidget->count(); + const int current = tabWidget->currentIndex(); + const QString currentTabIcon = QLatin1String("currentTabIcon"); + for (int i = 0; i < count; i++) { + tabWidget->setCurrentIndex(i); + const int index = sheet->indexOf(currentTabIcon); + sheet->setProperty(index, sheet->property(index)); + } + tabWidget->setCurrentIndex(current); + } else if (QToolBox *toolBox = qobject_cast(sheet->object())) { + const int count = toolBox->count(); + const int current = toolBox->currentIndex(); + const QString currentItemIcon = QLatin1String("currentItemIcon"); + for (int i = 0; i < count; i++) { + toolBox->setCurrentIndex(i); + const int index = sheet->indexOf(currentItemIcon); + sheet->setProperty(index, sheet->property(index)); + } + toolBox->setCurrentIndex(current); + } + } + QMapIterator itSh(m_d->m_reloadablePropertySheets); + while (itSh.hasNext()) { + QObject *object = itSh.next().value(); + reloadIconResources(iconCache(), object); + } +} + +void FormWindowBase::resourceSetActivated(QtResourceSet *resource, bool resourceSetChanged) +{ + if (resource == resourceSet() && resourceSetChanged) { + reloadProperties(); + emit pixmapCache()->reloaded(); + emit iconCache()->reloaded(); + if (QDesignerPropertyEditor *propertyEditor = qobject_cast(core()->propertyEditor())) + propertyEditor->reloadResourceProperties(); + } +} + +QVariantMap FormWindowBase::formData() +{ + QVariantMap rc; + if (m_d->m_hasFormGrid) + m_d->m_grid.addToVariantMap(rc, true); + return rc; +} + +void FormWindowBase::setFormData(const QVariantMap &vm) +{ + Grid formGrid; + m_d->m_hasFormGrid = formGrid.fromVariantMap(vm); + if (m_d->m_hasFormGrid) + m_d->m_grid = formGrid; +} + +QPoint FormWindowBase::grid() const +{ + return QPoint(m_d->m_grid.deltaX(), m_d->m_grid.deltaY()); +} + +void FormWindowBase::setGrid(const QPoint &grid) +{ + m_d->m_grid.setDeltaX(grid.x()); + m_d->m_grid.setDeltaY(grid.y()); +} + +bool FormWindowBase::hasFeature(Feature f) const +{ + return f & m_d->m_feature; +} + +static void recursiveUpdate(QWidget *w) +{ + w->update(); + + const QObjectList &l = w->children(); + const QObjectList::const_iterator cend = l.constEnd(); + for (QObjectList::const_iterator it = l.constBegin(); it != cend; ++it) { + if (QWidget *w = qobject_cast(*it)) + recursiveUpdate(w); + } +} + +void FormWindowBase::setFeatures(Feature f) +{ + m_d->m_feature = f; + const bool enableGrid = f & GridFeature; + m_d->m_grid.setVisible(enableGrid); + m_d->m_grid.setSnapX(enableGrid); + m_d->m_grid.setSnapY(enableGrid); + emit featureChanged(f); + recursiveUpdate(this); +} + +FormWindowBase::Feature FormWindowBase::features() const +{ + return m_d->m_feature; +} + +bool FormWindowBase::gridVisible() const +{ + return m_d->m_grid.visible() && currentTool() == 0; +} + +FormWindowBase::SaveResourcesBehaviour FormWindowBase::saveResourcesBehaviour() const +{ + return m_d->m_saveResourcesBehaviour; +} + +void FormWindowBase::setSaveResourcesBehaviour(SaveResourcesBehaviour behaviour) +{ + m_d->m_saveResourcesBehaviour = behaviour; +} + +void FormWindowBase::syncGridFeature() +{ + if (m_d->m_grid.snapX() || m_d->m_grid.snapY()) + m_d->m_feature |= GridFeature; + else + m_d->m_feature &= ~GridFeature; +} + +void FormWindowBase::setDesignerGrid(const Grid& grid) +{ + m_d->m_grid = grid; + syncGridFeature(); + recursiveUpdate(this); +} + +const Grid &FormWindowBase::designerGrid() const +{ + return m_d->m_grid; +} + +bool FormWindowBase::hasFormGrid() const +{ + return m_d->m_hasFormGrid; +} + +void FormWindowBase::setHasFormGrid(bool b) +{ + m_d->m_hasFormGrid = b; +} + +void FormWindowBase::setDefaultDesignerGrid(const Grid& grid) +{ + FormWindowBasePrivate::m_defaultGrid = grid; +} + +const Grid &FormWindowBase::defaultDesignerGrid() +{ + return FormWindowBasePrivate::m_defaultGrid; +} + +QMenu *FormWindowBase::initializePopupMenu(QWidget * /*managedWidget*/) +{ + return 0; +} + +// Widget under mouse for finding the Widget to highlight +// when doing DnD. Restricts to pages by geometry if a container with +// a container extension (or one of its helper widgets) is hit; otherwise +// returns the widget as such (be it managed/unmanaged) + +QWidget *FormWindowBase::widgetUnderMouse(const QPoint &formPos, WidgetUnderMouseMode /* wum */) +{ + // widget_under_mouse might be some temporary thing like the dropLine. We need + // the actual widget that's part of the edited GUI. + QWidget *rc = widgetAt(formPos); + if (!rc || qobject_cast(rc)) + return 0; + + if (rc == mainContainer()) { + // Refuse main container areas if the main container has a container extension, + // for example when hitting QToolBox/QTabWidget empty areas. + if (qt_extension(core()->extensionManager(), rc)) + return 0; + return rc; + } + + // If we hit on container extension type container, make sure + // we use the top-most current page + if (QWidget *container = findContainer(rc, false)) + if (QDesignerContainerExtension *c = qt_extension(core()->extensionManager(), container)) { + // For container that do not have a "stacked" nature (QToolBox, QMdiArea), + // make sure the position is within the current page + const int ci = c->currentIndex(); + if (ci < 0) + return 0; + QWidget *page = c->widget(ci); + QRect pageGeometry = page->geometry(); + pageGeometry.moveTo(page->mapTo(this, pageGeometry.topLeft())); + if (!pageGeometry.contains(formPos)) + return 0; + return page; + } + + return rc; +} + +void FormWindowBase::deleteWidgetList(const QWidgetList &widget_list) +{ + // We need a macro here even for single widgets because the some components (for example, + // the signal slot editor are connected to widgetRemoved() and add their + // own commands (for example, to delete w's connections) + const QString description = widget_list.size() == 1 ? + tr("Delete '%1'").arg(widget_list.front()->objectName()) : tr("Delete"); + + commandHistory()->beginMacro(description); + foreach (QWidget *w, widget_list) { + emit widgetRemoved(w); + DeleteWidgetCommand *cmd = new DeleteWidgetCommand(this); + cmd->init(w); + commandHistory()->push(cmd); + } + commandHistory()->endMacro(); +} + +QMenu *FormWindowBase::createExtensionTaskMenu(QDesignerFormWindowInterface *fw, QObject *o, bool trailingSeparator) +{ + typedef QList ActionList; + ActionList actions; + // 1) Standard public extension + QExtensionManager *em = fw->core()->extensionManager(); + if (const QDesignerTaskMenuExtension *extTaskMenu = qt_extension(em, o)) + actions += extTaskMenu->taskActions(); + if (const QDesignerTaskMenuExtension *intTaskMenu = qobject_cast(em->extension(o, QLatin1String("QDesignerInternalTaskMenuExtension")))) { + if (!actions.empty()) { + QAction *a = new QAction(fw); + a->setSeparator(true); + actions.push_back(a); + } + actions += intTaskMenu->taskActions(); + } + if (actions.empty()) + return 0; + if (trailingSeparator && !actions.back()->isSeparator()) { + QAction *a = new QAction(fw); + a->setSeparator(true); + actions.push_back(a); + } + QMenu *rc = new QMenu; + const ActionList::const_iterator cend = actions.constEnd(); + for (ActionList::const_iterator it = actions.constBegin(); it != cend; ++it) + rc->addAction(*it); + return rc; +} + +void FormWindowBase::emitObjectRemoved(QObject *o) +{ + emit objectRemoved(o); +} + +DeviceProfile FormWindowBase::deviceProfile() const +{ + return m_d->m_deviceProfile; +} + +QString FormWindowBase::styleName() const +{ + return m_d->m_deviceProfile.isEmpty() ? QString() : m_d->m_deviceProfile.style(); +} + +void FormWindowBase::emitWidgetRemoved(QWidget *w) +{ + emit widgetRemoved(w); +} + +QString FormWindowBase::deviceProfileName() const +{ + return m_d->m_deviceProfile.isEmpty() ? QString() : m_d->m_deviceProfile.name(); +} + +void FormWindowBase::setLineTerminatorMode(FormWindowBase::LineTerminatorMode mode) +{ + m_d->m_lineTerminatorMode = mode; +} + +FormWindowBase::LineTerminatorMode FormWindowBase::lineTerminatorMode() const +{ + return m_d->m_lineTerminatorMode; +} + +void FormWindowBase::triggerDefaultAction(QWidget *widget) +{ + if (QAction *action = qdesigner_internal::preferredEditAction(core(), widget)) + QTimer::singleShot(0, action, SIGNAL(triggered())); +} + +void FormWindowBase::setupDefaultAction(QDesignerFormWindowInterface *fw) +{ + QObject::connect(fw, SIGNAL(activated(QWidget*)), fw, SLOT(triggerDefaultAction(QWidget*))); +} + +QString FormWindowBase::fileContents() const +{ + const bool oldValue = QSimpleResource::setWarningsEnabled(false); + const QString rc = contents(); + QSimpleResource::setWarningsEnabled(oldValue); + return rc; +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/formwindowbase_p.h b/src/designer/src/lib/shared/formwindowbase_p.h new file mode 100644 index 000000000..f0fb2e204 --- /dev/null +++ b/src/designer/src/lib/shared/formwindowbase_p.h @@ -0,0 +1,205 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef FORMWINDOWBASE_H +#define FORMWINDOWBASE_H + +#include "shared_global_p.h" + +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerDnDItemInterface; +class QMenu; +class QtResourceSet; +class QDesignerPropertySheet; + +namespace qdesigner_internal { + +class QEditorFormBuilder; +class DeviceProfile; +class Grid; + +class DesignerPixmapCache; +class DesignerIconCache; +class FormWindowBasePrivate; + +class QDESIGNER_SHARED_EXPORT FormWindowBase: public QDesignerFormWindowInterface +{ + Q_OBJECT +public: + enum HighlightMode { Restore, Highlight }; + enum SaveResourcesBehaviour { SaveAll, SaveOnlyUsedQrcFiles, DontSaveQrcFiles }; + + explicit FormWindowBase(QDesignerFormEditorInterface *core, QWidget *parent = 0, Qt::WindowFlags flags = 0); + virtual ~FormWindowBase(); + + QVariantMap formData(); + void setFormData(const QVariantMap &vm); + + // Return contents without warnings. Should be 'contents(bool quiet)' + QString fileContents() const; + + // Return the widget containing the form. This is used to + // apply embedded design settings to that are inherited (for example font). + // These are meant to be applied to the form only and not to the other editors + // in the widget stack. + virtual QWidget *formContainer() const = 0; + + // Deprecated + virtual QPoint grid() const; + + // Deprecated + virtual void setGrid(const QPoint &grid); + + virtual bool hasFeature(Feature f) const; + virtual Feature features() const; + virtual void setFeatures(Feature f); + + const Grid &designerGrid() const; + void setDesignerGrid(const Grid& grid); + + bool hasFormGrid() const; + void setHasFormGrid(bool b); + + bool gridVisible() const; + + SaveResourcesBehaviour saveResourcesBehaviour() const; + void setSaveResourcesBehaviour(SaveResourcesBehaviour behaviour); + + static const Grid &defaultDesignerGrid(); + static void setDefaultDesignerGrid(const Grid& grid); + + // Overwrite to initialize and return a full popup menu for a managed widget + virtual QMenu *initializePopupMenu(QWidget *managedWidget); + // Helper to create a basic popup menu from task menu extensions (internal/public) + static QMenu *createExtensionTaskMenu(QDesignerFormWindowInterface *fw, QObject *o, bool trailingSeparator = true); + + virtual bool dropWidgets(const QList &item_list, QWidget *target, + const QPoint &global_mouse_pos) = 0; + + // Helper to find the widget at the mouse position with some flags. + enum WidgetUnderMouseMode { FindSingleSelectionDropTarget, FindMultiSelectionDropTarget }; + QWidget *widgetUnderMouse(const QPoint &formPos, WidgetUnderMouseMode m); + + virtual QWidget *widgetAt(const QPoint &pos) = 0; + virtual QWidget *findContainer(QWidget *w, bool excludeLayout) const = 0; + + void deleteWidgetList(const QWidgetList &widget_list); + + virtual void highlightWidget(QWidget *w, const QPoint &pos, HighlightMode mode = Highlight) = 0; + + enum PasteMode { PasteAll, PasteActionsOnly }; + virtual void paste(PasteMode pasteMode) = 0; + + // Factory method to create a form builder + virtual QEditorFormBuilder *createFormBuilder() = 0; + + virtual bool blockSelectionChanged(bool blocked) = 0; + virtual void emitSelectionChanged() = 0; + + DesignerPixmapCache *pixmapCache() const; + DesignerIconCache *iconCache() const; + QtResourceSet *resourceSet() const; + void setResourceSet(QtResourceSet *resourceSet); + void addReloadableProperty(QDesignerPropertySheet *sheet, int index); + void removeReloadableProperty(QDesignerPropertySheet *sheet, int index); + void addReloadablePropertySheet(QDesignerPropertySheet *sheet, QObject *object); + void removeReloadablePropertySheet(QDesignerPropertySheet *sheet); + void reloadProperties(); + + void emitWidgetRemoved(QWidget *w); + void emitObjectRemoved(QObject *o); + + DeviceProfile deviceProfile() const; + QString styleName() const; + QString deviceProfileName() const; + + enum LineTerminatorMode { + LFLineTerminator, + CRLFLineTerminator, + NativeLineTerminator = +#if defined (Q_OS_WIN) + CRLFLineTerminator +#else + LFLineTerminator +#endif + }; + + void setLineTerminatorMode(LineTerminatorMode mode); + LineTerminatorMode lineTerminatorMode() const; + + // Connect the 'activated' (doubleclicked) signal of the form window to a + // slot triggering the default action (of the task menu) + static void setupDefaultAction(QDesignerFormWindowInterface *fw); + +public slots: + void resourceSetActivated(QtResourceSet *resourceSet, bool resourceSetChanged); + +private slots: + void triggerDefaultAction(QWidget *w); + +private: + void syncGridFeature(); + + FormWindowBasePrivate *m_d; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // FORMWINDOWBASE_H diff --git a/src/designer/src/lib/shared/grid.cpp b/src/designer/src/lib/shared/grid.cpp new file mode 100644 index 000000000..ba991c782 --- /dev/null +++ b/src/designer/src/lib/shared/grid.cpp @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "grid_p.h" + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static const bool defaultSnap = true; +static const bool defaultVisible = true; +static const int DEFAULT_GRID = 10; +static const char* KEY_VISIBLE = "gridVisible"; +static const char* KEY_SNAPX = "gridSnapX"; +static const char* KEY_SNAPY = "gridSnapY"; +static const char* KEY_DELTAX = "gridDeltaX"; +static const char* KEY_DELTAY = "gridDeltaY"; + +// Insert a value into the serialization map unless default +template + static inline void valueToVariantMap(T value, T defaultValue, const QString &key, QVariantMap &v, bool forceKey) { + if (forceKey || value != defaultValue) + v.insert(key, QVariant(value)); + } + +// Obtain a value form QVariantMap +template + static inline bool valueFromVariantMap(const QVariantMap &v, const QString &key, T &value) { + const QVariantMap::const_iterator it = v.constFind(key); + const bool found = it != v.constEnd(); + if (found) + value = qvariant_cast(it.value()); + return found; + } + +namespace qdesigner_internal +{ + +Grid::Grid() : + m_visible(defaultVisible), + m_snapX(defaultSnap), + m_snapY(defaultSnap), + m_deltaX(DEFAULT_GRID), + m_deltaY(DEFAULT_GRID) +{ +} + +bool Grid::fromVariantMap(const QVariantMap& vm) +{ + Grid grid; + bool anyData = valueFromVariantMap(vm, QLatin1String(KEY_VISIBLE), grid.m_visible); + anyData |= valueFromVariantMap(vm, QLatin1String(KEY_SNAPX), grid.m_snapX); + anyData |= valueFromVariantMap(vm, QLatin1String(KEY_SNAPY), grid.m_snapY); + anyData |= valueFromVariantMap(vm, QLatin1String(KEY_DELTAX), grid.m_deltaX); + anyData |= valueFromVariantMap(vm, QLatin1String(KEY_DELTAY), grid.m_deltaY); + if (!anyData) + return false; + if (grid.m_deltaX == 0 || grid.m_deltaY == 0) { + qWarning("Attempt to set invalid grid with a spacing of 0."); + return false; + } + *this = grid; + return true; +} + +QVariantMap Grid::toVariantMap(bool forceKeys) const +{ + QVariantMap rc; + addToVariantMap(rc, forceKeys); + return rc; +} + +void Grid::addToVariantMap(QVariantMap& vm, bool forceKeys) const +{ + valueToVariantMap(m_visible, defaultVisible, QLatin1String(KEY_VISIBLE), vm, forceKeys); + valueToVariantMap(m_snapX, defaultSnap, QLatin1String(KEY_SNAPX), vm, forceKeys); + valueToVariantMap(m_snapY, defaultSnap, QLatin1String(KEY_SNAPY), vm, forceKeys); + valueToVariantMap(m_deltaX, DEFAULT_GRID, QLatin1String(KEY_DELTAX), vm, forceKeys); + valueToVariantMap(m_deltaY, DEFAULT_GRID, QLatin1String(KEY_DELTAY), vm, forceKeys); +} + +void Grid::paint(QWidget *widget, QPaintEvent *e) const +{ + QPainter p(widget); + paint(p, widget, e); +} + +void Grid::paint(QPainter &p, const QWidget *widget, QPaintEvent *e) const +{ + p.setPen(widget->palette().dark().color()); + + if (m_visible) { + const int xstart = (e->rect().x() / m_deltaX) * m_deltaX; + const int ystart = (e->rect().y() / m_deltaY) * m_deltaY; + + const int xend = e->rect().right(); + const int yend = e->rect().bottom(); + + typedef QVector Points; + static Points points; + points.clear(); + + for (int x = xstart; x <= xend; x += m_deltaX) { + points.reserve((yend - ystart) / m_deltaY + 1); + for (int y = ystart; y <= yend; y += m_deltaY) + points.push_back(QPointF(x, y)); + p.drawPoints( &(*points.begin()), points.count()); + points.clear(); + } + } +} + +int Grid::snapValue(int value, int grid) const +{ + const int rest = value % grid; + const int absRest = (rest < 0) ? -rest : rest; + int offset = 0; + if (2 * absRest > grid) + offset = 1; + if (rest < 0) + offset *= -1; + return (value / grid + offset) * grid; +} + +QPoint Grid::snapPoint(const QPoint &p) const +{ + const int sx = m_snapX ? snapValue(p.x(), m_deltaX) : p.x(); + const int sy = m_snapY ? snapValue(p.y(), m_deltaY) : p.y(); + return QPoint(sx, sy); +} + +int Grid::widgetHandleAdjustX(int x) const +{ + return m_snapX ? (x / m_deltaX) * m_deltaX + 1 : x; +} + +int Grid::widgetHandleAdjustY(int y) const +{ + return m_snapY ? (y / m_deltaY) * m_deltaY + 1 : y; +} + +bool Grid::equals(const Grid &rhs) const +{ + return m_visible == rhs.m_visible && + m_snapX == rhs.m_snapX && + m_snapY == rhs.m_snapY && + m_deltaX == rhs.m_deltaX && + m_deltaY == rhs.m_deltaY; +} +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/grid_p.h b/src/designer/src/lib/shared/grid_p.h new file mode 100644 index 000000000..b9c7316df --- /dev/null +++ b/src/designer/src/lib/shared/grid_p.h @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_GRID_H +#define QDESIGNER_GRID_H + +#include "shared_global_p.h" + +#include + +QT_BEGIN_NAMESPACE + +class QWidget; +class QPaintEvent; +class QPainter; + +namespace qdesigner_internal { + +// Designer grid which is able to serialize to QVariantMap +class QDESIGNER_SHARED_EXPORT Grid +{ +public: + Grid(); + + bool fromVariantMap(const QVariantMap& vm); + + void addToVariantMap(QVariantMap& vm, bool forceKeys = false) const; + QVariantMap toVariantMap(bool forceKeys = false) const; + + inline bool visible() const { return m_visible; } + void setVisible(bool visible) { m_visible = visible; } + + inline bool snapX() const { return m_snapX; } + void setSnapX(bool snap) { m_snapX = snap; } + + inline bool snapY() const { return m_snapY; } + void setSnapY(bool snap) { m_snapY = snap; } + + inline int deltaX() const { return m_deltaX; } + void setDeltaX(int dx) { m_deltaX = dx; } + + inline int deltaY() const { return m_deltaY; } + void setDeltaY(int dy) { m_deltaY = dy; } + + void paint(QWidget *widget, QPaintEvent *e) const; + void paint(QPainter &p, const QWidget *widget, QPaintEvent *e) const; + + QPoint snapPoint(const QPoint &p) const; + + int widgetHandleAdjustX(int x) const; + int widgetHandleAdjustY(int y) const; + + inline bool operator==(const Grid &rhs) const { return equals(rhs); } + inline bool operator!=(const Grid &rhs) const { return !equals(rhs); } + +private: + bool equals(const Grid &rhs) const; + int snapValue(int value, int grid) const; + bool m_visible; + bool m_snapX; + bool m_snapY; + int m_deltaX; + int m_deltaY; +}; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QDESIGNER_GRID_H diff --git a/src/designer/src/lib/shared/gridpanel.cpp b/src/designer/src/lib/shared/gridpanel.cpp new file mode 100644 index 000000000..0319e5e95 --- /dev/null +++ b/src/designer/src/lib/shared/gridpanel.cpp @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "gridpanel_p.h" +#include "ui_gridpanel.h" +#include "grid_p.h" + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +GridPanel::GridPanel(QWidget *parentWidget) : + QWidget(parentWidget) +{ + m_ui = new Ui::GridPanel; + m_ui->setupUi(this); + + connect(m_ui->m_resetButton, SIGNAL(clicked()), this, SLOT(reset())); +} + +GridPanel::~GridPanel() +{ + delete m_ui; +} + +void GridPanel::setGrid(const Grid &g) +{ + m_ui->m_deltaXSpinBox->setValue(g.deltaX()); + m_ui->m_deltaYSpinBox->setValue(g.deltaY()); + m_ui->m_visibleCheckBox->setCheckState(g.visible() ? Qt::Checked : Qt::Unchecked); + m_ui->m_snapXCheckBox->setCheckState(g.snapX() ? Qt::Checked : Qt::Unchecked); + m_ui->m_snapYCheckBox->setCheckState(g.snapY() ? Qt::Checked : Qt::Unchecked); +} + +void GridPanel::setTitle(const QString &title) +{ + m_ui->m_gridGroupBox->setTitle(title); +} + +Grid GridPanel::grid() const +{ + Grid rc; + rc.setDeltaX(m_ui->m_deltaXSpinBox->value()); + rc.setDeltaY(m_ui->m_deltaYSpinBox->value()); + rc.setSnapX(m_ui->m_snapXCheckBox->checkState() == Qt::Checked); + rc.setSnapY(m_ui->m_snapYCheckBox->checkState() == Qt::Checked); + rc.setVisible(m_ui->m_visibleCheckBox->checkState() == Qt::Checked); + return rc; +} + +void GridPanel::reset() +{ + setGrid(Grid()); +} + +void GridPanel::setCheckable (bool c) +{ + m_ui->m_gridGroupBox->setCheckable(c); +} + +bool GridPanel::isCheckable () const +{ + return m_ui->m_gridGroupBox->isCheckable (); +} + +bool GridPanel::isChecked () const +{ + return m_ui->m_gridGroupBox->isChecked (); +} + +void GridPanel::setChecked(bool c) +{ + m_ui->m_gridGroupBox->setChecked(c); +} + +void GridPanel::setResetButtonVisible(bool v) +{ + m_ui->m_resetButton->setVisible(v); +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/gridpanel.ui b/src/designer/src/lib/shared/gridpanel.ui new file mode 100644 index 000000000..adfdd3684 --- /dev/null +++ b/src/designer/src/lib/shared/gridpanel.ui @@ -0,0 +1,144 @@ + + qdesigner_internal::GridPanel + + + + 0 + 0 + 393 + 110 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Grid + + + + + + + 0 + 0 + + + + Visible + + + + + + + Grid &X + + + m_deltaXSpinBox + + + + + + + 2 + + + 100 + + + + + + + + 0 + 0 + + + + Snap + + + + + + + + + Reset + + + + + + + Qt::Horizontal + + + + 20 + 20 + + + + + + + + + + Grid &Y + + + m_deltaYSpinBox + + + + + + + 2 + + + 100 + + + + + + + + 0 + 0 + + + + Snap + + + + + + + + + + + diff --git a/src/designer/src/lib/shared/gridpanel_p.h b/src/designer/src/lib/shared/gridpanel_p.h new file mode 100644 index 000000000..adcfa3850 --- /dev/null +++ b/src/designer/src/lib/shared/gridpanel_p.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the Qt tools. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef GRIDPANEL_H +#define GRIDPANEL_H + +#include "shared_global_p.h" + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class Grid; + +namespace Ui { + class GridPanel; +} + +class QDESIGNER_SHARED_EXPORT GridPanel : public QWidget +{ + Q_OBJECT +public: + GridPanel(QWidget *parent = 0); + ~GridPanel(); + + void setTitle(const QString &title); + + void setGrid(const Grid &g); + Grid grid() const; + + void setCheckable (bool c); + bool isCheckable () const; + + bool isChecked () const; + void setChecked(bool c); + + void setResetButtonVisible(bool v); + +private slots: + void reset(); + +private: + Ui::GridPanel *m_ui; +}; + +} // qdesigner_internal + +QT_END_NAMESPACE + +#endif // GRIDPANEL_H diff --git a/src/designer/src/lib/shared/htmlhighlighter.cpp b/src/designer/src/lib/shared/htmlhighlighter.cpp new file mode 100644 index 000000000..d16ce62aa --- /dev/null +++ b/src/designer/src/lib/shared/htmlhighlighter.cpp @@ -0,0 +1,198 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include "htmlhighlighter_p.h" + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +HtmlHighlighter::HtmlHighlighter(QTextEdit *textEdit) + : QSyntaxHighlighter(textEdit) +{ + QTextCharFormat entityFormat; + entityFormat.setForeground(Qt::red); + setFormatFor(Entity, entityFormat); + + QTextCharFormat tagFormat; + tagFormat.setForeground(Qt::darkMagenta); + tagFormat.setFontWeight(QFont::Bold); + setFormatFor(Tag, tagFormat); + + QTextCharFormat commentFormat; + commentFormat.setForeground(Qt::gray); + commentFormat.setFontItalic(true); + setFormatFor(Comment, commentFormat); + + QTextCharFormat attributeFormat; + attributeFormat.setForeground(Qt::black); + attributeFormat.setFontWeight(QFont::Bold); + setFormatFor(Attribute, attributeFormat); + + QTextCharFormat valueFormat; + valueFormat.setForeground(Qt::blue); + setFormatFor(Value, valueFormat); +} + +void HtmlHighlighter::setFormatFor(Construct construct, + const QTextCharFormat &format) +{ + m_formats[construct] = format; + rehighlight(); +} + +void HtmlHighlighter::highlightBlock(const QString &text) +{ + static const QLatin1Char tab = QLatin1Char('\t'); + static const QLatin1Char space = QLatin1Char(' '); + static const QLatin1Char amp = QLatin1Char('&'); + static const QLatin1Char startTag = QLatin1Char('<'); + static const QLatin1Char endTag = QLatin1Char('>'); + static const QLatin1Char quot = QLatin1Char('"'); + static const QLatin1Char apos = QLatin1Char('\''); + static const QLatin1Char semicolon = QLatin1Char(';'); + static const QLatin1Char equals = QLatin1Char('='); + static const QLatin1String startComment = QLatin1String(""); + static const QLatin1String endElement = QLatin1String("/>"); + + int state = previousBlockState(); + int len = text.length(); + int start = 0; + int pos = 0; + + while (pos < len) { + switch (state) { + case NormalState: + default: + while (pos < len) { + QChar ch = text.at(pos); + if (ch == startTag) { + if (text.mid(pos, 4) == startComment) { + state = InComment; + } else { + state = InTag; + start = pos; + while (pos < len && text.at(pos) != space + && text.at(pos) != endTag + && text.at(pos) != tab + && text.mid(pos, 2) != endElement) + ++pos; + if (text.mid(pos, 2) == endElement) + ++pos; + setFormat(start, pos - start, + m_formats[Tag]); + break; + } + break; + } else if (ch == amp) { + start = pos; + while (pos < len && text.at(pos++) != semicolon) + ; + setFormat(start, pos - start, + m_formats[Entity]); + } else { + // No tag, comment or entity started, continue... + ++pos; + } + } + break; + case InComment: + start = pos; + while (pos < len) { + if (text.mid(pos, 3) == endComment) { + pos += 3; + state = NormalState; + break; + } else { + ++pos; + } + } + setFormat(start, pos - start, m_formats[Comment]); + break; + case InTag: + QChar quote = QChar::Null; + while (pos < len) { + QChar ch = text.at(pos); + if (quote.isNull()) { + start = pos; + if (ch == apos || ch == quot) { + quote = ch; + } else if (ch == endTag) { + ++pos; + setFormat(start, pos - start, m_formats[Tag]); + state = NormalState; + break; + } else if (text.mid(pos, 2) == endElement) { + pos += 2; + setFormat(start, pos - start, m_formats[Tag]); + state = NormalState; + break; + } else if (ch != space && text.at(pos) != tab) { + // Tag not ending, not a quote and no whitespace, so + // we must be dealing with an attribute. + ++pos; + while (pos < len && text.at(pos) != space + && text.at(pos) != tab + && text.at(pos) != equals) + ++pos; + setFormat(start, pos - start, m_formats[Attribute]); + start = pos; + } + } else if (ch == quote) { + quote = QChar::Null; + + // Anything quoted is a value + setFormat(start, pos - start, m_formats[Value]); + } + ++pos; + } + break; + } + } + setCurrentBlockState(state); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/htmlhighlighter_p.h b/src/designer/src/lib/shared/htmlhighlighter_p.h new file mode 100644 index 000000000..3c9bfc34b --- /dev/null +++ b/src/designer/src/lib/shared/htmlhighlighter_p.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef HTMLHIGHLIGHTER_H +#define HTMLHIGHLIGHTER_H + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +/* HTML syntax highlighter based on Qt Quarterly example */ +class HtmlHighlighter : public QSyntaxHighlighter +{ + Q_OBJECT + +public: + enum Construct { + Entity, + Tag, + Comment, + Attribute, + Value, + LastConstruct = Value + }; + + HtmlHighlighter(QTextEdit *textEdit); + + void setFormatFor(Construct construct, const QTextCharFormat &format); + + QTextCharFormat formatFor(Construct construct) const + { return m_formats[construct]; } + +protected: + enum State { + NormalState = -1, + InComment, + InTag + }; + + void highlightBlock(const QString &text); + +private: + QTextCharFormat m_formats[LastConstruct + 1]; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // HTMLHIGHLIGHTER_H diff --git a/src/designer/src/lib/shared/iconloader.cpp b/src/designer/src/lib/shared/iconloader.cpp new file mode 100644 index 000000000..b7f74b224 --- /dev/null +++ b/src/designer/src/lib/shared/iconloader.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "iconloader_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +QDESIGNER_SHARED_EXPORT QIcon createIconSet(const QString &name) +{ + QStringList candidates = QStringList() + << (QString::fromUtf8(":/trolltech/formeditor/images/") + name) +#ifdef Q_WS_MAC + << (QString::fromUtf8(":/trolltech/formeditor/images/mac/") + name) +#else + << (QString::fromUtf8(":/trolltech/formeditor/images/win/") + name) +#endif + << (QString::fromUtf8(":/trolltech/formeditor/images/designer_") + name); + + foreach (const QString &f, candidates) { + if (QFile::exists(f)) + return QIcon(f); + } + + return QIcon(); +} + +QDESIGNER_SHARED_EXPORT QIcon emptyIcon() +{ + return QIcon(QLatin1String(":/trolltech/formeditor/images/emptyicon.png")); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + diff --git a/src/designer/src/lib/shared/iconloader_p.h b/src/designer/src/lib/shared/iconloader_p.h new file mode 100644 index 000000000..f0e4d0ace --- /dev/null +++ b/src/designer/src/lib/shared/iconloader_p.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef ICONLOADER_H +#define ICONLOADER_H + +#include "shared_global_p.h" + +QT_BEGIN_NAMESPACE + +class QString; +class QIcon; + +namespace qdesigner_internal { + +QDESIGNER_SHARED_EXPORT QIcon createIconSet(const QString &name); +QDESIGNER_SHARED_EXPORT QIcon emptyIcon(); + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // ICONLOADER_H diff --git a/src/designer/src/lib/shared/iconselector.cpp b/src/designer/src/lib/shared/iconselector.cpp new file mode 100644 index 000000000..0d6e3e0e8 --- /dev/null +++ b/src/designer/src/lib/shared/iconselector.cpp @@ -0,0 +1,655 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "iconselector_p.h" +#include "qdesigner_utils_p.h" +#include "qtresourcemodel_p.h" +#include "qtresourceview_p.h" +#include "iconloader_p.h" +#include "qdesigner_integration_p.h" +#include "formwindowbase_p.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// -------------------- LanguageResourceDialogPrivate +class LanguageResourceDialogPrivate { + LanguageResourceDialog *q_ptr; + Q_DECLARE_PUBLIC(LanguageResourceDialog) + +public: + LanguageResourceDialogPrivate(QDesignerResourceBrowserInterface *rb); + void init(LanguageResourceDialog *p); + + void setCurrentPath(const QString &filePath); + QString currentPath() const; + + void slotAccepted(); + void slotPathChanged(const QString &); + +private: + void setOkButtonEnabled(bool v) { m_dialogButtonBox->button(QDialogButtonBox::Ok)->setEnabled(v); } + static bool checkPath(const QString &p); + + QDesignerResourceBrowserInterface *m_browser; + QDialogButtonBox *m_dialogButtonBox; +}; + +LanguageResourceDialogPrivate::LanguageResourceDialogPrivate(QDesignerResourceBrowserInterface *rb) : + q_ptr(0), + m_browser(rb), + m_dialogButtonBox(new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel)) +{ + setOkButtonEnabled(false); +} + +void LanguageResourceDialogPrivate::init(LanguageResourceDialog *p) +{ + q_ptr = p; + QLayout *layout = new QVBoxLayout(p); + layout->addWidget(m_browser); + layout->addWidget(m_dialogButtonBox); + QObject::connect(m_dialogButtonBox, SIGNAL(accepted()), p, SLOT(slotAccepted())); + QObject::connect(m_dialogButtonBox, SIGNAL(rejected()), p, SLOT(reject())); + QObject::connect(m_browser, SIGNAL(currentPathChanged(QString)), p, SLOT(slotPathChanged(QString))); + QObject::connect(m_browser, SIGNAL(pathActivated(QString)), p, SLOT(slotAccepted())); + p->setModal(true); + p->setWindowTitle(LanguageResourceDialog::tr("Choose Resource")); + p->setWindowFlags(p->windowFlags() & ~Qt::WindowContextHelpButtonHint); + setOkButtonEnabled(false); +} + +void LanguageResourceDialogPrivate::setCurrentPath(const QString &filePath) +{ + m_browser->setCurrentPath(filePath); + setOkButtonEnabled(checkPath(filePath)); +} + +QString LanguageResourceDialogPrivate::currentPath() const +{ + return m_browser->currentPath(); +} + +bool LanguageResourceDialogPrivate::checkPath(const QString &p) +{ + return p.isEmpty() ? false : IconSelector::checkPixmap(p, IconSelector::CheckFast); +} + +void LanguageResourceDialogPrivate::slotAccepted() +{ + if (checkPath(currentPath())) + q_ptr->accept(); +} + +void LanguageResourceDialogPrivate::slotPathChanged(const QString &p) +{ + setOkButtonEnabled(checkPath(p)); +} + +// ------------ LanguageResourceDialog +LanguageResourceDialog::LanguageResourceDialog(QDesignerResourceBrowserInterface *rb, QWidget *parent) : + QDialog(parent), + d_ptr(new LanguageResourceDialogPrivate(rb)) +{ + d_ptr->init( this); +} + +LanguageResourceDialog::~LanguageResourceDialog() +{ +} + +void LanguageResourceDialog::setCurrentPath(const QString &filePath) +{ + d_ptr->setCurrentPath(filePath); +} + +QString LanguageResourceDialog::currentPath() const +{ + return d_ptr->currentPath(); +} + +LanguageResourceDialog* LanguageResourceDialog::create(QDesignerFormEditorInterface *core, QWidget *parent) +{ + if (QDesignerLanguageExtension *lang = qt_extension(core->extensionManager(), core)) + if (QDesignerResourceBrowserInterface *rb = lang->createResourceBrowser(0)) + return new LanguageResourceDialog(rb, parent); + if (QDesignerIntegration *di = qobject_cast(core->integration())) + if (QDesignerResourceBrowserInterface *rb = di->createResourceBrowser(0)) + return new LanguageResourceDialog(rb, parent); + return 0; +} + +// ------------ IconSelectorPrivate + +static inline QPixmap emptyPixmap() +{ + QImage img(16, 16, QImage::Format_ARGB32_Premultiplied); + img.fill(0); + return QPixmap::fromImage(img); +} + +class IconSelectorPrivate +{ + IconSelector *q_ptr; + Q_DECLARE_PUBLIC(IconSelector) +public: + IconSelectorPrivate(); + + void slotStateActivated(); + void slotSetActivated(); + void slotSetResourceActivated(); + void slotSetFileActivated(); + void slotResetActivated(); + void slotResetAllActivated(); + void slotUpdate(); + + QList, QString> > m_stateToName; // could be static map + + QMap, int> m_stateToIndex; + QMap > m_indexToState; + + const QIcon m_emptyIcon; + QComboBox *m_stateComboBox; + QToolButton *m_iconButton; + QAction *m_resetAction; + QAction *m_resetAllAction; + PropertySheetIconValue m_icon; + DesignerIconCache *m_iconCache; + DesignerPixmapCache *m_pixmapCache; + QtResourceModel *m_resourceModel; + QDesignerFormEditorInterface *m_core; +}; + +IconSelectorPrivate::IconSelectorPrivate() : + q_ptr(0), + m_emptyIcon(emptyPixmap()), + m_stateComboBox(0), + m_iconButton(0), + m_resetAction(0), + m_resetAllAction(0), + m_iconCache(0), + m_pixmapCache(0), + m_resourceModel(0), + m_core(0) +{ +} +void IconSelectorPrivate::slotUpdate() +{ + QIcon icon; + if (m_iconCache) + icon = m_iconCache->icon(m_icon); + + QMap, PropertySheetPixmapValue> paths = m_icon.paths(); + QMapIterator, int> itIndex(m_stateToIndex); + while (itIndex.hasNext()) { + const QPair state = itIndex.next().key(); + const PropertySheetPixmapValue pixmap = paths.value(state); + const int index = itIndex.value(); + + QIcon pixmapIcon = QIcon(icon.pixmap(16, 16, state.first, state.second)); + if (pixmapIcon.isNull()) + pixmapIcon = m_emptyIcon; + m_stateComboBox->setItemIcon(index, pixmapIcon); + QFont font = q_ptr->font(); + if (!pixmap.path().isEmpty()) + font.setBold(true); + m_stateComboBox->setItemData(index, font, Qt::FontRole); + } + + QPair state = m_indexToState.value(m_stateComboBox->currentIndex()); + PropertySheetPixmapValue currentPixmap = paths.value(state); + m_resetAction->setEnabled(!currentPixmap.path().isEmpty()); + m_resetAllAction->setEnabled(!paths.isEmpty()); + m_stateComboBox->update(); +} + +void IconSelectorPrivate::slotStateActivated() +{ + slotUpdate(); +} + +void IconSelectorPrivate::slotSetActivated() +{ + QPair state = m_indexToState.value(m_stateComboBox->currentIndex()); + const PropertySheetPixmapValue pixmap = m_icon.pixmap(state.first, state.second); + // Default to resource + const PropertySheetPixmapValue::PixmapSource ps = pixmap.path().isEmpty() ? PropertySheetPixmapValue::ResourcePixmap : pixmap.pixmapSource(m_core); + switch (ps) { + case PropertySheetPixmapValue::LanguageResourcePixmap: + case PropertySheetPixmapValue::ResourcePixmap: + slotSetResourceActivated(); + break; + case PropertySheetPixmapValue::FilePixmap: + slotSetFileActivated(); + break; + } +} + +// Choose a pixmap from resource; use language-dependent resource browser if present +QString IconSelector::choosePixmapResource(QDesignerFormEditorInterface *core, QtResourceModel *resourceModel, const QString &oldPath, QWidget *parent) +{ + Q_UNUSED(resourceModel) + QString rc; + + if (LanguageResourceDialog* ldlg = LanguageResourceDialog::create(core, parent)) { + ldlg->setCurrentPath(oldPath); + if (ldlg->exec() == QDialog::Accepted) + rc = ldlg->currentPath(); + delete ldlg; + } else { + QtResourceViewDialog dlg(core, parent); + + QDesignerIntegration *designerIntegration = qobject_cast(core->integration()); + if (designerIntegration) + dlg.setResourceEditingEnabled(designerIntegration->isResourceEditingEnabled()); + + dlg.selectResource(oldPath); + if (dlg.exec() == QDialog::Accepted) + rc = dlg.selectedResource(); + } + return rc; +} + +void IconSelectorPrivate::slotSetResourceActivated() +{ + const QPair state = m_indexToState.value(m_stateComboBox->currentIndex()); + + PropertySheetPixmapValue pixmap = m_icon.pixmap(state.first, state.second); + const QString oldPath = pixmap.path(); + const QString newPath = IconSelector::choosePixmapResource(m_core, m_resourceModel, oldPath, q_ptr); + if (newPath.isEmpty() || newPath == oldPath) + return; + const PropertySheetPixmapValue newPixmap = PropertySheetPixmapValue(newPath); + if (newPixmap != pixmap) { + m_icon.setPixmap(state.first, state.second, newPixmap); + slotUpdate(); + emit q_ptr->iconChanged(m_icon); + } +} + +// Helpers for choosing image files: Check for valid image. +bool IconSelector::checkPixmap(const QString &fileName, CheckMode cm, QString *errorMessage) +{ + const QFileInfo fi(fileName); + if (!fi.exists() || !fi.isFile() || !fi.isReadable()) { + if (errorMessage) + *errorMessage = tr("The pixmap file '%1' cannot be read.").arg(fileName); + return false; + } + QImageReader reader(fileName); + if (!reader.canRead()) { + if (errorMessage) + *errorMessage = tr("The file '%1' does not appear to be a valid pixmap file: %2").arg(fileName).arg(reader.errorString()); + return false; + } + if (cm == CheckFast) + return true; + + const QImage image = reader.read(); + if (image.isNull()) { + if (errorMessage) + *errorMessage = tr("The file '%1' could not be read: %2").arg(fileName).arg(reader.errorString()); + return false; + } + return true; +} + +// Helpers for choosing image files: Return an image filter for QFileDialog, courtesy of StyledButton +static QString imageFilter() +{ + QString filter = QApplication::translate("IconSelector", "All Pixmaps ("); + const QList supportedImageFormats = QImageReader::supportedImageFormats(); + const QString jpeg = QLatin1String("JPEG"); + const int count = supportedImageFormats.count(); + for (int i = 0; i< count; ++i) { + if (i) + filter += QLatin1Char(' '); + filter += QLatin1String("*."); + const QString outputFormat = QString::fromUtf8(supportedImageFormats.at(i)); + if (outputFormat != jpeg) + filter += outputFormat.toLower(); + else + filter += QLatin1String("jpg *.jpeg"); + } + filter += QLatin1Char(')'); + return filter; +} + +// Helpers for choosing image files: Choose a file +QString IconSelector::choosePixmapFile(const QString &directory, QDesignerDialogGuiInterface *dlgGui,QWidget *parent) +{ + QString errorMessage; + QString newPath; + do { + const QString title = tr("Choose a Pixmap"); + static const QString filter = imageFilter(); + newPath = dlgGui->getOpenImageFileName(parent, title, directory, filter); + if (newPath.isEmpty()) + break; + if (checkPixmap(newPath, CheckFully, &errorMessage)) + break; + dlgGui->message(parent, QDesignerDialogGuiInterface::ResourceEditorMessage, QMessageBox::Warning, tr("Pixmap Read Error"), errorMessage); + } while(true); + return newPath; +} + +void IconSelectorPrivate::slotSetFileActivated() +{ + QPair state = m_indexToState.value(m_stateComboBox->currentIndex()); + + PropertySheetPixmapValue pixmap = m_icon.pixmap(state.first, state.second); + const QString newPath = IconSelector::choosePixmapFile(pixmap.path(), m_core->dialogGui(), q_ptr); + if (!newPath.isEmpty()) { + const PropertySheetPixmapValue newPixmap = PropertySheetPixmapValue(newPath); + if (!(newPixmap == pixmap)) { + m_icon.setPixmap(state.first, state.second, newPixmap); + slotUpdate(); + emit q_ptr->iconChanged(m_icon); + } + } +} + +void IconSelectorPrivate::slotResetActivated() +{ + QPair state = m_indexToState.value(m_stateComboBox->currentIndex()); + + PropertySheetPixmapValue pixmap = m_icon.pixmap(state.first, state.second); + const PropertySheetPixmapValue newPixmap; + if (!(newPixmap == pixmap)) { + m_icon.setPixmap(state.first, state.second, newPixmap); + slotUpdate(); + emit q_ptr->iconChanged(m_icon); + } +} + +void IconSelectorPrivate::slotResetAllActivated() +{ + const PropertySheetIconValue newIcon; + if (!(m_icon == newIcon)) { + m_icon = newIcon; + slotUpdate(); + emit q_ptr->iconChanged(m_icon); + } +} + +// ------------- IconSelector +IconSelector::IconSelector(QWidget *parent) : + QWidget(parent), d_ptr(new IconSelectorPrivate()) +{ + d_ptr->q_ptr = this; + + d_ptr->m_stateComboBox = new QComboBox(this); + + QHBoxLayout *l = new QHBoxLayout(this); + d_ptr->m_iconButton = new QToolButton(this); + d_ptr->m_iconButton->setText(tr("...")); + d_ptr->m_iconButton->setPopupMode(QToolButton::MenuButtonPopup); + l->addWidget(d_ptr->m_stateComboBox); + l->addWidget(d_ptr->m_iconButton); + l->setMargin(0); + + d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Normal, QIcon::Off), tr("Normal Off") ); + d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Normal, QIcon::On), tr("Normal On") ); + d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Disabled, QIcon::Off), tr("Disabled Off") ); + d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Disabled, QIcon::On), tr("Disabled On") ); + d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Active, QIcon::Off), tr("Active Off") ); + d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Active, QIcon::On), tr("Active On") ); + d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Selected, QIcon::Off), tr("Selected Off") ); + d_ptr->m_stateToName << qMakePair(qMakePair(QIcon::Selected, QIcon::On), tr("Selected On") ); + + QMenu *setMenu = new QMenu(this); + + QAction *setResourceAction = new QAction(tr("Choose Resource..."), this); + QAction *setFileAction = new QAction(tr("Choose File..."), this); + d_ptr->m_resetAction = new QAction(tr("Reset"), this); + d_ptr->m_resetAllAction = new QAction(tr("Reset All"), this); + d_ptr->m_resetAction->setEnabled(false); + d_ptr->m_resetAllAction->setEnabled(false); + //d_ptr->m_resetAction->setIcon(createIconSet(QString::fromUtf8("resetproperty.png"))); + + setMenu->addAction(setResourceAction); + setMenu->addAction(setFileAction); + setMenu->addSeparator(); + setMenu->addAction(d_ptr->m_resetAction); + setMenu->addAction(d_ptr->m_resetAllAction); + + int index = 0; + QStringList items; + QListIterator, QString> > itName(d_ptr->m_stateToName); + while (itName.hasNext()) { + QPair, QString> item = itName.next(); + const QPair state = item.first; + const QString name = item.second; + + items.append(name); + d_ptr->m_stateToIndex[state] = index; + d_ptr->m_indexToState[index] = state; + index++; + } + d_ptr->m_stateComboBox->addItems(items); + + d_ptr->m_iconButton->setMenu(setMenu); + + connect(d_ptr->m_stateComboBox, SIGNAL(activated(int)), this, SLOT(slotStateActivated())); + connect(d_ptr->m_iconButton, SIGNAL(clicked()), this, SLOT(slotSetActivated())); + connect(setResourceAction, SIGNAL(triggered()), this, SLOT(slotSetResourceActivated())); + connect(setFileAction, SIGNAL(triggered()), this, SLOT(slotSetFileActivated())); + connect(d_ptr->m_resetAction, SIGNAL(triggered()), this, SLOT(slotResetActivated())); + connect(d_ptr->m_resetAllAction, SIGNAL(triggered()), this, SLOT(slotResetAllActivated())); + + d_ptr->slotUpdate(); +} + +IconSelector::~IconSelector() +{ +} + +void IconSelector::setIcon(const PropertySheetIconValue &icon) +{ + if (d_ptr->m_icon == icon) + return; + + d_ptr->m_icon = icon; + d_ptr->slotUpdate(); +} + +PropertySheetIconValue IconSelector::icon() const +{ + return d_ptr->m_icon; +} + +void IconSelector::setFormEditor(QDesignerFormEditorInterface *core) +{ + d_ptr->m_core = core; + d_ptr->m_resourceModel = core->resourceModel(); + d_ptr->slotUpdate(); +} + +void IconSelector::setIconCache(DesignerIconCache *iconCache) +{ + d_ptr->m_iconCache = iconCache; + connect(iconCache, SIGNAL(reloaded()), this, SLOT(slotUpdate())); + d_ptr->slotUpdate(); +} + +void IconSelector::setPixmapCache(DesignerPixmapCache *pixmapCache) +{ + d_ptr->m_pixmapCache = pixmapCache; + connect(pixmapCache, SIGNAL(reloaded()), this, SLOT(slotUpdate())); + d_ptr->slotUpdate(); +} + +// --- IconThemeEditor + +// Validator for theme line edit, accepts empty or non-blank strings. +class BlankSuppressingValidator : public QValidator { +public: + explicit BlankSuppressingValidator(QObject * parent = 0) : QValidator(parent) {} + + virtual State validate(QString &input, int &pos) const { + const int blankPos = input.indexOf(QLatin1Char(' ')); + if (blankPos != -1) { + pos = blankPos; + return Invalid; + } + return Acceptable; + } +}; + +struct IconThemeEditorPrivate { + IconThemeEditorPrivate(); + + const QPixmap m_emptyPixmap; + QLineEdit *m_themeLineEdit; + QLabel *m_themeLabel; +}; + +IconThemeEditorPrivate::IconThemeEditorPrivate() : + m_emptyPixmap(emptyPixmap()), + m_themeLineEdit(new QLineEdit), + m_themeLabel(new QLabel) +{ +} + +IconThemeEditor::IconThemeEditor(QWidget *parent, bool wantResetButton) : + QWidget (parent), d(new IconThemeEditorPrivate) +{ + QHBoxLayout *mainHLayout = new QHBoxLayout; + mainHLayout->setMargin(0); + + // Vertically center theme preview label + d->m_themeLabel->setPixmap(d->m_emptyPixmap); + + QVBoxLayout *themeLabelVLayout = new QVBoxLayout; + d->m_themeLabel->setMargin(1); + themeLabelVLayout->setMargin(0); + themeLabelVLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding)); + themeLabelVLayout->addWidget(d->m_themeLabel); + themeLabelVLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding)); + mainHLayout->addLayout(themeLabelVLayout); + + d->m_themeLineEdit = new QLineEdit; + d->m_themeLineEdit->setValidator(new BlankSuppressingValidator(d->m_themeLineEdit)); + connect(d->m_themeLineEdit, SIGNAL(textChanged(QString)), this, SLOT(slotChanged(QString))); + connect(d->m_themeLineEdit, SIGNAL(textEdited(QString)), this, SIGNAL(edited(QString))); + mainHLayout->addWidget(d->m_themeLineEdit); + + if (wantResetButton) { + QToolButton *themeResetButton = new QToolButton; + themeResetButton->setIcon(createIconSet(QLatin1String("resetproperty.png"))); + connect(themeResetButton, SIGNAL(clicked()), this, SLOT(reset())); + mainHLayout->addWidget(themeResetButton); + } + + setLayout(mainHLayout); + setFocusProxy(d->m_themeLineEdit); +} + +IconThemeEditor::~IconThemeEditor() +{ +} + +void IconThemeEditor::reset() +{ + d->m_themeLineEdit->clear(); + emit edited(QString()); +} + +void IconThemeEditor::slotChanged(const QString &theme) +{ + updatePreview(theme); +} + +void IconThemeEditor::updatePreview(const QString &t) +{ + // Update preview label with icon. + if (t.isEmpty() || !QIcon::hasThemeIcon(t)) { // Empty + const QPixmap *currentPixmap = d->m_themeLabel->pixmap(); + if (currentPixmap == 0 || currentPixmap->serialNumber() != d->m_emptyPixmap.serialNumber()) + d->m_themeLabel->setPixmap(d->m_emptyPixmap); + } else { + const QIcon icon = QIcon::fromTheme(t); + d->m_themeLabel->setPixmap(icon.pixmap(d->m_emptyPixmap.size())); + } +} + +QString IconThemeEditor::theme() const +{ + return d->m_themeLineEdit->text(); +} + +void IconThemeEditor::setTheme(const QString &t) +{ + d->m_themeLineEdit->setText(t); +} + +} // qdesigner_internal + +QT_END_NAMESPACE + +#include "moc_iconselector_p.cpp" diff --git a/src/designer/src/lib/shared/iconselector_p.h b/src/designer/src/lib/shared/iconselector_p.h new file mode 100644 index 000000000..4f68b730f --- /dev/null +++ b/src/designer/src/lib/shared/iconselector_p.h @@ -0,0 +1,172 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef ICONSELECTOR_H +#define ICONSELECTOR_H + +#include "shared_global_p.h" + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QtResourceModel; +class QDesignerFormEditorInterface; +class QDesignerDialogGuiInterface; +class QDesignerResourceBrowserInterface; + +namespace qdesigner_internal { + +class DesignerIconCache; +class DesignerPixmapCache; +class PropertySheetIconValue; +struct IconThemeEditorPrivate; + +// Resource Dialog that embeds the language-dependent resource widget as returned by the language extension +class QDESIGNER_SHARED_EXPORT LanguageResourceDialog : public QDialog +{ + Q_OBJECT + + explicit LanguageResourceDialog(QDesignerResourceBrowserInterface *rb, QWidget *parent = 0); + +public: + virtual ~LanguageResourceDialog(); + // Factory: Returns 0 if the language extension does not provide a resource browser. + static LanguageResourceDialog* create(QDesignerFormEditorInterface *core, QWidget *parent); + + void setCurrentPath(const QString &filePath); + QString currentPath() const; + +private: + QScopedPointer d_ptr; + Q_DECLARE_PRIVATE(LanguageResourceDialog) + Q_DISABLE_COPY(LanguageResourceDialog) + Q_PRIVATE_SLOT(d_func(), void slotAccepted()) + Q_PRIVATE_SLOT(d_func(), void slotPathChanged(QString)) + +}; + +class QDESIGNER_SHARED_EXPORT IconSelector: public QWidget +{ + Q_OBJECT +public: + IconSelector(QWidget *parent = 0); + virtual ~IconSelector(); + + void setFormEditor(QDesignerFormEditorInterface *core); // required for dialog gui. + void setIconCache(DesignerIconCache *iconCache); + void setPixmapCache(DesignerPixmapCache *pixmapCache); + + void setIcon(const PropertySheetIconValue &icon); + PropertySheetIconValue icon() const; + + // Check whether a pixmap may be read + enum CheckMode { CheckFast, CheckFully }; + static bool checkPixmap(const QString &fileName, CheckMode cm = CheckFully, QString *errorMessage = 0); + // Choose a pixmap from file + static QString choosePixmapFile(const QString &directory, QDesignerDialogGuiInterface *dlgGui, QWidget *parent); + // Choose a pixmap from resource; use language-dependent resource browser if present + static QString choosePixmapResource(QDesignerFormEditorInterface *core, QtResourceModel *resourceModel, const QString &oldPath, QWidget *parent); + +signals: + void iconChanged(const PropertySheetIconValue &icon); +private: + QScopedPointer d_ptr; + Q_DECLARE_PRIVATE(IconSelector) + Q_DISABLE_COPY(IconSelector) + + Q_PRIVATE_SLOT(d_func(), void slotStateActivated()) + Q_PRIVATE_SLOT(d_func(), void slotSetActivated()) + Q_PRIVATE_SLOT(d_func(), void slotSetResourceActivated()) + Q_PRIVATE_SLOT(d_func(), void slotSetFileActivated()) + Q_PRIVATE_SLOT(d_func(), void slotResetActivated()) + Q_PRIVATE_SLOT(d_func(), void slotResetAllActivated()) + Q_PRIVATE_SLOT(d_func(), void slotUpdate()) +}; + +// IconThemeEditor: Let's the user input theme icon names and shows a preview label. +class QDESIGNER_SHARED_EXPORT IconThemeEditor : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QString theme READ theme WRITE setTheme DESIGNABLE true) +public: + explicit IconThemeEditor(QWidget *parent = 0, bool wantResetButton = true); + virtual ~IconThemeEditor(); + + QString theme() const; + void setTheme(const QString &theme); + +signals: + void edited(const QString &); + +public slots: + void reset(); + +private slots: + void slotChanged(const QString &); + +private: + void updatePreview(const QString &); + + QScopedPointer d; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // ICONSELECTOR_H + diff --git a/src/designer/src/lib/shared/invisible_widget.cpp b/src/designer/src/lib/shared/invisible_widget.cpp new file mode 100644 index 000000000..6aceeaa52 --- /dev/null +++ b/src/designer/src/lib/shared/invisible_widget.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "invisible_widget_p.h" + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +InvisibleWidget::InvisibleWidget(QWidget *parent) + : QWidget() +{ + setAttribute(Qt::WA_NoChildEventsForParent); + setParent(parent); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/invisible_widget_p.h b/src/designer/src/lib/shared/invisible_widget_p.h new file mode 100644 index 000000000..04ca72458 --- /dev/null +++ b/src/designer/src/lib/shared/invisible_widget_p.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef INVISIBLE_WIDGET_H +#define INVISIBLE_WIDGET_H + +#include "shared_global_p.h" + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QDESIGNER_SHARED_EXPORT InvisibleWidget: public QWidget +{ + Q_OBJECT +public: + InvisibleWidget(QWidget *parent = 0); +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // INVISIBLE_WIDGET_H diff --git a/src/designer/src/lib/shared/layout.cpp b/src/designer/src/lib/shared/layout.cpp new file mode 100644 index 000000000..9fe438b08 --- /dev/null +++ b/src/designer/src/lib/shared/layout.cpp @@ -0,0 +1,1332 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "layout_p.h" +#include "qdesigner_utils_p.h" +#include "qlayout_widget_p.h" +#include "spacer_widget_p.h" +#include "layoutdecoration.h" +#include "widgetfactory_p.h" +#include "qdesigner_widgetitem_p.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +enum { FormLayoutColumns = 2 }; + +namespace qdesigner_internal { + +/* The wizard has a policy of setting a size policy of its external children + * according to the page being expanding or not (in the latter case, the + * page will be pushed to the top). When setting/breaking layouts, this needs + * to be updated, which happens via a fake style change event. */ + +void updateWizardLayout(QWidget *layoutBase); + +class FriendlyWizardPage : public QWizardPage { + friend void updateWizardLayout(QWidget *); +}; + +void updateWizardLayout(QWidget *layoutBase) +{ + if (QWizardPage *wizardPage = qobject_cast(layoutBase)) + if (QWizard *wizard = static_cast(wizardPage)->wizard()) { + QEvent event(QEvent::StyleChange); + QApplication::sendEvent(wizard, &event); + } +} + +/*! + \class Layout layout.h + \brief Baseclass for layouting widgets in the Designer (Helper for Layout commands) + \internal + + Classes derived from this abstract base class are used for layouting + operations in the Designer (creating/breaking layouts). + + Instances live in the Layout/BreakLayout commands. +*/ + +/*! \a p specifies the parent of the layoutBase \a lb. The parent + might be changed in setup(). If the layoutBase is a + container, the parent and the layoutBase are the same. Also they + always have to be a widget known to the designer (e.g. in the case + of the tabwidget parent and layoutBase are the tabwidget and not the + page which actually gets laid out. For actual usage the correct + widget is found later by Layout.) + */ + +Layout::Layout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb, LayoutInfo::Type layoutType) : + m_widgets(wl), + m_parentWidget(p), + m_layoutBase(lb), + m_formWindow(fw), + m_layoutType(layoutType), + m_reparentLayoutWidget(true), + m_isBreak(false) +{ + if (m_layoutBase) + m_oldGeometry = m_layoutBase->geometry(); +} + +Layout::~Layout() +{ +} + +/*! The widget list we got in the constructor might contain too much + widgets (like widgets with different parents, already laid out + widgets, etc.). Here we set up the list and so the only the "best" + widgets get laid out. +*/ + +void Layout::setup() +{ + m_startPoint = QPoint(32767, 32767); + + // Go through all widgets of the list we got. As we can only + // layout widgets which have the same parent, we first do some + // sorting which means create a list for each parent containing + // its child here. After that we keep working on the list of + // children which has the most entries. + // Widgets which are already laid out are thrown away here too + + QMultiMap lists; + foreach (QWidget *w, m_widgets) { + QWidget *p = w->parentWidget(); + + if (p && LayoutInfo::layoutType(m_formWindow->core(), p) != LayoutInfo::NoLayout + && m_formWindow->core()->metaDataBase()->item(p->layout()) != 0) + continue; + + lists.insert(p, w); + } + + QWidgetList lastList; + QWidgetList parents = lists.keys(); + foreach (QWidget *p, parents) { + QWidgetList children = lists.values(p); + + if (children.count() > lastList.count()) + lastList = children; + } + + + // If we found no list (because no widget did fit at all) or the + // best list has only one entry and we do not layout a container, + // we leave here. + QDesignerWidgetDataBaseInterface *widgetDataBase = m_formWindow->core()->widgetDataBase(); + if (lastList.count() < 2 && + (!m_layoutBase || + (!widgetDataBase->isContainer(m_layoutBase, false) && + m_layoutBase != m_formWindow->mainContainer())) + ) { + m_widgets.clear(); + m_startPoint = QPoint(0, 0); + return; + } + + // Now we have a new and clean widget list, which makes sense + // to layout + m_widgets = lastList; + // Also use the only correct parent later, so store it + + Q_ASSERT(m_widgets.isEmpty() == false); + + m_parentWidget = m_formWindow->core()->widgetFactory()->widgetOfContainer(m_widgets.first()->parentWidget()); + // Now calculate the position where the layout-meta-widget should + // be placed and connect to widgetDestroyed() signals of the + // widgets to get informed if one gets deleted to be able to + // handle that and do not crash in this case + foreach (QWidget *w, m_widgets) { + connect(w, SIGNAL(destroyed()), this, SLOT(widgetDestroyed())); + m_startPoint = QPoint(qMin(m_startPoint.x(), w->x()), qMin(m_startPoint.y(), w->y())); + const QRect rc(w->geometry()); + + m_geometries.insert(w, rc); + // Change the Z-order, as saving/loading uses the Z-order for + // writing/creating widgets and this has to be the same as in + // the layout. Else saving + loading will give different results + w->raise(); + } + + sort(); +} + +void Layout::widgetDestroyed() +{ + if (QWidget *w = qobject_cast(sender())) { + m_widgets.removeAt(m_widgets.indexOf(w)); + m_geometries.remove(w); + } +} + +bool Layout::prepareLayout(bool &needMove, bool &needReparent) +{ + foreach (QWidget *widget, m_widgets) { + widget->raise(); + } + + needMove = !m_layoutBase; + needReparent = needMove || (m_reparentLayoutWidget && qobject_cast(m_layoutBase)) || qobject_cast(m_layoutBase); + + QDesignerWidgetFactoryInterface *widgetFactory = m_formWindow->core()->widgetFactory(); + QDesignerMetaDataBaseInterface *metaDataBase = m_formWindow->core()->metaDataBase(); + + if (m_layoutBase == 0) { + const bool useSplitter = m_layoutType == LayoutInfo::HSplitter || m_layoutType == LayoutInfo::VSplitter; + const QString baseWidgetClassName = useSplitter ? QLatin1String("QSplitter") : QLatin1String("QLayoutWidget"); + m_layoutBase = widgetFactory->createWidget(baseWidgetClassName, widgetFactory->containerOfWidget(m_parentWidget)); + if (useSplitter) { + m_layoutBase->setObjectName(QLatin1String("splitter")); + m_formWindow->ensureUniqueObjectName(m_layoutBase); + } + } else { + LayoutInfo::deleteLayout(m_formWindow->core(), m_layoutBase); + } + + metaDataBase->add(m_layoutBase); + + Q_ASSERT(m_layoutBase->layout() == 0 || metaDataBase->item(m_layoutBase->layout()) == 0); + + return true; +} + +static bool isMainContainer(QDesignerFormWindowInterface *fw, const QWidget *w) +{ + return w && (w == fw || w == fw->mainContainer()); +} + +static bool isPageOfContainerWidget(QDesignerFormWindowInterface *fw, QWidget *widget) +{ + QDesignerContainerExtension *c = qt_extension( + fw->core()->extensionManager(), widget->parentWidget()); + + if (c != 0) { + for (int i = 0; icount(); ++i) { + if (widget == c->widget(i)) + return true; + } + } + + return false; +} +void Layout::finishLayout(bool needMove, QLayout *layout) +{ + if (m_parentWidget == m_layoutBase) { + QWidget *widget = m_layoutBase; + m_oldGeometry = widget->geometry(); + + bool done = false; + while (!isMainContainer(m_formWindow, widget) && !done) { + if (!m_formWindow->isManaged(widget)) { + widget = widget->parentWidget(); + continue; + } else if (LayoutInfo::isWidgetLaidout(m_formWindow->core(), widget)) { + widget = widget->parentWidget(); + continue; + } else if (isPageOfContainerWidget(m_formWindow, widget)) { + widget = widget->parentWidget(); + continue; + } else if (widget->parentWidget()) { + QScrollArea *area = qobject_cast(widget->parentWidget()->parentWidget()); + if (area && area->widget() == widget) { + widget = area; + continue; + } + } + + done = true; + } + updateWizardLayout(m_layoutBase); + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + // We don't want to resize the form window + if (!Utils::isCentralWidget(m_formWindow, widget)) + widget->adjustSize(); + + return; + } + + if (needMove) + m_layoutBase->move(m_startPoint); + + const QRect g(m_layoutBase->pos(), m_layoutBase->size()); + + if (LayoutInfo::layoutType(m_formWindow->core(), m_layoutBase->parentWidget()) == LayoutInfo::NoLayout && !m_isBreak) + m_layoutBase->adjustSize(); + else if (m_isBreak) + m_layoutBase->setGeometry(m_oldGeometry); + + m_oldGeometry = g; + if (layout) + layout->invalidate(); + m_layoutBase->show(); + + if (qobject_cast(m_layoutBase) || qobject_cast(m_layoutBase)) { + m_formWindow->clearSelection(false); + m_formWindow->manageWidget(m_layoutBase); + m_formWindow->selectWidget(m_layoutBase); + } +} + +void Layout::undoLayout() +{ + if (!m_widgets.count()) + return; + + m_formWindow->selectWidget(m_layoutBase, false); + + QDesignerWidgetFactoryInterface *widgetFactory = m_formWindow->core()->widgetFactory(); + QHashIterator it(m_geometries); + while (it.hasNext()) { + it.next(); + + if (!it.key()) + continue; + + QWidget* w = it.key(); + const QRect rc = it.value(); + + const bool showIt = w->isVisibleTo(m_formWindow); + QWidget *container = widgetFactory->containerOfWidget(m_parentWidget); + + // ### remove widget here + QWidget *parentWidget = w->parentWidget(); + QDesignerFormEditorInterface *core = m_formWindow->core(); + QDesignerLayoutDecorationExtension *deco = qt_extension(core->extensionManager(), parentWidget); + + if (deco) + deco->removeWidget(w); + + w->setParent(container); + w->setGeometry(rc); + + if (showIt) + w->show(); + } + + LayoutInfo::deleteLayout(m_formWindow->core(), m_layoutBase); + + if (m_parentWidget != m_layoutBase && !qobject_cast(m_layoutBase)) { + m_formWindow->unmanageWidget(m_layoutBase); + m_layoutBase->hide(); + } else { + QMainWindow *mw = qobject_cast(m_formWindow->mainContainer()); + if (m_layoutBase != m_formWindow->mainContainer() && + (!mw || mw->centralWidget() != m_layoutBase)) + m_layoutBase->setGeometry(m_oldGeometry); + } +} + +void Layout::breakLayout() +{ + typedef QMap WidgetRectMap; + WidgetRectMap rects; + /* Store the geometry of the widgets. The idea is to give the user space + * to rearrange them, so, we do a adjustSize() on them, unless they want + * to grow (expanding widgets like QTextEdit), in which the geometry is + * preserved. Note that historically, geometries were re-applied + * only after breaking splitters. */ + foreach (QWidget *w, m_widgets) { + const QRect geom = w->geometry(); + const QSize sizeHint = w->sizeHint(); + const bool restoreGeometry = sizeHint.isEmpty() || sizeHint.width() > geom.width() || sizeHint.height() > geom.height(); + rects.insert(w, restoreGeometry ? w->geometry() : QRect(geom.topLeft(), QSize())); + } + const QPoint m_layoutBasePos = m_layoutBase->pos(); + QDesignerWidgetDataBaseInterface *widgetDataBase = m_formWindow->core()->widgetDataBase(); + + LayoutInfo::deleteLayout(m_formWindow->core(), m_layoutBase); + + const bool needReparent = (m_reparentLayoutWidget && qobject_cast(m_layoutBase)) || + qobject_cast(m_layoutBase) || + (!widgetDataBase->isContainer(m_layoutBase, false) && + m_layoutBase != m_formWindow->mainContainer()); + const bool add = m_geometries.isEmpty(); + + QMapIterator it(rects); + while (it.hasNext()) { + it.next(); + + QWidget *w = it.key(); + if (needReparent) { + w->setParent(m_layoutBase->parentWidget(), 0); + w->move(m_layoutBasePos + it.value().topLeft()); + w->show(); + } + + const QRect oldGeometry = it.value(); + if (oldGeometry.isEmpty()) { + w->adjustSize(); + } else { + w->resize(oldGeometry.size()); + } + + if (add) + m_geometries.insert(w, QRect(w->pos(), w->size())); + } + + if (needReparent) { + m_layoutBase->hide(); + m_parentWidget = m_layoutBase->parentWidget(); + m_formWindow->unmanageWidget(m_layoutBase); + } else { + m_parentWidget = m_layoutBase; + } + updateWizardLayout(m_layoutBase); + + if (!m_widgets.isEmpty() && m_widgets.first() && m_widgets.first()->isVisibleTo(m_formWindow)) + m_formWindow->selectWidget(m_widgets.first()); + else + m_formWindow->selectWidget(m_formWindow); +} + +static QString suggestLayoutName(const char *className) +{ + // Legacy + if (!qstrcmp(className, "QHBoxLayout")) + return QLatin1String("horizontalLayout"); + if (!qstrcmp(className, "QVBoxLayout")) + return QLatin1String("verticalLayout"); + if (!qstrcmp(className, "QGridLayout")) + return QLatin1String("gridLayout"); + + return qtify(QString::fromUtf8(className)); +} +QLayout *Layout::createLayout(int type) +{ + Q_ASSERT(m_layoutType != LayoutInfo::HSplitter && m_layoutType != LayoutInfo::VSplitter); + QLayout *layout = m_formWindow->core()->widgetFactory()->createLayout(m_layoutBase, 0, type); + // set a name + layout->setObjectName(suggestLayoutName(layout->metaObject()->className())); + m_formWindow->ensureUniqueObjectName(layout); + // QLayoutWidget + QDesignerPropertySheetExtension *sheet = qt_extension(m_formWindow->core()->extensionManager(), layout); + if (sheet && qobject_cast(m_layoutBase)) { + sheet->setProperty(sheet->indexOf(QLatin1String("leftMargin")), 0); + sheet->setProperty(sheet->indexOf(QLatin1String("topMargin")), 0); + sheet->setProperty(sheet->indexOf(QLatin1String("rightMargin")), 0); + sheet->setProperty(sheet->indexOf(QLatin1String("bottomMargin")), 0); + } + return layout; +} + +void Layout::reparentToLayoutBase(QWidget *w) +{ + if (w->parent() != m_layoutBase) { + w->setParent(m_layoutBase, 0); + w->move(QPoint(0,0)); + } +} + +namespace { // within qdesigner_internal + +// ----- PositionSortPredicate: Predicate to be usable as LessThan function to sort widgets by position +class PositionSortPredicate { +public: + PositionSortPredicate(Qt::Orientation orientation) : m_orientation(orientation) {} + bool operator()(const QWidget* w1, const QWidget* w2) { + return m_orientation == Qt::Horizontal ? w1->x() < w2->x() : w1->y() < w2->y(); + } + private: + const Qt::Orientation m_orientation; +}; + +// -------- BoxLayout +class BoxLayout : public Layout +{ +public: + BoxLayout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb, + Qt::Orientation orientation); + + virtual void doLayout(); + virtual void sort(); + +private: + const Qt::Orientation m_orientation; +}; + +BoxLayout::BoxLayout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb, + Qt::Orientation orientation) : + Layout(wl, p, fw, lb, orientation == Qt::Horizontal ? LayoutInfo::HBox : LayoutInfo::VBox), + m_orientation(orientation) +{ +} + +void BoxLayout::sort() +{ + QWidgetList wl = widgets(); + qStableSort(wl.begin(), wl.end(), PositionSortPredicate(m_orientation)); + setWidgets(wl); +} + +void BoxLayout::doLayout() +{ + bool needMove, needReparent; + if (!prepareLayout(needMove, needReparent)) + return; + + QBoxLayout *layout = static_cast(createLayout(m_orientation == Qt::Horizontal ? LayoutInfo::HBox : LayoutInfo::VBox)); + + QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem. + + const QWidgetList::const_iterator cend = widgets().constEnd(); + for (QWidgetList::const_iterator it = widgets().constBegin(); it != cend; ++it) { + QWidget *w = *it; + if (needReparent) + reparentToLayoutBase(w); + + if (const Spacer *spacer = qobject_cast(w)) + layout->addWidget(w, 0, spacer->alignment()); + else + layout->addWidget(w); + w->show(); + } + finishLayout(needMove, layout); +} + +// -------- SplitterLayout +class SplitterLayout : public Layout +{ +public: + SplitterLayout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb, + Qt::Orientation orientation); + + virtual void doLayout(); + virtual void sort(); + +private: + const Qt::Orientation m_orientation; +}; + +SplitterLayout::SplitterLayout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb, + Qt::Orientation orientation) : + Layout(wl, p, fw, lb, orientation == Qt::Horizontal ? LayoutInfo::HSplitter : LayoutInfo::VSplitter), + m_orientation(orientation) +{ +} + +void SplitterLayout::sort() +{ + QWidgetList wl = widgets(); + qStableSort(wl.begin(), wl.end(), PositionSortPredicate(m_orientation)); + setWidgets(wl); +} + +void SplitterLayout::doLayout() +{ + bool needMove, needReparent; + if (!prepareLayout(needMove, needReparent)) + return; + + QSplitter *splitter = qobject_cast(layoutBaseWidget()); + Q_ASSERT(splitter != 0); + + + const QWidgetList::const_iterator cend = widgets().constEnd(); + for (QWidgetList::const_iterator it = widgets().constBegin(); it != cend; ++it) { + QWidget *w = *it; + if (needReparent) + reparentToLayoutBase(w); + splitter->addWidget(w); + w->show(); + } + + splitter->setOrientation(m_orientation); + finishLayout(needMove); +} + +// ---------- Grid: Helper for laying out grids + +class Grid +{ +public: + enum Mode { + GridLayout, // Arbitrary size/supports span + FormLayout // 2-column/no span + }; + + Grid(Mode mode); + void resize(int nrows, int ncols); + + ~Grid(); + + QWidget* cell(int row, int col) const { return m_cells[ row * m_ncols + col]; } + + void setCells(const QRect &c, QWidget* w); + + bool empty() const { return m_nrows * m_ncols; } + int numRows() const { return m_nrows; } + int numCols() const { return m_ncols; } + + void simplify(); + bool locateWidget(QWidget* w, int& row, int& col, int& rowspan, int& colspan) const; + + QDebug debug(QDebug str) const; + +private: + void setCell(int row, int col, QWidget* w) { m_cells[ row * m_ncols + col] = w; } + void swapCells(int r1, int c1, int r2, int c2); + void shrink(); + void reallocFormLayout(); + int countRow(int r, int c) const; + int countCol(int r, int c) const; + void setRow(int r, int c, QWidget* w, int count); + void setCol(int r, int c, QWidget* w, int count); + bool isWidgetStartCol(int c) const; + bool isWidgetEndCol(int c) const; + bool isWidgetStartRow(int r) const; + bool isWidgetEndRow(int r) const; + bool isWidgetTopLeft(int r, int c) const; + void extendLeft(); + void extendRight(); + void extendUp(); + void extendDown(); + bool shrinkFormLayoutSpans(); + + const Mode m_mode; + int m_nrows; + int m_ncols; + + QWidget** m_cells; // widget matrix w11, w12, w21... +}; + +Grid::Grid(Mode mode) : + m_mode(mode), + m_nrows(0), + m_ncols(0), + m_cells(0) +{ +} + +Grid::~Grid() +{ + delete [] m_cells; +} + +void Grid::resize(int nrows, int ncols) +{ + delete [] m_cells; + m_cells = 0; + m_nrows = nrows; + m_ncols = ncols; + if (const int allocSize = m_nrows * m_ncols) { + m_cells = new QWidget*[allocSize]; + qFill(m_cells, m_cells + allocSize, static_cast(0)); + } +} + +QDebug Grid::debug(QDebug str) const +{ + str << m_nrows << 'x' << m_ncols << '\n'; + QSet widgets; + const int cellCount = m_nrows * m_ncols; + int row, col, rowspan, colspan; + for (int c = 0; c < cellCount; c++) + if (QWidget *w = m_cells[c]) + if (!widgets.contains(w)) { + widgets.insert(w); + locateWidget(w, row, col, rowspan, colspan); + str << w << " at " << row << col << rowspan << 'x' << colspan << '\n'; + } + for (int r = 0; r < m_nrows; r++) + for (int c = 0; c < m_ncols; c++) + str << "At " << r << c << cell(r, c) << '\n'; + + return str; +} + +static inline QDebug operator<<(QDebug str, const Grid &g) { return g.debug(str); } + +void Grid::setCells(const QRect &c, QWidget* w) +{ + const int bottom = c.top() + c.height(); + const int width = c.width(); + + for (int r = c.top(); r < bottom; r++) { + QWidget **pos = m_cells + r * m_ncols + c.left(); + qFill(pos, pos + width, w); + } +} + + +void Grid::swapCells(int r1, int c1, int r2, int c2) +{ + QWidget *w1 = cell(r1, c1); + setCell(r1, c1, cell(r2, c2)); + setCell(r2, c2, w1); +} + +int Grid::countRow(int r, int c) const +{ + QWidget* w = cell(r, c); + int i = c + 1; + while (i < m_ncols && cell(r, i) == w) + i++; + return i - c; +} + +int Grid::countCol(int r, int c) const +{ + QWidget* w = cell(r, c); + int i = r + 1; + while (i < m_nrows && cell(i, c) == w) + i++; + return i - r; +} + +void Grid::setCol(int r, int c, QWidget* w, int count) +{ + for (int i = 0; i < count; i++) + setCell(r + i, c, w); +} + +void Grid::setRow(int r, int c, QWidget* w, int count) +{ + for (int i = 0; i < count; i++) + setCell(r, c + i, w); +} + +bool Grid::isWidgetStartCol(int c) const +{ + for (int r = 0; r < m_nrows; r++) { + if (cell(r, c) && ((c==0) || (cell(r, c) != cell(r, c-1)))) { + return true; + } + } + return false; +} + +bool Grid::isWidgetEndCol(int c) const +{ + for (int r = 0; r < m_nrows; r++) { + if (cell(r, c) && ((c == m_ncols-1) || (cell(r, c) != cell(r, c+1)))) + return true; + } + return false; +} + +bool Grid::isWidgetStartRow(int r) const +{ + for ( int c = 0; c < m_ncols; c++) { + if (cell(r, c) && ((r==0) || (cell(r, c) != cell(r-1, c)))) + return true; + } + return false; +} + +bool Grid::isWidgetEndRow(int r) const +{ + for (int c = 0; c < m_ncols; c++) { + if (cell(r, c) && ((r == m_nrows-1) || (cell(r, c) != cell(r+1, c)))) + return true; + } + return false; +} + + +bool Grid::isWidgetTopLeft(int r, int c) const +{ + QWidget* w = cell(r, c); + if (!w) + return false; + return (!r || cell(r-1, c) != w) && (!c || cell(r, c-1) != w); +} + +void Grid::extendLeft() +{ + for (int c = 1; c < m_ncols; c++) { + for (int r = 0; r < m_nrows; r++) { + QWidget* w = cell(r, c); + if (!w) + continue; + + const int cc = countCol(r, c); + int stretch = 0; + for (int i = c-1; i >= 0; i--) { + if (cell(r, i)) + break; + if (countCol(r, i) < cc) + break; + if (isWidgetEndCol(i)) + break; + if (isWidgetStartCol(i)) { + stretch = c - i; + break; + } + } + if (stretch) { + for (int i = 0; i < stretch; i++) + setCol(r, c-i-1, w, cc); + } + } + } +} + + +void Grid::extendRight() +{ + for (int c = m_ncols - 2; c >= 0; c--) { + for (int r = 0; r < m_nrows; r++) { + QWidget* w = cell(r, c); + if (!w) + continue; + const int cc = countCol(r, c); + int stretch = 0; + for (int i = c+1; i < m_ncols; i++) { + if (cell(r, i)) + break; + if (countCol(r, i) < cc) + break; + if (isWidgetStartCol(i)) + break; + if (isWidgetEndCol(i)) { + stretch = i - c; + break; + } + } + if (stretch) { + for (int i = 0; i < stretch; i++) + setCol(r, c+i+1, w, cc); + } + } + } + +} + +void Grid::extendUp() +{ + for (int r = 1; r < m_nrows; r++) { + for (int c = 0; c < m_ncols; c++) { + QWidget* w = cell(r, c); + if (!w) + continue; + const int cr = countRow(r, c); + int stretch = 0; + for (int i = r-1; i >= 0; i--) { + if (cell(i, c)) + break; + if (countRow(i, c) < cr) + break; + if (isWidgetEndRow(i)) + break; + if (isWidgetStartRow(i)) { + stretch = r - i; + break; + } + } + if (stretch) { + for (int i = 0; i < stretch; i++) + setRow(r-i-1, c, w, cr); + } + } + } +} + +void Grid::extendDown() +{ + for (int r = m_nrows - 2; r >= 0; r--) { + for (int c = 0; c < m_ncols; c++) { + QWidget* w = cell(r, c); + if (!w) + continue; + const int cr = countRow(r, c); + int stretch = 0; + for (int i = r+1; i < m_nrows; i++) { + if (cell(i, c)) + break; + if (countRow(i, c) < cr) + break; + if (isWidgetStartRow(i)) + break; + if (isWidgetEndRow(i)) { + stretch = i - r; + break; + } + } + if (stretch) { + for (int i = 0; i < stretch; i++) + setRow(r+i+1, c, w, cr); + } + } + } +} + +void Grid::simplify() +{ + switch (m_mode) { + case GridLayout: + // Grid: Extend all widgets to occupy most space and delete + // rows/columns that are not bordering on a widget + extendLeft(); + extendRight(); + extendUp(); + extendDown(); + shrink(); + break; + case FormLayout: + // Form: First treat it as a grid to get the same behaviour + // regarding spanning and shrinking. Then restrict the span to + // the horizontal span possible in the form, simplify again + // and spread the widgets over a 2-column layout + extendLeft(); + extendRight(); + extendUp(); + extendDown(); + shrink(); + if (shrinkFormLayoutSpans()) + shrink(); + reallocFormLayout(); + break; + } + +} + +void Grid::shrink() +{ + // tick off the occupied cols/rows (bordering on widget edges) + QVector columns(m_ncols, false); + QVector rows(m_nrows, false); + + for (int c = 0; c < m_ncols; c++) + for (int r = 0; r < m_nrows; r++) + if (isWidgetTopLeft(r, c)) + rows[r] = columns[c] = true; + + // remove empty cols/rows + const int simplifiedNCols = columns.count(true); + const int simplifiedNRows = rows.count(true); + if (simplifiedNCols == m_ncols && simplifiedNRows == m_nrows) + return; + // reallocate and copy omitting the empty cells + QWidget **simplifiedCells = new QWidget*[simplifiedNCols * simplifiedNRows]; + qFill(simplifiedCells, simplifiedCells + simplifiedNCols * simplifiedNRows, static_cast(0)); + QWidget **simplifiedPtr = simplifiedCells; + + for (int r = 0; r < m_nrows; r++) + if (rows[r]) + for (int c = 0; c < m_ncols; c++) + if (columns[c]) { + if (QWidget *w = cell(r, c)) + *simplifiedPtr = w; + simplifiedPtr++; + } + Q_ASSERT(simplifiedPtr == simplifiedCells + simplifiedNCols * simplifiedNRows); + delete [] m_cells; + m_cells = simplifiedCells; + m_nrows = simplifiedNRows; + m_ncols = simplifiedNCols; +} + +bool Grid::shrinkFormLayoutSpans() +{ + bool shrunk = false; + typedef QSet WidgetSet; + // Determine unique set of widgets + WidgetSet widgets; + QWidget **end = m_cells + m_ncols * m_nrows; + for (QWidget **wptr = m_cells; wptr < end; wptr++) + if (QWidget *w = *wptr) + widgets.insert(w); + // Restrict the widget span: max horizontal span at column 0: 2, anything else: 1 + const int maxRowSpan = 1; + const WidgetSet::const_iterator cend = widgets.constEnd(); + for (WidgetSet::const_iterator it = widgets.constBegin(); it != cend ; ++it) { + QWidget *w = *it; + int row, col, rowspan, colspan; + if (!locateWidget(w, row, col, rowspan, colspan)) + qDebug("ooops, widget '%s' does not fit in layout", w->objectName().toUtf8().constData()); + const int maxColSpan = col == 0 ? 2 : 1; + const int newColSpan = qMin(colspan, maxColSpan); + const int newRowSpan = qMin(rowspan, maxRowSpan); + if (newColSpan != colspan || newRowSpan != rowspan) { + // in case like this: + // W1 W1 + // W1 W2 + // do: + // W1 0 + // 0 W2 + for (int i = row; i < row + rowspan - 1; i++) + for (int j = col; j < col + colspan - 1; j++) + if (i > row + newColSpan - 1 || j > col + newRowSpan - 1) + if (cell(i, j) == w) + setCell(i, j, 0); + shrunk = true; + } + } + return shrunk; +} + +void Grid::reallocFormLayout() +{ + // Columns matching? -> happy! + if (m_ncols == FormLayoutColumns) + return; + + // If there are offset columns (starting past the field column), + // move them to the left and squeeze them. This also prevents the + // following reallocation from creating empty form rows. + int pastRightWidgetCount = 0; + if (m_ncols > FormLayoutColumns) { + for (int r = 0; r < m_nrows; r++) { + // Try to find a column where the form columns are empty and + // there are widgets further to the right. + if (cell(r, 0) == 0 && cell(r, 1) == 0) { + int sourceCol = FormLayoutColumns; + QWidget *firstWidget = 0; + for ( ; sourceCol < m_ncols; sourceCol++) + if (QWidget *w = cell(r, sourceCol)) { + firstWidget = w; + break; + } + if (firstWidget) { + // Move/squeeze. Copy to beginning of column if it is a label, else field + int targetCol = qobject_cast(firstWidget) ? 0 : 1; + for ( ; sourceCol < m_ncols; sourceCol++) + if (QWidget *w = cell(r, sourceCol)) + setCell(r, targetCol++, w); + // Pad with zero + for ( ; targetCol < m_ncols; targetCol++) + setCell(r, targetCol, 0); + } + } + // Any protruding widgets left on that row? + for (int c = FormLayoutColumns; c < m_ncols; c++) + if (cell(r, c)) + pastRightWidgetCount++; + } + } + // Reallocate with 2 columns. Just insert the protruding ones as fields. + const int formNRows = m_nrows + pastRightWidgetCount; + QWidget **formCells = new QWidget*[FormLayoutColumns * formNRows]; + qFill(formCells, formCells + FormLayoutColumns * formNRows, static_cast(0)); + QWidget **formPtr = formCells; + const int matchingColumns = qMin(m_ncols, static_cast(FormLayoutColumns)); + for (int r = 0; r < m_nrows; r++) { + int c = 0; + for ( ; c < matchingColumns; c++) // Just copy over matching columns + *formPtr++ = cell(r, c); + formPtr += FormLayoutColumns - matchingColumns; // In case old format was 1 column + // protruding widgets: Insert as single-field rows + for ( ; c < m_ncols; c++) + if (QWidget *w = cell(r, c)) { + formPtr++; + *formPtr++ = w; + } + } + Q_ASSERT(formPtr == formCells + FormLayoutColumns * formNRows); + delete [] m_cells; + m_cells = formCells; + m_nrows = formNRows; + m_ncols = FormLayoutColumns; +} + +bool Grid::locateWidget(QWidget *w, int &row, int &col, int &rowspan, int &colspan) const +{ + const int end = m_nrows * m_ncols; + const int startIndex = qFind(m_cells, m_cells + end, w) - m_cells; + if (startIndex == end) + return false; + + row = startIndex / m_ncols; + col = startIndex % m_ncols; + for (rowspan = 1; row + rowspan < m_nrows && cell(row + rowspan, col) == w; rowspan++) {} + for (colspan = 1; col + colspan < m_ncols && cell(row, col + colspan) == w; colspan++) {} + return true; +} + +// QGridLayout/QFormLayout Helpers: get item position/add item (overloads to make templates work) + +void getGridItemPosition(QGridLayout *gridLayout, int index, int *row, int *column, int *rowspan, int *colspan) +{ + gridLayout->getItemPosition(index, row, column, rowspan, colspan); +} + +void addWidgetToGrid(QGridLayout *lt, QWidget * widget, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment) +{ + lt->addWidget(widget, row, column, rowSpan, columnSpan, alignment); +} + +inline void getGridItemPosition(QFormLayout *formLayout, int index, int *row, int *column, int *rowspan, int *colspan) +{ + getFormLayoutItemPosition(formLayout, index, row, column, rowspan, colspan); +} + +inline void addWidgetToGrid(QFormLayout *lt, QWidget * widget, int row, int column, int, int columnSpan, Qt::Alignment) +{ + formLayoutAddWidget(lt, widget, QRect(column, row, columnSpan, 1), false); +} + +// ----------- Base template for grid like layouts +template +class GridLayout : public Layout +{ +public: + GridLayout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb); + + virtual void doLayout(); + virtual void sort() { setWidgets(buildGrid(widgets())); } + +protected: + QWidget *widgetAt(GridLikeLayout *layout, int row, int column) const; + +protected: + QWidgetList buildGrid(const QWidgetList &); + Grid m_grid; +}; + +template +GridLayout::GridLayout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb) : + Layout(wl, p, fw, lb, LayoutInfo::Grid), + m_grid(static_cast(GridMode)) +{ +} + +template +QWidget *GridLayout::widgetAt(GridLikeLayout *layout, int row, int column) const +{ + int index = 0; + while (QLayoutItem *item = layout->itemAt(index)) { + if (item->widget()) { + int r, c, rowspan, colspan; + getGridItemPosition(layout, index, &r, &c, &rowspan, &colspan); + if (row == r && column == c) + return item->widget(); + } + ++index; + } + return 0; +} + +template +void GridLayout::doLayout() +{ + bool needMove, needReparent; + if (!prepareLayout(needMove, needReparent)) + return; + + GridLikeLayout *layout = static_cast(createLayout(LayoutType)); + + if (m_grid.empty()) + sort(); + + QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem. + + const QWidgetList::const_iterator cend = widgets().constEnd(); + for (QWidgetList::const_iterator it = widgets().constBegin(); it != cend; ++it) { + QWidget *w = *it; + int r = 0, c = 0, rs = 0, cs = 0; + + if (m_grid.locateWidget(w, r, c, rs, cs)) { + if (needReparent) + reparentToLayoutBase(w); + + Qt::Alignment alignment = Qt::Alignment(0); + if (const Spacer *spacer = qobject_cast(w)) + alignment = spacer->alignment(); + + addWidgetToGrid(layout, w, r, c, rs, cs, alignment); + + w->show(); + } else { + qDebug("ooops, widget '%s' does not fit in layout", w->objectName().toUtf8().constData()); + } + } + + QLayoutSupport::createEmptyCells(layout); + + finishLayout(needMove, layout); +} + +// Remove duplicate entries (Remove next, if equal to current) +void removeIntVecDuplicates(QVector &v) +{ + if (v.size() < 2) + return; + + for (QVector::iterator current = v.begin() ; (current != v.end()) && ((current+1) != v.end()) ; ) + if ( (*current == *(current+1)) ) + v.erase(current+1); + else + ++current; +} + +// Ensure a non-zero size for a widget geometry (squeezed spacers) +inline QRect expandGeometry(const QRect &rect) +{ + return rect.isEmpty() ? QRect(rect.topLeft(), rect.size().expandedTo(QSize(1, 1))) : rect; +} + +template +QWidgetList GridLayout::buildGrid(const QWidgetList &widgetList) +{ + if (widgetList.empty()) + return QWidgetList(); + + // Pixel to cell conversion: + // By keeping a list of start'n'stop values (x & y) for each widget, + // it is possible to create a very small grid of cells to represent + // the widget layout. + // ----------------------------------------------------------------- + + // We need a list of both start and stop values for x- & y-axis + const int widgetCount = widgetList.size(); + QVector x( widgetCount * 2 ); + QVector y( widgetCount * 2 ); + + // Using push_back would look nicer, but operator[] is much faster + int index = 0; + for (int i = 0; i < widgetCount; ++i) { + const QRect widgetPos = expandGeometry(widgetList.at(i)->geometry()); + x[index] = widgetPos.left(); + x[index+1] = widgetPos.right(); + y[index] = widgetPos.top(); + y[index+1] = widgetPos.bottom(); + index += 2; + } + + qSort(x); + qSort(y); + + // Remove duplicate x entries (Remove next, if equal to current) + removeIntVecDuplicates(x); + removeIntVecDuplicates(y); + + // Note that left == right and top == bottom for size 1 items; reserve + // enough space + m_grid.resize(y.size(), x.size()); + + const QWidgetList::const_iterator cend = widgetList.constEnd(); + for (QWidgetList::const_iterator it = widgetList.constBegin(); it != cend; ++it) { + QWidget *w = *it; + // Mark the cells in the grid that contains a widget + const QRect widgetPos = expandGeometry(w->geometry()); + QRect c(0, 0, 0, 0); // rect of columns/rows + + // From left til right (not including) + const int leftIdx = x.indexOf(widgetPos.left()); + Q_ASSERT(leftIdx != -1); + c.setLeft(leftIdx); + c.setRight(leftIdx); + for (int cw=leftIdx; cw(widgets, parentWidget, fw, layoutBase); + case LayoutInfo::HBox: + case LayoutInfo::VBox: { + const Qt::Orientation orientation = layoutType == LayoutInfo::HBox ? Qt::Horizontal : Qt::Vertical; + return new BoxLayout(widgets, parentWidget, fw, layoutBase, orientation); + } + case LayoutInfo::HSplitter: + case LayoutInfo::VSplitter: { + const Qt::Orientation orientation = layoutType == LayoutInfo::HSplitter ? Qt::Horizontal : Qt::Vertical; + return new SplitterLayout(widgets, parentWidget, fw, layoutBase, orientation); + } + case LayoutInfo::Form: + return new GridLayout(widgets, parentWidget, fw, layoutBase); + default: + break; + } + Q_ASSERT(0); + return 0; +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/layout_p.h b/src/designer/src/lib/shared/layout_p.h new file mode 100644 index 000000000..f901b63b9 --- /dev/null +++ b/src/designer/src/lib/shared/layout_p.h @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef LAYOUT_H +#define LAYOUT_H + +#include "shared_global_p.h" +#include "layoutinfo_p.h" + +#include +#include +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { +class QDESIGNER_SHARED_EXPORT Layout : public QObject +{ + Q_OBJECT + Q_DISABLE_COPY(Layout) +protected: + Layout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb, LayoutInfo::Type layoutType); + +public: + static Layout* createLayout(const QWidgetList &widgets, QWidget *parentWidget, + QDesignerFormWindowInterface *fw, + QWidget *layoutBase, LayoutInfo::Type layoutType); + + virtual ~Layout(); + + virtual void sort() = 0; + virtual void doLayout() = 0; + + virtual void setup(); + virtual void undoLayout(); + virtual void breakLayout(); + + const QWidgetList &widgets() const { return m_widgets; } + QWidget *parentWidget() const { return m_parentWidget; } + QWidget *layoutBaseWidget() const { return m_layoutBase; } + + /* Determines whether instances of QLayoutWidget are unmanaged/hidden + * after breaking a layout. Default is true. Can be turned off when + * morphing */ + bool reparentLayoutWidget() const { return m_reparentLayoutWidget; } + void setReparentLayoutWidget(bool v) { m_reparentLayoutWidget = v; } + +protected: + virtual void finishLayout(bool needMove, QLayout *layout = 0); + virtual bool prepareLayout(bool &needMove, bool &needReparent); + + void setWidgets(const QWidgetList &widgets) { m_widgets = widgets; } + QLayout *createLayout(int type); + void reparentToLayoutBase(QWidget *w); + +private slots: + void widgetDestroyed(); + +private: + QWidgetList m_widgets; + QWidget *m_parentWidget; + typedef QHash WidgetGeometryHash; + WidgetGeometryHash m_geometries; + QWidget *m_layoutBase; + QDesignerFormWindowInterface *m_formWindow; + const LayoutInfo::Type m_layoutType; + QPoint m_startPoint; + QRect m_oldGeometry; + + bool m_reparentLayoutWidget; + const bool m_isBreak; +}; + +namespace Utils +{ + +inline int indexOfWidget(QLayout *layout, QWidget *widget) +{ + int index = 0; + while (QLayoutItem *item = layout->itemAt(index)) { + if (item->widget() == widget) + return index; + + ++index; + } + + return -1; +} + +} // namespace Utils + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // LAYOUT_H diff --git a/src/designer/src/lib/shared/layoutinfo.cpp b/src/designer/src/lib/shared/layoutinfo.cpp new file mode 100644 index 000000000..804d069c5 --- /dev/null +++ b/src/designer/src/lib/shared/layoutinfo.cpp @@ -0,0 +1,312 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "layoutinfo_p.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { +/*! + \overload +*/ +LayoutInfo::Type LayoutInfo::layoutType(const QDesignerFormEditorInterface *core, const QLayout *layout) +{ + Q_UNUSED(core) + if (!layout) + return NoLayout; + else if (qobject_cast(layout)) + return HBox; + else if (qobject_cast(layout)) + return VBox; + else if (qobject_cast(layout)) + return Grid; + else if (qobject_cast(layout)) + return Form; + return UnknownLayout; +} + +static const QHash &layoutNameTypeMap() +{ + static QHash nameTypeMap; + if (nameTypeMap.empty()) { + nameTypeMap.insert(QLatin1String("QVBoxLayout"), LayoutInfo::VBox); + nameTypeMap.insert(QLatin1String("QHBoxLayout"), LayoutInfo::HBox); + nameTypeMap.insert(QLatin1String("QGridLayout"), LayoutInfo::Grid); + nameTypeMap.insert(QLatin1String("QFormLayout"), LayoutInfo::Form); + } + return nameTypeMap; +} + +LayoutInfo::Type LayoutInfo::layoutType(const QString &typeName) +{ + return layoutNameTypeMap().value(typeName, NoLayout); +} + +QString LayoutInfo::layoutName(Type t) +{ + return layoutNameTypeMap().key(t); +} + +/*! + \overload +*/ +LayoutInfo::Type LayoutInfo::layoutType(const QDesignerFormEditorInterface *core, const QWidget *w) +{ + if (const QSplitter *splitter = qobject_cast(w)) + return splitter->orientation() == Qt::Horizontal ? HSplitter : VSplitter; + return layoutType(core, w->layout()); +} + +LayoutInfo::Type LayoutInfo::managedLayoutType(const QDesignerFormEditorInterface *core, + const QWidget *w, + QLayout **ptrToLayout) +{ + if (ptrToLayout) + *ptrToLayout = 0; + if (const QSplitter *splitter = qobject_cast(w)) + return splitter->orientation() == Qt::Horizontal ? HSplitter : VSplitter; + QLayout *layout = managedLayout(core, w); + if (!layout) + return NoLayout; + if (ptrToLayout) + *ptrToLayout = layout; + return layoutType(core, layout); +} + +QWidget *LayoutInfo::layoutParent(const QDesignerFormEditorInterface *core, QLayout *layout) +{ + Q_UNUSED(core) + + QObject *o = layout; + while (o) { + if (QWidget *widget = qobject_cast(o)) + return widget; + + o = o->parent(); + } + return 0; +} + +void LayoutInfo::deleteLayout(const QDesignerFormEditorInterface *core, QWidget *widget) +{ + if (QDesignerContainerExtension *container = qt_extension(core->extensionManager(), widget)) + widget = container->widget(container->currentIndex()); + + Q_ASSERT(widget != 0); + + QLayout *layout = managedLayout(core, widget); + + if (layout == 0 || core->metaDataBase()->item(layout) != 0) { + delete layout; + widget->updateGeometry(); + return; + } + + qDebug() << "trying to delete an unmanaged layout:" << "widget:" << widget << "layout:" << layout; +} + +LayoutInfo::Type LayoutInfo::laidoutWidgetType(const QDesignerFormEditorInterface *core, + QWidget *widget, + bool *isManaged, + QLayout **ptrToLayout) +{ + if (isManaged) + *isManaged = false; + if (ptrToLayout) + *ptrToLayout = 0; + + QWidget *parent = widget->parentWidget(); + if (!parent) + return NoLayout; + + // 1) Splitter + if (QSplitter *splitter = qobject_cast(parent)) { + if (isManaged) + *isManaged = core->metaDataBase()->item(splitter); + return splitter->orientation() == Qt::Horizontal ? HSplitter : VSplitter; + } + + // 2) Layout of parent + QLayout *parentLayout = parent->layout(); + if (!parentLayout) + return NoLayout; + + if (parentLayout->indexOf(widget) != -1) { + if (isManaged) + *isManaged = core->metaDataBase()->item(parentLayout); + if (ptrToLayout) + *ptrToLayout = parentLayout; + return layoutType(core, parentLayout); + } + + // 3) Some child layout (see below comment about Q3GroupBox) + const QList childLayouts = parentLayout->findChildren(); + if (childLayouts.empty()) + return NoLayout; + const QList::const_iterator lcend = childLayouts.constEnd(); + for (QList::const_iterator it = childLayouts.constBegin(); it != lcend; ++it) { + QLayout *layout = *it; + if (layout->indexOf(widget) != -1) { + if (isManaged) + *isManaged = core->metaDataBase()->item(layout); + if (ptrToLayout) + *ptrToLayout = layout; + return layoutType(core, layout); + } + } + + return NoLayout; +} + +QLayout *LayoutInfo::internalLayout(const QWidget *widget) +{ + QLayout *widgetLayout = widget->layout(); + if (widgetLayout && widget->inherits("Q3GroupBox")) { + if (widgetLayout->count()) { + widgetLayout = widgetLayout->itemAt(0)->layout(); + } else { + widgetLayout = 0; + } + } + return widgetLayout; +} + + +QLayout *LayoutInfo::managedLayout(const QDesignerFormEditorInterface *core, const QWidget *widget) +{ + if (widget == 0) + return 0; + + QLayout *layout = widget->layout(); + if (!layout) + return 0; + + return managedLayout(core, layout); +} + +QLayout *LayoutInfo::managedLayout(const QDesignerFormEditorInterface *core, QLayout *layout) +{ + QDesignerMetaDataBaseInterface *metaDataBase = core->metaDataBase(); + + if (!metaDataBase) + return layout; + /* This code exists mainly for the Q3GroupBox class, for which + * widget->layout() returns an internal VBoxLayout. */ + const QDesignerMetaDataBaseItemInterface *item = metaDataBase->item(layout); + if (item == 0) { + layout = layout->findChild(); + item = metaDataBase->item(layout); + } + if (!item) + return 0; + return layout; +} + +// Is it a a dummy grid placeholder created by Designer? +bool LayoutInfo::isEmptyItem(QLayoutItem *item) +{ + if (item == 0) { + qDebug() << "** WARNING Zero-item passed on to isEmptyItem(). This indicates a layout inconsistency."; + return true; + } + return item->spacerItem() != 0; +} + +QDESIGNER_SHARED_EXPORT void getFormLayoutItemPosition(const QFormLayout *formLayout, int index, int *rowPtr, int *columnPtr, int *rowspanPtr, int *colspanPtr) +{ + int row; + QFormLayout::ItemRole role; + formLayout->getItemPosition(index, &row, &role); + const int columnspan = role == QFormLayout::SpanningRole ? 2 : 1; + const int column = (columnspan > 1 || role == QFormLayout::LabelRole) ? 0 : 1; + if (rowPtr) + *rowPtr = row; + if (columnPtr) + *columnPtr = column; + if (rowspanPtr) + *rowspanPtr = 1; + if (colspanPtr) + *colspanPtr = columnspan; +} + +static inline QFormLayout::ItemRole formLayoutRole(int column, int colspan) +{ + if (colspan > 1) + return QFormLayout::SpanningRole; + return column == 0 ? QFormLayout::LabelRole : QFormLayout::FieldRole; +} + +QDESIGNER_SHARED_EXPORT void formLayoutAddWidget(QFormLayout *formLayout, QWidget *w, const QRect &r, bool insert) +{ + // Consistent API galore... + if (insert) { + const bool spanning = r.width() > 1; + if (spanning) { + formLayout->insertRow(r.y(), w); + } else { + QWidget *label = 0, *field = 0; + if (r.x() == 0) { + label = w; + } else { + field = w; + } + formLayout->insertRow(r.y(), label, field); + } + } else { + formLayout->setWidget(r.y(), formLayoutRole(r.x(), r.width()), w); + } +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/layoutinfo_p.h b/src/designer/src/lib/shared/layoutinfo_p.h new file mode 100644 index 000000000..dadfa6ff3 --- /dev/null +++ b/src/designer/src/lib/shared/layoutinfo_p.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef LAYOUTINFO_H +#define LAYOUTINFO_H + +#include "shared_global_p.h" + +QT_BEGIN_NAMESPACE + +class QWidget; +class QLayout; +class QLayoutItem; +class QDesignerFormEditorInterface; +class QFormLayout; +class QRect; +class QString; + +namespace qdesigner_internal { + +class QDESIGNER_SHARED_EXPORT LayoutInfo +{ +public: + enum Type + { + NoLayout, + HSplitter, + VSplitter, + HBox, + VBox, + Grid, + Form, + UnknownLayout // QDockWindow inside QMainWindow is inside QMainWindowLayout - it doesn't mean there is no layout + }; + + static void deleteLayout(const QDesignerFormEditorInterface *core, QWidget *widget); + + // Examines the immediate layout of the widget (will fail for Q3Group Box). + static Type layoutType(const QDesignerFormEditorInterface *core, const QWidget *w); + // Examines the managed layout of the widget + static Type managedLayoutType(const QDesignerFormEditorInterface *core, const QWidget *w, QLayout **layout = 0); + static Type layoutType(const QDesignerFormEditorInterface *core, const QLayout *layout); + static Type layoutType(const QString &typeName); + static QString layoutName(Type t); + + static QWidget *layoutParent(const QDesignerFormEditorInterface *core, QLayout *layout); + + static Type laidoutWidgetType(const QDesignerFormEditorInterface *core, QWidget *widget, bool *isManaged = 0, QLayout **layout = 0); + static bool inline isWidgetLaidout(const QDesignerFormEditorInterface *core, QWidget *widget) { return laidoutWidgetType(core, widget) != NoLayout; } + + static QLayout *managedLayout(const QDesignerFormEditorInterface *core, const QWidget *widget); + static QLayout *managedLayout(const QDesignerFormEditorInterface *core, QLayout *layout); + static QLayout *internalLayout(const QWidget *widget); + + // Is it a a dummy grid placeholder created by Designer? + static bool isEmptyItem(QLayoutItem *item); +}; + +QDESIGNER_SHARED_EXPORT void getFormLayoutItemPosition(const QFormLayout *formLayout, int index, int *rowPtr, int *columnPtr = 0, int *rowspanPtr = 0, int *colspanPtr = 0); +QDESIGNER_SHARED_EXPORT void formLayoutAddWidget(QFormLayout *formLayout, QWidget *w, const QRect &r, bool insert); +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // LAYOUTINFO_H diff --git a/src/designer/src/lib/shared/metadatabase.cpp b/src/designer/src/lib/shared/metadatabase.cpp new file mode 100644 index 000000000..3cde7da13 --- /dev/null +++ b/src/designer/src/lib/shared/metadatabase.cpp @@ -0,0 +1,295 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "metadatabase_p.h" +#include "widgetdatabase_p.h" + +// sdk +#include + +// Qt +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace { + const bool debugMetaDatabase = false; +} + +namespace qdesigner_internal { + +MetaDataBaseItem::MetaDataBaseItem(QObject *object) + : m_object(object), + m_enabled(true) +{ +} + +MetaDataBaseItem::~MetaDataBaseItem() +{ +} + +QString MetaDataBaseItem::name() const +{ + Q_ASSERT(m_object); + return m_object->objectName(); +} + +void MetaDataBaseItem::setName(const QString &name) +{ + Q_ASSERT(m_object); + m_object->setObjectName(name); +} + +QString MetaDataBaseItem::customClassName() const +{ + return m_customClassName; +} +void MetaDataBaseItem::setCustomClassName(const QString &customClassName) +{ + m_customClassName = customClassName; +} + + +MetaDataBaseItem::TabOrder MetaDataBaseItem::tabOrder() const +{ + return m_tabOrder; +} + +void MetaDataBaseItem::setTabOrder(const TabOrder &tabOrder) +{ + m_tabOrder = tabOrder; +} + +bool MetaDataBaseItem::enabled() const +{ + return m_enabled; +} + +void MetaDataBaseItem::setEnabled(bool b) +{ + m_enabled = b; +} + +QString MetaDataBaseItem::script() const +{ + return m_script; +} + +void MetaDataBaseItem::setScript(const QString &script) +{ + m_script = script; +} + +QStringList MetaDataBaseItem::fakeSlots() const +{ + return m_fakeSlots; +} + +void MetaDataBaseItem::setFakeSlots(const QStringList &fs) +{ + m_fakeSlots = fs; +} + +QStringList MetaDataBaseItem::fakeSignals() const +{ + return m_fakeSignals; +} + +void MetaDataBaseItem::setFakeSignals(const QStringList &fs) +{ + m_fakeSignals = fs; +} + +// ----------------------------------------------------- +MetaDataBase::MetaDataBase(QDesignerFormEditorInterface *core, QObject *parent) + : QDesignerMetaDataBaseInterface(parent), + m_core(core) +{ +} + +MetaDataBase::~MetaDataBase() +{ + qDeleteAll(m_items); +} + +MetaDataBaseItem *MetaDataBase::metaDataBaseItem(QObject *object) const +{ + MetaDataBaseItem *i = m_items.value(object); + if (i == 0 || !i->enabled()) + return 0; + return i; +} + +void MetaDataBase::add(QObject *object) +{ + MetaDataBaseItem *item = m_items.value(object); + if (item != 0) { + item->setEnabled(true); + if (debugMetaDatabase) { + qDebug() << "MetaDataBase::add: Existing item for " << object->metaObject()->className() << item->name(); + } + return; + } + + item = new MetaDataBaseItem(object); + m_items.insert(object, item); + if (debugMetaDatabase) { + qDebug() << "MetaDataBase::add: New item " << object->metaObject()->className() << item->name(); + } + connect(object, SIGNAL(destroyed(QObject*)), + this, SLOT(slotDestroyed(QObject*))); + + emit changed(); +} + +void MetaDataBase::remove(QObject *object) +{ + Q_ASSERT(object); + + if (MetaDataBaseItem *item = m_items.value(object)) { + item->setEnabled(false); + emit changed(); + } +} + +QList MetaDataBase::objects() const +{ + QList result; + + ItemMap::const_iterator it = m_items.begin(); + for (; it != m_items.end(); ++it) { + if (it.value()->enabled()) + result.append(it.key()); + } + + return result; +} + +QDesignerFormEditorInterface *MetaDataBase::core() const +{ + return m_core; +} + +void MetaDataBase::slotDestroyed(QObject *object) +{ + if (m_items.contains(object)) { + MetaDataBaseItem *item = m_items.value(object); + delete item; + m_items.remove(object); + } +} + +// promotion convenience +QDESIGNER_SHARED_EXPORT bool promoteWidget(QDesignerFormEditorInterface *core,QWidget *widget,const QString &customClassName) +{ + + MetaDataBase *db = qobject_cast(core->metaDataBase()); + if (!db) + return false; + MetaDataBaseItem *item = db->metaDataBaseItem(widget); + if (!item) { + db ->add(widget); + item = db->metaDataBaseItem(widget); + } + // Recursive promotion occurs if there is a plugin missing. + const QString oldCustomClassName = item->customClassName(); + if (!oldCustomClassName.isEmpty()) { + qDebug() << "WARNING: Recursive promotion of " << oldCustomClassName << " to " << customClassName + << ". A plugin is missing."; + } + item->setCustomClassName(customClassName); + if (debugMetaDatabase) { + qDebug() << "Promoting " << widget->metaObject()->className() << " to " << customClassName; + } + return true; +} + +QDESIGNER_SHARED_EXPORT void demoteWidget(QDesignerFormEditorInterface *core,QWidget *widget) +{ + MetaDataBase *db = qobject_cast(core->metaDataBase()); + if (!db) + return; + MetaDataBaseItem *item = db->metaDataBaseItem(widget); + item->setCustomClassName(QString()); + if (debugMetaDatabase) { + qDebug() << "Demoting " << widget; + } +} + +QDESIGNER_SHARED_EXPORT bool isPromoted(QDesignerFormEditorInterface *core, QWidget* widget) +{ + const MetaDataBase *db = qobject_cast(core->metaDataBase()); + if (!db) + return false; + const MetaDataBaseItem *item = db->metaDataBaseItem(widget); + if (!item) + return false; + return !item->customClassName().isEmpty(); +} + +QDESIGNER_SHARED_EXPORT QString promotedCustomClassName(QDesignerFormEditorInterface *core, QWidget* widget) +{ + const MetaDataBase *db = qobject_cast(core->metaDataBase()); + if (!db) + return QString(); + const MetaDataBaseItem *item = db->metaDataBaseItem(widget); + if (!item) + return QString(); + return item->customClassName(); +} + +QDESIGNER_SHARED_EXPORT QString promotedExtends(QDesignerFormEditorInterface *core, QWidget* widget) +{ + const QString customClassName = promotedCustomClassName(core,widget); + if (customClassName.isEmpty()) + return QString(); + const int i = core->widgetDataBase()->indexOfClassName(customClassName); + if (i == -1) + return QString(); + return core->widgetDataBase()->item(i)->extends(); +} + + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/metadatabase_p.h b/src/designer/src/lib/shared/metadatabase_p.h new file mode 100644 index 000000000..5675217cc --- /dev/null +++ b/src/designer/src/lib/shared/metadatabase_p.h @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef METADATABASE_H +#define METADATABASE_H + +#include "shared_global_p.h" + +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QDESIGNER_SHARED_EXPORT MetaDataBaseItem: public QDesignerMetaDataBaseItemInterface +{ +public: + explicit MetaDataBaseItem(QObject *object); + virtual ~MetaDataBaseItem(); + + virtual QString name() const; + virtual void setName(const QString &name); + + typedef QList TabOrder; + virtual TabOrder tabOrder() const; + virtual void setTabOrder(const TabOrder &tabOrder); + + virtual bool enabled() const; + virtual void setEnabled(bool b); + + QString customClassName() const; + void setCustomClassName(const QString &customClassName); + + QString script() const; + void setScript(const QString &script); + + QStringList fakeSlots() const; + void setFakeSlots(const QStringList &); + + QStringList fakeSignals() const; + void setFakeSignals(const QStringList &); + +private: + QObject *m_object; + TabOrder m_tabOrder; + bool m_enabled; + QString m_customClassName; + QString m_script; + QStringList m_fakeSlots; + QStringList m_fakeSignals; +}; + +class QDESIGNER_SHARED_EXPORT MetaDataBase: public QDesignerMetaDataBaseInterface +{ + Q_OBJECT +public: + explicit MetaDataBase(QDesignerFormEditorInterface *core, QObject *parent = 0); + virtual ~MetaDataBase(); + + virtual QDesignerFormEditorInterface *core() const; + + virtual QDesignerMetaDataBaseItemInterface *item(QObject *object) const { return metaDataBaseItem(object); } + virtual MetaDataBaseItem *metaDataBaseItem(QObject *object) const; + virtual void add(QObject *object); + virtual void remove(QObject *object); + + virtual QList objects() const; + +private slots: + void slotDestroyed(QObject *object); + +private: + QDesignerFormEditorInterface *m_core; + typedef QHash ItemMap; + ItemMap m_items; +}; + + // promotion convenience + QDESIGNER_SHARED_EXPORT bool promoteWidget(QDesignerFormEditorInterface *core,QWidget *widget,const QString &customClassName); + QDESIGNER_SHARED_EXPORT void demoteWidget(QDesignerFormEditorInterface *core,QWidget *widget); + QDESIGNER_SHARED_EXPORT bool isPromoted(QDesignerFormEditorInterface *core, QWidget* w); + QDESIGNER_SHARED_EXPORT QString promotedCustomClassName(QDesignerFormEditorInterface *core, QWidget* w); + QDESIGNER_SHARED_EXPORT QString promotedExtends(QDesignerFormEditorInterface *core, QWidget* w); + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // METADATABASE_H diff --git a/src/designer/src/lib/shared/morphmenu.cpp b/src/designer/src/lib/shared/morphmenu.cpp new file mode 100644 index 000000000..67121e597 --- /dev/null +++ b/src/designer/src/lib/shared/morphmenu.cpp @@ -0,0 +1,635 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "morphmenu_p.h" +#include "formwindowbase_p.h" +#include "widgetfactory_p.h" +#include "qdesigner_formwindowcommand_p.h" +#include "qlayout_widget_p.h" +#include "layoutinfo_p.h" +#include "qdesigner_propertycommand_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +Q_DECLARE_METATYPE(QWidgetList) + +QT_BEGIN_NAMESPACE + +// Helpers for the dynamic properties that store Z/Widget order +static const char *widgetOrderPropertyC = "_q_widgetOrder"; +static const char *zOrderPropertyC = "_q_zOrder"; + +/* Morphing in Designer: + * It is possible to morph: + * - Non-Containers into similar widgets by category + * - Simple page containers into similar widgets or page-based containers with + * a single page (in theory also into a QLayoutWidget, but this might + * not always be appropriate). + * - Page-based containers into page-based containers or simple containers if + * they have just one page + * [Page based containers meaning here having a container extension] + * Morphing types are restricted to the basic Qt types. Morphing custom + * widgets is considered risky since they might have unmanaged layouts + * or the like. + * + * Requirements: + * - The widget must be on a non-laid out parent or in a layout managed + * by Designer + * - Its child widgets must be non-laid out or in a layout managed + * by Designer + * Note that child widgets can be + * - On the widget itself in the case of simple containers + * - On several pages in the case of page-based containers + * This is what is called 'childContainers' in the code (the widget itself + * or the list of container extension pages). + * + * The Morphing process encompasses: + * - Create a target widget and apply properties as far as applicable + * If the target widget has a container extension, add a sufficient + * number of pages. + * - Transferring the child widgets over to the new childContainers. + * In the case of a managed layout on a childContainer, this is simply + * set on the target childContainer, which is a new Qt 4.5 + * functionality. + * - Replace the widget itself in the parent layout + */ + +namespace qdesigner_internal { + +enum MorphCategory { + MorphCategoryNone, MorphSimpleContainer, MorphPageContainer, MorphItemView, + MorphButton, MorphSpinBox, MorphTextEdit +}; + +// Determine category of a widget +static MorphCategory category(const QWidget *w) +{ + // Simple containers: Exact match + const QMetaObject *mo = w->metaObject(); + if (mo == &QWidget::staticMetaObject || mo == &QFrame::staticMetaObject || mo == &QGroupBox::staticMetaObject || mo == &QLayoutWidget::staticMetaObject) + return MorphSimpleContainer; + if (mo == &QTabWidget::staticMetaObject || mo == &QStackedWidget::staticMetaObject || mo == &QToolBox::staticMetaObject) + return MorphPageContainer; + if (qobject_cast(w)) + return MorphItemView; + if (qobject_cast(w)) + return MorphButton; + if (qobject_cast(w)) + return MorphSpinBox; + if (qobject_cast(w) || qobject_cast(w)) + return MorphTextEdit; + + return MorphCategoryNone; +} + +/* Return the similar classes of a category. This is currently restricted + * to the known Qt classes with no precautions to parse the Widget Database + * (which is too risky, custom classes might have container extensions + * or non-managed layouts, etc.). */ + +static QStringList classesOfCategory(MorphCategory cat) +{ + typedef QMap CandidateCache; + static CandidateCache candidateCache; + CandidateCache::iterator it = candidateCache.find(cat); + if (it == candidateCache.end()) { + it = candidateCache.insert(cat, QStringList()); + QStringList &l = it.value(); + switch (cat) { + case MorphCategoryNone: + break; + case MorphSimpleContainer: + // Do not generally allow to morph into a layout. + // This can be risky in case of container pages,etc. + l << QLatin1String("QWidget") << QLatin1String("QFrame") << QLatin1String("QGroupBox"); + break; + case MorphPageContainer: + l << QLatin1String("QTabWidget") << QLatin1String("QStackedWidget") << QLatin1String("QToolBox"); + break; + case MorphItemView: + l << QLatin1String("QListView") << QLatin1String("QListWidget") + << QLatin1String("QTreeView") << QLatin1String("QTreeWidget") + << QLatin1String("QTableView") << QLatin1String("QTableWidget") + << QLatin1String("QColumnView"); + break; + case MorphButton: + l << QLatin1String("QCheckBox") << QLatin1String("QRadioButton") + << QLatin1String("QPushButton") << QLatin1String("QToolButton") + << QLatin1String("QCommandLinkButton"); + break; + case MorphSpinBox: + l << QLatin1String("QDateTimeEdit") << QLatin1String("QDateEdit") + << QLatin1String("QTimeEdit") + << QLatin1String("QSpinBox") << QLatin1String("QDoubleSpinBox"); + break; + case MorphTextEdit: + l << QLatin1String("QTextEdit") << QLatin1String("QPlainTextEdit") << QLatin1String("QTextBrowser"); + break; + } + } + return it.value(); +} + +// Return the widgets containing the children to be transferred to. This is the +// widget itself in most cases, except for QDesignerContainerExtension cases +static QWidgetList childContainers(const QDesignerFormEditorInterface *core, QWidget *w) +{ + if (const QDesignerContainerExtension *ce = qt_extension(core->extensionManager(), w)) { + QWidgetList children; + if (const int count = ce->count()) { + for (int i = 0; i < count; i++) + children.push_back(ce->widget(i)); + } + return children; + } + QWidgetList self; + self.push_back(w); + return self; +} + +// Suggest a suitable objectname for the widget to be morphed into +// Replace the class name parts: 'xxFrame' -> 'xxGroupBox', 'frame' -> 'groupBox' +static QString suggestObjectName(const QString &oldClassName, const QString &newClassName, const QString &oldName) +{ + QString oldClassPart = oldClassName; + QString newClassPart = newClassName; + if (oldClassPart.startsWith(QLatin1Char('Q'))) + oldClassPart.remove(0, 1); + if (newClassPart.startsWith(QLatin1Char('Q'))) + newClassPart.remove(0, 1); + + QString newName = oldName; + newName.replace(oldClassPart, newClassPart); + oldClassPart[0] = oldClassPart.at(0).toLower(); + newClassPart[0] = newClassPart.at(0).toLower(); + newName.replace(oldClassPart, newClassPart); + return newName; +} + +// Find the label whose buddy the widget is. +QLabel *buddyLabelOf(QDesignerFormWindowInterface *fw, QWidget *w) +{ + typedef QList LabelList; + const LabelList labelList = fw->findChildren(); + if (labelList.empty()) + return 0; + const LabelList::const_iterator cend = labelList.constEnd(); + for (LabelList::const_iterator it = labelList.constBegin(); it != cend; ++it ) + if ( (*it)->buddy() == w) + return *it; + return 0; +} + +// Replace widgets in a widget-list type dynamic property of the parent +// used for Z-order, etc. +static void replaceWidgetListDynamicProperty(QWidget *parentWidget, + QWidget *oldWidget, QWidget *newWidget, + const char *name) +{ + QWidgetList list = qvariant_cast(parentWidget->property(name)); + const int index = list.indexOf(oldWidget); + if (index != -1) { + list.replace(index, newWidget); + parentWidget->setProperty(name, QVariant::fromValue(list)); + } +} + +/* Morph a widget into another class. Use the static addMorphMacro() to + * add a respective command sequence to the undo stack as it emits signals + * which cause other commands to be added. */ +class MorphWidgetCommand : public QDesignerFormWindowCommand +{ + Q_DISABLE_COPY(MorphWidgetCommand) +public: + + explicit MorphWidgetCommand(QDesignerFormWindowInterface *formWindow); + ~MorphWidgetCommand(); + + // Convenience to add a morph command sequence macro + static bool addMorphMacro(QDesignerFormWindowInterface *formWindow, QWidget *w, const QString &newClass); + + bool init(QWidget *widget, const QString &newClass); + + QString newWidgetName() const { return m_afterWidget->objectName(); } + + virtual void redo(); + virtual void undo(); + + static QStringList candidateClasses(QDesignerFormWindowInterface *fw, QWidget *w); + +private: + static bool canMorph(QDesignerFormWindowInterface *fw, QWidget *w, int *childContainerCount = 0, MorphCategory *cat = 0); + void morph(QWidget *before, QWidget *after); + + QWidget *m_beforeWidget; + QWidget *m_afterWidget; +}; + +bool MorphWidgetCommand::addMorphMacro(QDesignerFormWindowInterface *fw, QWidget *w, const QString &newClass) +{ + MorphWidgetCommand *morphCmd = new MorphWidgetCommand(fw); + if (!morphCmd->init(w, newClass)) { + qWarning("*** Unable to create a MorphWidgetCommand"); + delete morphCmd; + return false; + } + QLabel *buddyLabel = buddyLabelOf(fw, w); + // Need a macro since it adds further commands + QUndoStack *us = fw->commandHistory(); + us->beginMacro(morphCmd->text()); + // Have the signal slot/buddy editors add their commands to delete widget + if (FormWindowBase *fwb = qobject_cast(fw)) + fwb->emitWidgetRemoved(w); + + const QString newWidgetName = morphCmd->newWidgetName(); + us->push(morphCmd); + + // restore buddy using the QByteArray name. + if (buddyLabel) { + SetPropertyCommand *buddyCmd = new SetPropertyCommand(fw); + buddyCmd->init(buddyLabel, QLatin1String("buddy"), QVariant(newWidgetName.toUtf8())); + us->push(buddyCmd); + } + us->endMacro(); + return true; +} + +MorphWidgetCommand::MorphWidgetCommand(QDesignerFormWindowInterface *formWindow) : + QDesignerFormWindowCommand(QString(), formWindow), + m_beforeWidget(0), + m_afterWidget(0) +{ +} + +MorphWidgetCommand::~MorphWidgetCommand() +{ +} + +bool MorphWidgetCommand::init(QWidget *widget, const QString &newClassName) +{ + QDesignerFormWindowInterface *fw = formWindow(); + QDesignerFormEditorInterface *core = fw->core(); + + if (!canMorph(fw, widget)) + return false; + + const QString oldClassName = WidgetFactory::classNameOf(core, widget); + const QString oldName = widget->objectName(); + //: MorphWidgetCommand description + setText(QApplication::translate("Command", "Morph %1/'%2' into %3").arg(oldClassName, oldName, newClassName)); + + m_beforeWidget = widget; + m_afterWidget = core->widgetFactory()->createWidget(newClassName, fw); + if (!m_afterWidget) + return false; + + // Set object name. Do not unique it (as to maintain it). + m_afterWidget->setObjectName(suggestObjectName(oldClassName, newClassName, oldName)); + + // If the target has a container extension, we add enough new pages to take + // up the children of the before widget + if (QDesignerContainerExtension* c = qt_extension(core->extensionManager(), m_afterWidget)) { + if (const int pageCount = childContainers(core, m_beforeWidget).size()) { + const QString qWidget = QLatin1String("QWidget"); + const QString containerName = m_afterWidget->objectName(); + for (int i = 0; i < pageCount; i++) { + QString name = containerName; + name += QLatin1String("Page"); + name += QString::number(i + 1); + QWidget *page = core->widgetFactory()->createWidget(qWidget); + page->setObjectName(name); + fw->ensureUniqueObjectName(page); + c->addWidget(page); + core->metaDataBase()->add(page); + } + } + } + + // Copy over applicable properties + const QDesignerPropertySheetExtension *beforeSheet = qt_extension(core->extensionManager(), widget); + QDesignerPropertySheetExtension *afterSheet = qt_extension(core->extensionManager(), m_afterWidget); + const QString objectNameProperty = QLatin1String("objectName"); + const int count = beforeSheet->count(); + for (int i = 0; i < count; i++) + if (beforeSheet->isVisible(i) && beforeSheet->isChanged(i)) { + const QString name = beforeSheet->propertyName(i); + if (name != objectNameProperty) { + const int afterIndex = afterSheet->indexOf(name); + if (afterIndex != -1 && afterSheet->isVisible(afterIndex) && afterSheet->propertyGroup(afterIndex) == beforeSheet->propertyGroup(i)) { + afterSheet->setProperty(i, beforeSheet->property(i)); + afterSheet->setChanged(i, true); + } else { + // Some mismatch. The rest won't match, either + break; + } + } + } + return true; +} + +void MorphWidgetCommand::redo() +{ + morph(m_beforeWidget, m_afterWidget); +} + +void MorphWidgetCommand::undo() +{ + morph(m_afterWidget, m_beforeWidget); +} + +void MorphWidgetCommand::morph(QWidget *before, QWidget *after) +{ + QDesignerFormWindowInterface *fw = formWindow(); + + fw->unmanageWidget(before); + + const QRect oldGeom = before->geometry(); + QWidget *parent = before->parentWidget(); + Q_ASSERT(parent); + /* Morphing consists of main 2 steps + * 1) Move over children (laid out, non-laid out) + * 2) Register self with new parent (laid out, non-laid out) */ + + // 1) Move children. Loop over child containers + QWidgetList beforeChildContainers = childContainers(fw->core(), before); + QWidgetList afterChildContainers = childContainers(fw->core(), after); + Q_ASSERT(beforeChildContainers.size() == afterChildContainers.size()); + const int childContainerCount = beforeChildContainers.size(); + for (int i = 0; i < childContainerCount; i++) { + QWidget *beforeChildContainer = beforeChildContainers.at(i); + QWidget *afterChildContainer = afterChildContainers.at(i); + if (QLayout *childLayout = beforeChildContainer->layout()) { + // Laid-out: Move the layout (since 4.5) + afterChildContainer->setLayout(childLayout); + } else { + // Non-Laid-out: Reparent, move over + const QObjectList c = beforeChildContainer->children(); + const QObjectList::const_iterator cend = c.constEnd(); + for (QObjectList::const_iterator it = c.constBegin(); it != cend; ++it) { + if ( (*it)->isWidgetType()) { + QWidget *w = static_cast(*it); + if (fw->isManaged(w)) { + const QRect geom = w->geometry(); + w->setParent(afterChildContainer); + w->setGeometry(geom); + } + } + } + } + afterChildContainer->setProperty(widgetOrderPropertyC, beforeChildContainer->property(widgetOrderPropertyC)); + afterChildContainer->setProperty(zOrderPropertyC, beforeChildContainer->property(zOrderPropertyC)); + } + + // 2) Replace the actual widget in the parent layout + after->setGeometry(oldGeom); + if (QLayout *containingLayout = LayoutInfo::managedLayout(fw->core(), parent)) { + LayoutHelper *lh = LayoutHelper::createLayoutHelper(LayoutInfo::layoutType(fw->core(), containingLayout)); + Q_ASSERT(lh); + lh->replaceWidget(containingLayout, before, after); + delete lh; + } else { + before->hide(); + before->setParent(0); + after->setParent(parent); + after->setGeometry(oldGeom); + } + + // Check various properties: Z order, form tab order + replaceWidgetListDynamicProperty(parent, before, after, widgetOrderPropertyC); + replaceWidgetListDynamicProperty(parent, before, after, zOrderPropertyC); + + QDesignerMetaDataBaseItemInterface *formItem = fw->core()->metaDataBase()->item(fw); + QWidgetList tabOrder = formItem->tabOrder(); + const int tabIndex = tabOrder.indexOf(before); + if (tabIndex != -1) { + tabOrder.replace(tabIndex, after); + formItem->setTabOrder(tabOrder); + } + + after->show(); + fw->manageWidget(after); + + fw->clearSelection(false); + fw->selectWidget(after); +} + +/* Check if morphing is possible. It must be a valid category and the parent/ + * child relationships must be either non-laidout or directly on + * Designer-managed layouts. */ +bool MorphWidgetCommand::canMorph(QDesignerFormWindowInterface *fw, QWidget *w, int *ptrToChildContainerCount, MorphCategory *ptrToCat) +{ + if (ptrToChildContainerCount) + *ptrToChildContainerCount = 0; + const MorphCategory cat = category(w); + if (ptrToCat) + *ptrToCat = cat; + if (cat == MorphCategoryNone) + return false; + + QDesignerFormEditorInterface *core = fw->core(); + // Don't know how to fiddle class names in Jambi.. + if (qt_extension(core->extensionManager(), core)) + return false; + if (!fw->isManaged(w) || w == fw->mainContainer()) + return false; + // Check the parent relationship. We accept only managed parent widgets + // with a single, managed layout in which widget is a member. + QWidget *parent = w->parentWidget(); + if (parent == 0) + return false; + if (QLayout *pl = LayoutInfo::managedLayout(core, parent)) + if (pl->indexOf(w) < 0 || !core->metaDataBase()->item(pl)) + return false; + // Check Widget database + const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase(); + const int wdbindex = wdb->indexOfObject(w); + if (wdbindex == -1) + return false; + const bool isContainer = wdb->item(wdbindex)->isContainer(); + if (!isContainer) + return true; + // Check children. All child containers must be non-laid-out or have managed layouts + const QWidgetList pages = childContainers(core, w); + const int pageCount = pages.size(); + if (ptrToChildContainerCount) + *ptrToChildContainerCount = pageCount; + if (pageCount) { + for (int i = 0; i < pageCount; i++) + if (QLayout *cl = pages.at(i)->layout()) + if (!core->metaDataBase()->item(cl)) + return false; + } + return true; +} + +QStringList MorphWidgetCommand::candidateClasses(QDesignerFormWindowInterface *fw, QWidget *w) +{ + int childContainerCount; + MorphCategory cat; + if (!canMorph(fw, w, &childContainerCount, &cat)) + return QStringList(); + + QStringList rc = classesOfCategory(cat); + switch (cat) { + // Frames, etc can always be morphed into one-page page containers + case MorphSimpleContainer: + rc += classesOfCategory(MorphPageContainer); + break; + // Multipage-Containers can be morphed into simple containers if they + // have 1 page. + case MorphPageContainer: + if (childContainerCount == 1) + rc += classesOfCategory(MorphSimpleContainer); + break; + default: + break; + } + return rc; +} + +// MorphMenu +MorphMenu::MorphMenu(QObject *parent) : + QObject(parent), + m_subMenuAction(0), + m_menu(0), + m_mapper(0), + m_widget(0), + m_formWindow(0) +{ +} + +void MorphMenu::populate(QWidget *w, QDesignerFormWindowInterface *fw, ActionList& al) +{ + if (populateMenu(w, fw)) + al.push_back(m_subMenuAction); +} + +void MorphMenu::populate(QWidget *w, QDesignerFormWindowInterface *fw, QMenu& m) +{ + if (populateMenu(w, fw)) + m.addAction(m_subMenuAction); +} + +void MorphMenu::slotMorph(const QString &newClassName) +{ + MorphWidgetCommand::addMorphMacro(m_formWindow, m_widget, newClassName); +} + +bool MorphMenu::populateMenu(QWidget *w, QDesignerFormWindowInterface *fw) +{ + m_widget = 0; + m_formWindow = 0; + + // Clear menu + if (m_subMenuAction) { + m_subMenuAction->setVisible(false); + m_menu->clear(); + } + + // Checks: Must not be main container + if (w == fw->mainContainer()) + return false; + + const QStringList c = MorphWidgetCommand::candidateClasses(fw, w); + if (c.empty()) + return false; + + // Pull up + m_widget = w; + m_formWindow = fw; + const QString oldClassName = WidgetFactory::classNameOf(fw->core(), w); + + if (!m_subMenuAction) { + m_subMenuAction = new QAction(tr("Morph into"), this); + m_menu = new QMenu; + m_subMenuAction->setMenu(m_menu); + m_mapper = new QSignalMapper(this); + connect(m_mapper , SIGNAL(mapped(QString)), this, SLOT(slotMorph(QString))); + } + + // Add actions + const QStringList::const_iterator cend = c.constEnd(); + for (QStringList::const_iterator it = c.constBegin(); it != cend; ++it) { + if (*it != oldClassName) { + QAction *a = m_menu->addAction(*it); + m_mapper->setMapping (a, *it); + connect(a, SIGNAL(triggered()), m_mapper, SLOT(map())); + } + } + m_subMenuAction->setVisible(true); + return true; +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/morphmenu_p.h b/src/designer/src/lib/shared/morphmenu_p.h new file mode 100644 index 000000000..9d20545a6 --- /dev/null +++ b/src/designer/src/lib/shared/morphmenu_p.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef MORPH_COMMAND_H +#define MORPH_COMMAND_H + +#include "shared_global_p.h" +#include "qdesigner_formwindowcommand_p.h" + +QT_BEGIN_NAMESPACE + +class QAction; +class QSignalMapper; +class QMenu; + +namespace qdesigner_internal { + +/* Conveniene morph menu that acts on a single widget. */ +class QDESIGNER_SHARED_EXPORT MorphMenu : public QObject { + Q_DISABLE_COPY(MorphMenu) + Q_OBJECT +public: + typedef QList ActionList; + + explicit MorphMenu(QObject *parent = 0); + + void populate(QWidget *w, QDesignerFormWindowInterface *fw, ActionList& al); + void populate(QWidget *w, QDesignerFormWindowInterface *fw, QMenu& m); + +private slots: + void slotMorph(const QString &newClassName); + +private: + bool populateMenu(QWidget *w, QDesignerFormWindowInterface *fw); + + QAction *m_subMenuAction; + QMenu *m_menu; + QSignalMapper *m_mapper; + + QWidget *m_widget; + QDesignerFormWindowInterface *m_formWindow; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // MORPH_COMMAND_H diff --git a/src/designer/src/lib/shared/newactiondialog.cpp b/src/designer/src/lib/shared/newactiondialog.cpp new file mode 100644 index 000000000..9aaa347c7 --- /dev/null +++ b/src/designer/src/lib/shared/newactiondialog.cpp @@ -0,0 +1,199 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "newactiondialog_p.h" +#include "ui_newactiondialog.h" +#include "richtexteditor_p.h" +#include "actioneditor_p.h" +#include "formwindowbase_p.h" +#include "qdesigner_utils_p.h" +#include "iconloader_p.h" + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { +// -------------------- ActionData + +ActionData::ActionData() : + checkable(false) +{ +} + +// Returns a combination of ChangeMask flags +unsigned ActionData::compare(const ActionData &rhs) const +{ + unsigned rc = 0; + if (text != rhs.text) + rc |= TextChanged; + if (name != rhs.name) + rc |= NameChanged; + if (toolTip != rhs.toolTip) + rc |= ToolTipChanged ; + if (icon != rhs.icon) + rc |= IconChanged ; + if (checkable != rhs.checkable) + rc |= CheckableChanged; + if (keysequence != rhs.keysequence) + rc |= KeysequenceChanged ; + return rc; +} + +// -------------------- NewActionDialog +NewActionDialog::NewActionDialog(ActionEditor *parent) : + QDialog(parent, Qt::Sheet), + m_ui(new Ui::NewActionDialog), + m_actionEditor(parent) +{ + m_ui->setupUi(this); + + m_ui->tooltipEditor->setTextPropertyValidationMode(ValidationRichText); + connect(m_ui->toolTipToolButton, SIGNAL(clicked()), this, SLOT(slotEditToolTip())); + + m_ui->keysequenceResetToolButton->setIcon(createIconSet(QLatin1String("resetproperty.png"))); + connect(m_ui->keysequenceResetToolButton, SIGNAL(clicked()), this, SLOT(slotResetKeySequence())); + + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + m_ui->editActionText->setFocus(); + m_auto_update_object_name = true; + updateButtons(); + + QDesignerFormWindowInterface *form = parent->formWindow(); + m_ui->iconSelector->setFormEditor(form->core()); + FormWindowBase *formBase = qobject_cast(form); + + if (formBase) { + m_ui->iconSelector->setPixmapCache(formBase->pixmapCache()); + m_ui->iconSelector->setIconCache(formBase->iconCache()); + } +} + +NewActionDialog::~NewActionDialog() +{ + delete m_ui; +} + +QString NewActionDialog::actionText() const +{ + return m_ui->editActionText->text(); +} + +QString NewActionDialog::actionName() const +{ + return m_ui->editObjectName->text(); +} + +ActionData NewActionDialog::actionData() const +{ + ActionData rc; + rc.text = actionText(); + rc.name = actionName(); + rc.toolTip = m_ui->tooltipEditor->text(); + rc.icon = m_ui->iconSelector->icon(); + rc.icon.setTheme(m_ui->iconThemeEditor->theme()); + rc.checkable = m_ui->checkableCheckBox->checkState() == Qt::Checked; + rc.keysequence = PropertySheetKeySequenceValue(m_ui->keySequenceEdit->keySequence()); + return rc; +} + +void NewActionDialog::setActionData(const ActionData &d) +{ + m_ui->editActionText->setText(d.text); + m_ui->editObjectName->setText(d.name); + m_ui->iconSelector->setIcon(d.icon.unthemed()); + m_ui->iconThemeEditor->setTheme(d.icon.theme()); + m_ui->tooltipEditor->setText(d.toolTip); + m_ui->keySequenceEdit->setKeySequence(d.keysequence.value()); + m_ui->checkableCheckBox->setCheckState(d.checkable ? Qt::Checked : Qt::Unchecked); + + m_auto_update_object_name = false; + updateButtons(); +} + +void NewActionDialog::on_editActionText_textEdited(const QString &text) +{ + if (text.isEmpty()) + m_auto_update_object_name = true; + + if (m_auto_update_object_name) + m_ui->editObjectName->setText(ActionEditor::actionTextToName(text)); + + updateButtons(); +} + +void NewActionDialog::on_editObjectName_textEdited(const QString&) +{ + updateButtons(); + m_auto_update_object_name = false; +} + +void NewActionDialog::slotEditToolTip() +{ + const QString oldToolTip = m_ui->tooltipEditor->text(); + RichTextEditorDialog richTextDialog(m_actionEditor->core(), this); + richTextDialog.setText(oldToolTip); + if (richTextDialog.showDialog() == QDialog::Rejected) + return; + const QString newToolTip = richTextDialog.text(); + if (newToolTip != oldToolTip) + m_ui->tooltipEditor->setText(newToolTip); +} + +void NewActionDialog::slotResetKeySequence() +{ + m_ui->keySequenceEdit->setKeySequence(QKeySequence()); + m_ui->keySequenceEdit->setFocus(Qt::MouseFocusReason); +} + +void NewActionDialog::updateButtons() +{ + QPushButton *okButton = m_ui->buttonBox->button(QDialogButtonBox::Ok); + okButton->setEnabled(!actionText().isEmpty() && !actionName().isEmpty()); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/newactiondialog.ui b/src/designer/src/lib/shared/newactiondialog.ui new file mode 100644 index 000000000..aef971058 --- /dev/null +++ b/src/designer/src/lib/shared/newactiondialog.ui @@ -0,0 +1,313 @@ + + + ********************************************************************* +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +********************************************************************* + qdesigner_internal::NewActionDialog + + + + 0 + 0 + 366 + 270 + + + + New Action... + + + + + + + + &Text: + + + editActionText + + + + + + + + 255 + 0 + + + + + + + + Object &name: + + + editObjectName + + + + + + + + + + T&oolTip: + + + tooltipEditor + + + + + + + + + + 0 + 0 + + + + + + + + ... + + + + + + + + + Icon th&eme: + + + iconThemeEditor + + + + + + + + + + &Icon: + + + iconSelector + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + + &Checkable: + + + checkableCheckBox + + + + + + + &Shortcut: + + + keySequenceEdit + + + + + + + + + + 0 + 0 + + + + + + + + ... + + + + + + + + + + + Qt::Vertical + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + qdesigner_internal::IconSelector + QWidget +
iconselector_p.h
+ 1 +
+ + QtKeySequenceEdit + QWidget +
qtpropertybrowserutils_p.h
+ 1 +
+ + TextPropertyEditor + QWidget +
textpropertyeditor_p.h
+ 1 +
+ + qdesigner_internal::IconThemeEditor + QWidget +
iconselector_p.h
+ 1 +
+
+ + editActionText + editObjectName + + + + + buttonBox + accepted() + qdesigner_internal::NewActionDialog + accept() + + + 165 + 162 + + + 291 + 94 + + + + + buttonBox + rejected() + qdesigner_internal::NewActionDialog + reject() + + + 259 + 162 + + + 293 + 128 + + + + +
diff --git a/src/designer/src/lib/shared/newactiondialog_p.h b/src/designer/src/lib/shared/newactiondialog_p.h new file mode 100644 index 000000000..b06d1f9a5 --- /dev/null +++ b/src/designer/src/lib/shared/newactiondialog_p.h @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef NEWACTIONDIALOG_P_H +#define NEWACTIONDIALOG_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qdesigner_utils_p.h" // PropertySheetIconValue + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +namespace Ui { + class NewActionDialog; +} + +class ActionEditor; + +struct ActionData { + + enum ChangeMask { + TextChanged = 0x1, NameChanged = 0x2, ToolTipChanged = 0x4, + IconChanged = 0x8, CheckableChanged = 0x10, KeysequenceChanged = 0x20 + }; + + ActionData(); + // Returns a combination of ChangeMask flags + unsigned compare(const ActionData &rhs) const; + + QString text; + QString name; + QString toolTip; + PropertySheetIconValue icon; + bool checkable; + PropertySheetKeySequenceValue keysequence; +}; + +inline bool operator==(const ActionData &a1, const ActionData &a2) { return a1.compare(a2) == 0u; } +inline bool operator!=(const ActionData &a1, const ActionData &a2) { return a1.compare(a2) != 0u; } + +class NewActionDialog: public QDialog +{ + Q_OBJECT +public: + explicit NewActionDialog(ActionEditor *parent); + virtual ~NewActionDialog(); + + ActionData actionData() const; + void setActionData(const ActionData &d); + + QString actionText() const; + QString actionName() const; + +private slots: + void on_editActionText_textEdited(const QString &text); + void on_editObjectName_textEdited(const QString &text); + void slotEditToolTip(); + void slotResetKeySequence(); + +private: + Ui::NewActionDialog *m_ui; + ActionEditor *m_actionEditor; + bool m_auto_update_object_name; + + void updateButtons(); +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // NEWACTIONDIALOG_P_H diff --git a/src/designer/src/lib/shared/newformwidget.cpp b/src/designer/src/lib/shared/newformwidget.cpp new file mode 100644 index 000000000..150d97104 --- /dev/null +++ b/src/designer/src/lib/shared/newformwidget.cpp @@ -0,0 +1,586 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "newformwidget_p.h" +#include "ui_newformwidget.h" +#include "qdesigner_formbuilder_p.h" +#include "sheet_delegate_p.h" +#include "widgetdatabase_p.h" +#include "shared_settings_p.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +enum { profileComboIndexOffset = 1 }; +enum { debugNewFormWidget = 0 }; + +enum NewForm_CustomRole { + // File name (templates from resources, paths) + TemplateNameRole = Qt::UserRole + 100, + // Class name (widgets from Widget data base) + ClassNameRole = Qt::UserRole + 101 +}; + +static const char *newFormObjectNameC = "Form"; + +// Create a form name for an arbitrary class. If it is Qt, qtify it, +// else return "Form". +static QString formName(const QString &className) +{ + if (!className.startsWith(QLatin1Char('Q'))) + return QLatin1String(newFormObjectNameC); + QString rc = className; + rc.remove(0, 1); + return rc; +} + +namespace qdesigner_internal { + +struct TemplateSize { + const char *name; + int width; + int height; +}; + +static const struct TemplateSize templateSizes[] = +{ + { QT_TRANSLATE_NOOP("qdesigner_internal::NewFormWidget", "Default size"), 0, 0 }, + { QT_TRANSLATE_NOOP("qdesigner_internal::NewFormWidget", "QVGA portrait (240x320)"), 240, 320 }, + { QT_TRANSLATE_NOOP("qdesigner_internal::NewFormWidget", "QVGA landscape (320x240)"), 320, 240 }, + { QT_TRANSLATE_NOOP("qdesigner_internal::NewFormWidget", "VGA portrait (480x640)"), 480, 640 }, + { QT_TRANSLATE_NOOP("qdesigner_internal::NewFormWidget", "VGA landscape (640x480)"), 640, 480 } +}; + +/* -------------- NewForm dialog. + * Designer takes new form templates from: + * 1) Files located in directories specified in resources + * 2) Files located in directories specified as user templates + * 3) XML from container widgets deemed usable for form templates by the widget + * database + * 4) XML from custom container widgets deemed usable for form templates by the + * widget database + * + * The widget database provides helper functions to obtain lists of names + * and xml for 3,4. + * + * Fixed-size forms for embedded platforms are obtained as follows: + * 1) If the origin is a file: + * - Check if the file exists in the subdirectory "/x/" of + * the path (currently the case for the dialog box because the button box + * needs to be positioned) + * - Scale the form using the QWidgetDatabase::scaleFormTemplate routine. + * 2) If the origin is XML: + * - Scale the form using the QWidgetDatabase::scaleFormTemplate routine. + * + * The tree widget item roles indicate which type of entry it is + * (TemplateNameRole = file name 1,2, ClassNameRole = class name 3,4) + */ + +NewFormWidget::NewFormWidget(QDesignerFormEditorInterface *core, QWidget *parentWidget) : + QDesignerNewFormWidgetInterface(parentWidget), + m_core(core), + m_ui(new Ui::NewFormWidget), + m_currentItem(0), + m_acceptedItem(0) +{ + typedef QList DeviceProfileList; + + m_ui->setupUi(this); + m_ui->treeWidget->setItemDelegate(new qdesigner_internal::SheetDelegate(m_ui->treeWidget, this)); + m_ui->treeWidget->header()->hide(); + m_ui->treeWidget->header()->setStretchLastSection(true); + m_ui->lblPreview->setBackgroundRole(QPalette::Base); + QDesignerSharedSettings settings(m_core); + + QString uiExtension = QLatin1String("ui"); + QString templatePath = QLatin1String(":/trolltech/designer/templates/forms"); + + QDesignerLanguageExtension *lang = qt_extension(core->extensionManager(), core); + if (lang) { + templatePath = QLatin1String(":/templates/forms"); + uiExtension = lang->uiExtension(); + } + + // Resource templates + const QString formTemplate = settings.formTemplate(); + QTreeWidgetItem *selectedItem = 0; + loadFrom(templatePath, true, uiExtension, formTemplate, selectedItem); + // Additional template paths + const QStringList formTemplatePaths = settings.formTemplatePaths(); + const QStringList::const_iterator ftcend = formTemplatePaths.constEnd(); + for (QStringList::const_iterator it = formTemplatePaths.constBegin(); it != ftcend; ++it) + loadFrom(*it, false, uiExtension, formTemplate, selectedItem); + + // Widgets/custom widgets + if (!lang) { + //: New Form Dialog Categories + loadFrom(tr("Widgets"), qdesigner_internal::WidgetDataBase::formWidgetClasses(core), formTemplate, selectedItem); + loadFrom(tr("Custom Widgets"), qdesigner_internal::WidgetDataBase::customFormWidgetClasses(core), formTemplate, selectedItem); + } + + // Still no selection - default to first item + if (selectedItem == 0 && m_ui->treeWidget->topLevelItemCount() != 0) { + QTreeWidgetItem *firstTopLevel = m_ui->treeWidget->topLevelItem(0); + if (firstTopLevel->childCount() > 0) + selectedItem = firstTopLevel->child(0); + } + + // Open parent, select and make visible + if (selectedItem) { + m_ui->treeWidget->setCurrentItem(selectedItem); + m_ui->treeWidget->setItemSelected(selectedItem, true); + m_ui->treeWidget->scrollToItem(selectedItem->parent()); + } + // Fill profile combo + m_deviceProfiles = settings.deviceProfiles(); + m_ui->profileComboBox->addItem(tr("None")); + connect(m_ui->profileComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotDeviceProfileIndexChanged(int))); + if (m_deviceProfiles.empty()) { + m_ui->profileComboBox->setEnabled(false); + } else { + const DeviceProfileList::const_iterator dcend = m_deviceProfiles.constEnd(); + for (DeviceProfileList::const_iterator it = m_deviceProfiles.constBegin(); it != dcend; ++it) + m_ui->profileComboBox->addItem(it->name()); + const int ci = settings.currentDeviceProfileIndex(); + if (ci >= 0) + m_ui->profileComboBox->setCurrentIndex(ci + profileComboIndexOffset); + } + // Fill size combo + const int sizeCount = sizeof(templateSizes)/ sizeof(TemplateSize); + for (int i = 0; i < sizeCount; i++) { + const QSize size = QSize(templateSizes[i].width, templateSizes[i].height); + m_ui->sizeComboBox->addItem(tr(templateSizes[i].name), size); + } + + setTemplateSize(settings.newFormSize()); + + if (debugNewFormWidget) + qDebug() << Q_FUNC_INFO << "Leaving"; +} + +NewFormWidget::~NewFormWidget() +{ + QDesignerSharedSettings settings (m_core); + settings.setNewFormSize(templateSize()); + // Do not change previously stored item if dialog was rejected + if (m_acceptedItem) + settings.setFormTemplate(m_acceptedItem->text(0)); + delete m_ui; +} + +void NewFormWidget::on_treeWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *) +{ + if (debugNewFormWidget) + qDebug() << Q_FUNC_INFO << current; + if (!current) + return; + + if (!current->parent()) { // Top level item: Ensure expanded when browsing down + return; + } + + m_currentItem = current; + + emit currentTemplateChanged(showCurrentItemPixmap()); +} + +bool NewFormWidget::showCurrentItemPixmap() +{ + bool rc = false; + if (m_currentItem) { + const QPixmap pixmap = formPreviewPixmap(m_currentItem); + if (pixmap.isNull()) { + m_ui->lblPreview->setText(tr("Error loading form")); + } else { + m_ui->lblPreview->setPixmap(pixmap); + rc = true; + } + } + return rc; +} + +void NewFormWidget::on_treeWidget_itemActivated(QTreeWidgetItem *item) +{ + if (debugNewFormWidget) + qDebug() << Q_FUNC_INFO << item; + + if (item->data(0, TemplateNameRole).isValid() || item->data(0, ClassNameRole).isValid()) + emit templateActivated(); +} + +QPixmap NewFormWidget::formPreviewPixmap(const QTreeWidgetItem *item) +{ + // Cache pixmaps per item/device profile + const ItemPixmapCacheKey cacheKey(item, profileComboIndex()); + ItemPixmapCache::iterator it = m_itemPixmapCache.find(cacheKey); + if (it == m_itemPixmapCache.end()) { + // file or string? + const QVariant fileName = item->data(0, TemplateNameRole); + QPixmap rc; + if (fileName.type() == QVariant::String) { + rc = formPreviewPixmap(fileName.toString()); + } else { + const QVariant classNameV = item->data(0, ClassNameRole); + Q_ASSERT(classNameV.type() == QVariant::String); + const QString className = classNameV.toString(); + QByteArray data = qdesigner_internal::WidgetDataBase::formTemplate(m_core, className, formName(className)).toUtf8(); + QBuffer buffer(&data); + buffer.open(QIODevice::ReadOnly); + rc = formPreviewPixmap(buffer); + } + if (rc.isNull()) // Retry invalid ones + return rc; + it = m_itemPixmapCache.insert(cacheKey, rc); + } + return it.value(); +} + +QPixmap NewFormWidget::formPreviewPixmap(const QString &fileName) const +{ + QFile f(fileName); + if (f.open(QFile::ReadOnly)) { + QFileInfo fi(fileName); + const QPixmap rc = formPreviewPixmap(f, fi.absolutePath()); + f.close(); + return rc; + } + qWarning() << "The file " << fileName << " could not be opened: " << f.errorString(); + return QPixmap(); +} + +QImage NewFormWidget::grabForm(QDesignerFormEditorInterface *core, + QIODevice &file, + const QString &workingDir, + const qdesigner_internal::DeviceProfile &dp) +{ + qdesigner_internal::NewFormWidgetFormBuilder + formBuilder(core, qdesigner_internal::QDesignerFormBuilder::DisableScripts, dp); + if (!workingDir.isEmpty()) + formBuilder.setWorkingDirectory(workingDir); + + QWidget *widget = formBuilder.load(&file, 0); + if (!widget) + return QImage(); + + const QPixmap pixmap = QPixmap::grabWidget(widget); + widget->deleteLater(); + return pixmap.toImage(); +} + +QPixmap NewFormWidget::formPreviewPixmap(QIODevice &file, const QString &workingDir) const +{ + const int margin = 7; + const int shadow = 7; + const int previewSize = 256; + + const QImage wimage = grabForm(m_core, file, workingDir, currentDeviceProfile()); + if (wimage.isNull()) + return QPixmap(); + const QImage image = wimage.scaled(previewSize - margin * 2, previewSize - margin * 2, + Qt::KeepAspectRatio, + Qt::SmoothTransformation); + + QImage dest(previewSize, previewSize, QImage::Format_ARGB32_Premultiplied); + dest.fill(0); + + QPainter p(&dest); + p.drawImage(margin, margin, image); + + p.setPen(QPen(palette().brush(QPalette::WindowText), 0)); + + p.drawRect(margin-1, margin-1, image.width() + 1, image.height() + 1); + + const QColor dark(Qt::darkGray); + const QColor light(Qt::transparent); + + // right shadow + { + const QRect rect(margin + image.width() + 1, margin + shadow, shadow, image.height() - shadow + 1); + QLinearGradient lg(rect.topLeft(), rect.topRight()); + lg.setColorAt(0, dark); + lg.setColorAt(1, light); + p.fillRect(rect, lg); + } + + // bottom shadow + { + const QRect rect(margin + shadow, margin + image.height() + 1, image.width() - shadow + 1, shadow); + QLinearGradient lg(rect.topLeft(), rect.bottomLeft()); + lg.setColorAt(0, dark); + lg.setColorAt(1, light); + p.fillRect(rect, lg); + } + + // bottom/right corner shadow + { + const QRect rect(margin + image.width() + 1, margin + image.height() + 1, shadow, shadow); + QRadialGradient g(rect.topLeft(), shadow); + g.setColorAt(0, dark); + g.setColorAt(1, light); + p.fillRect(rect, g); + } + + // top/right corner + { + const QRect rect(margin + image.width() + 1, margin, shadow, shadow); + QRadialGradient g(rect.bottomLeft(), shadow); + g.setColorAt(0, dark); + g.setColorAt(1, light); + p.fillRect(rect, g); + } + + // bottom/left corner + { + const QRect rect(margin, margin + image.height() + 1, shadow, shadow); + QRadialGradient g(rect.topRight(), shadow); + g.setColorAt(0, dark); + g.setColorAt(1, light); + p.fillRect(rect, g); + } + + p.end(); + + return QPixmap::fromImage(dest); +} + +void NewFormWidget::loadFrom(const QString &path, bool resourceFile, const QString &uiExtension, + const QString &selectedItem, QTreeWidgetItem *&selectedItemFound) +{ + const QDir dir(path); + + if (!dir.exists()) + return; + + // Iterate through the directory and add the templates + const QFileInfoList list = dir.entryInfoList(QStringList(QLatin1String("*.") + uiExtension), + QDir::Files); + + if (list.isEmpty()) + return; + + const QChar separator = resourceFile ? QChar(QLatin1Char('/')) + : QDir::separator(); + QTreeWidgetItem *root = new QTreeWidgetItem(m_ui->treeWidget); + root->setFlags(root->flags() & ~Qt::ItemIsSelectable); + // Try to get something that is easy to read. + QString visiblePath = path; + int index = visiblePath.lastIndexOf(separator); + if (index != -1) { + // try to find a second slash, just to be a bit better. + const int index2 = visiblePath.lastIndexOf(separator, index - 1); + if (index2 != -1) + index = index2; + visiblePath = visiblePath.mid(index + 1); + visiblePath = QDir::toNativeSeparators(visiblePath); + } + + const QChar underscore = QLatin1Char('_'); + const QChar blank = QLatin1Char(' '); + root->setText(0, visiblePath.replace(underscore, blank)); + root->setToolTip(0, path); + + const QFileInfoList::const_iterator lcend = list.constEnd(); + for (QFileInfoList::const_iterator it = list.constBegin(); it != lcend; ++it) { + if (!it->isFile()) + continue; + + QTreeWidgetItem *item = new QTreeWidgetItem(root); + const QString text = it->baseName().replace(underscore, blank); + if (selectedItemFound == 0 && text == selectedItem) + selectedItemFound = item; + item->setText(0, text); + item->setData(0, TemplateNameRole, it->absoluteFilePath()); + } +} + +void NewFormWidget::loadFrom(const QString &title, const QStringList &nameList, + const QString &selectedItem, QTreeWidgetItem *&selectedItemFound) +{ + if (nameList.empty()) + return; + QTreeWidgetItem *root = new QTreeWidgetItem(m_ui->treeWidget); + root->setFlags(root->flags() & ~Qt::ItemIsSelectable); + root->setText(0, title); + const QStringList::const_iterator cend = nameList.constEnd(); + for (QStringList::const_iterator it = nameList.constBegin(); it != cend; ++it) { + const QString text = *it; + QTreeWidgetItem *item = new QTreeWidgetItem(root); + item->setText(0, text); + if (selectedItemFound == 0 && text == selectedItem) + selectedItemFound = item; + item->setData(0, ClassNameRole, *it); + } +} + +void NewFormWidget::on_treeWidget_itemPressed(QTreeWidgetItem *item) +{ + if (item && !item->parent()) + m_ui->treeWidget->setItemExpanded(item, !m_ui->treeWidget->isItemExpanded(item)); +} + +QSize NewFormWidget::templateSize() const +{ + return m_ui->sizeComboBox->itemData(m_ui->sizeComboBox->currentIndex()).toSize(); +} + +void NewFormWidget::setTemplateSize(const QSize &s) +{ + const int index = s.isNull() ? 0 : m_ui->sizeComboBox->findData(s); + if (index != -1) + m_ui->sizeComboBox->setCurrentIndex(index); +} + +static QString readAll(const QString &fileName, QString *errorMessage) +{ + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly|QIODevice::Text)) { + *errorMessage = NewFormWidget::tr("Unable to open the form template file '%1': %2").arg(fileName, file.errorString()); + return QString(); + } + return QString::fromUtf8(file.readAll()); +} + +QString NewFormWidget::itemToTemplate(const QTreeWidgetItem *item, QString *errorMessage) const +{ + const QSize size = templateSize(); + // file name or string contents? + const QVariant templateFileName = item->data(0, TemplateNameRole); + if (templateFileName.type() == QVariant::String) { + const QString fileName = templateFileName.toString(); + // No fixed size: just open. + if (size.isNull()) + return readAll(fileName, errorMessage); + // try to find a file matching the size, like "../640x480/xx.ui" + const QFileInfo fiBase(fileName); + QString sizeFileName; + QTextStream(&sizeFileName) << fiBase.path() << QDir::separator() + << size.width() << QLatin1Char('x') << size.height() << QDir::separator() + << fiBase.fileName(); + if (QFileInfo(sizeFileName).isFile()) + return readAll(sizeFileName, errorMessage); + // Nothing found, scale via DOM/temporary file + QString contents = readAll(fileName, errorMessage); + if (!contents.isEmpty()) + contents = qdesigner_internal::WidgetDataBase::scaleFormTemplate(contents, size, false); + return contents; + } + // Content. + const QString className = item->data(0, ClassNameRole).toString(); + QString contents = qdesigner_internal::WidgetDataBase::formTemplate(m_core, className, formName(className)); + if (!size.isNull()) + contents = qdesigner_internal::WidgetDataBase::scaleFormTemplate(contents, size, false); + return contents; +} + +void NewFormWidget::slotDeviceProfileIndexChanged(int idx) +{ + // Store index for form windows to take effect and refresh pixmap + QDesignerSharedSettings settings(m_core); + settings.setCurrentDeviceProfileIndex(idx - profileComboIndexOffset); + showCurrentItemPixmap(); +} + +int NewFormWidget::profileComboIndex() const +{ + return m_ui->profileComboBox->currentIndex(); +} + +qdesigner_internal::DeviceProfile NewFormWidget::currentDeviceProfile() const +{ + const int ci = profileComboIndex(); + if (ci > 0) + return m_deviceProfiles.at(ci - profileComboIndexOffset); + return qdesigner_internal::DeviceProfile(); +} + +bool NewFormWidget::hasCurrentTemplate() const +{ + return m_currentItem != 0; +} + +QString NewFormWidget::currentTemplateI(QString *ptrToErrorMessage) +{ + if (m_currentItem == 0) { + *ptrToErrorMessage = tr("Internal error: No template selected."); + return QString(); + } + const QString contents = itemToTemplate(m_currentItem, ptrToErrorMessage); + if (contents.isEmpty()) + return contents; + + m_acceptedItem = m_currentItem; + return contents; +} + +QString NewFormWidget::currentTemplate(QString *ptrToErrorMessage) +{ + if (ptrToErrorMessage) + return currentTemplateI(ptrToErrorMessage); + // Do not loose the error + QString errorMessage; + const QString contents = currentTemplateI(&errorMessage); + if (!errorMessage.isEmpty()) + qWarning("%s", errorMessage.toUtf8().constData()); + return contents; +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/newformwidget.ui b/src/designer/src/lib/shared/newformwidget.ui new file mode 100644 index 000000000..830057c0e --- /dev/null +++ b/src/designer/src/lib/shared/newformwidget.ui @@ -0,0 +1,192 @@ + + + ********************************************************************* +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +********************************************************************* + qdesigner_internal::NewFormWidget + + + + 0 + 0 + 480 + 194 + + + + + 6 + + + 1 + + + + + + 200 + 0 + + + + + 128 + 128 + + + + false + + + 1 + + + + 0 + + + + + + + + + + + 0 + 0 + + + + 1 + + + Choose a template for a preview + + + Qt::AlignCenter + + + 5 + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 7 + 0 + + + + + + + + Embedded Design + + + + + + + + + + + + Device: + + + + + + + Screen Size: + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + diff --git a/src/designer/src/lib/shared/newformwidget_p.h b/src/designer/src/lib/shared/newformwidget_p.h new file mode 100644 index 000000000..940b11ce9 --- /dev/null +++ b/src/designer/src/lib/shared/newformwidget_p.h @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef NEWFORMWIDGET_H +#define NEWFORMWIDGET_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "shared_global_p.h" +#include "deviceprofile_p.h" + +#include + +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QIODevice; +class QTreeWidgetItem; + +namespace qdesigner_internal { + +namespace Ui { + class NewFormWidget; +} + +class QDesignerWorkbench; + +class QDESIGNER_SHARED_EXPORT NewFormWidget : public QDesignerNewFormWidgetInterface +{ + Q_OBJECT + Q_DISABLE_COPY(NewFormWidget) + +public: + typedef QList DeviceProfileList; + + explicit NewFormWidget(QDesignerFormEditorInterface *core, QWidget *parentWidget); + virtual ~NewFormWidget(); + + virtual bool hasCurrentTemplate() const; + virtual QString currentTemplate(QString *errorMessage = 0); + + // Convenience for implementing file dialogs with preview + static QImage grabForm(QDesignerFormEditorInterface *core, + QIODevice &file, + const QString &workingDir, + const qdesigner_internal::DeviceProfile &dp); + +private slots: + void on_treeWidget_itemActivated(QTreeWidgetItem *item); + void on_treeWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *); + void on_treeWidget_itemPressed(QTreeWidgetItem *item); + void slotDeviceProfileIndexChanged(int idx); + +private: + QPixmap formPreviewPixmap(const QString &fileName) const; + QPixmap formPreviewPixmap(QIODevice &file, const QString &workingDir = QString()) const; + QPixmap formPreviewPixmap(const QTreeWidgetItem *item); + + void loadFrom(const QString &path, bool resourceFile, const QString &uiExtension, + const QString &selectedItem, QTreeWidgetItem *&selectedItemFound); + void loadFrom(const QString &title, const QStringList &nameList, + const QString &selectedItem, QTreeWidgetItem *&selectedItemFound); + +private: + QString itemToTemplate(const QTreeWidgetItem *item, QString *errorMessage) const; + QString currentTemplateI(QString *ptrToErrorMessage); + + QSize templateSize() const; + void setTemplateSize(const QSize &s); + int profileComboIndex() const; + qdesigner_internal::DeviceProfile currentDeviceProfile() const; + bool showCurrentItemPixmap(); + + // Pixmap cache (item, profile combo index) + typedef QPair ItemPixmapCacheKey; + typedef QMap ItemPixmapCache; + ItemPixmapCache m_itemPixmapCache; + + QDesignerFormEditorInterface *m_core; + Ui::NewFormWidget *m_ui; + QTreeWidgetItem *m_currentItem; + QTreeWidgetItem *m_acceptedItem; + DeviceProfileList m_deviceProfiles; +}; + +} + +QT_END_NAMESPACE + +#endif // NEWFORMWIDGET_H diff --git a/src/designer/src/lib/shared/orderdialog.cpp b/src/designer/src/lib/shared/orderdialog.cpp new file mode 100644 index 000000000..e992fdd34 --- /dev/null +++ b/src/designer/src/lib/shared/orderdialog.cpp @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "orderdialog_p.h" +#include "iconloader_p.h" +#include "ui_orderdialog.h" + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +// OrderDialog: Used to reorder the pages of QStackedWidget and QToolBox. +// Provides up and down buttons as well as DnD via QAbstractItemView::InternalMove mode +namespace qdesigner_internal { + +OrderDialog::OrderDialog(QWidget *parent) : + QDialog(parent), + m_ui(new Ui::OrderDialog), + m_format(PageOrderFormat) +{ + m_ui->setupUi(this); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + m_ui->upButton->setIcon(createIconSet(QString::fromUtf8("up.png"))); + m_ui->downButton->setIcon(createIconSet(QString::fromUtf8("down.png"))); + m_ui->buttonBox->button(QDialogButtonBox::Ok)->setDefault(true); + connect(m_ui->buttonBox->button(QDialogButtonBox::Reset), SIGNAL(clicked()), this, SLOT(slotReset())); + // Catch the remove operation of a DnD operation in QAbstractItemView::InternalMove mode to enable buttons + // Selection mode is 'contiguous' to enable DnD of groups + connect(m_ui->pageList->model(), SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(slotEnableButtonsAfterDnD())); + + m_ui->upButton->setEnabled(false); + m_ui->downButton->setEnabled(false); +} + +OrderDialog::~OrderDialog() +{ + delete m_ui; +} + +void OrderDialog::setDescription(const QString &d) +{ + m_ui->groupBox->setTitle(d); +} + +void OrderDialog::setPageList(const QWidgetList &pages) +{ + // The QWidget* are stored in a map indexed by the old index. + // The old index is set as user data on the item instead of the QWidget* + // because DnD is enabled which requires the user data to serializable + m_orderMap.clear(); + const int count = pages.count(); + for (int i=0; i < count; ++i) + m_orderMap.insert(i, pages.at(i)); + buildList(); +} + +void OrderDialog::buildList() +{ + m_ui->pageList->clear(); + const OrderMap::const_iterator cend = m_orderMap.constEnd(); + for (OrderMap::const_iterator it = m_orderMap.constBegin(); it != cend; ++it) { + QListWidgetItem *item = new QListWidgetItem(); + const int index = it.key(); + switch (m_format) { + case PageOrderFormat: + item->setText(tr("Index %1 (%2)").arg(index).arg(it.value()->objectName())); + break; + case TabOrderFormat: + item->setText(tr("%1 %2").arg(index+1).arg(it.value()->objectName())); + break; + } + item->setData(Qt::UserRole, QVariant(index)); + m_ui->pageList->addItem(item); + } + + if (m_ui->pageList->count() > 0) + m_ui->pageList->setCurrentRow(0); +} + +void OrderDialog::slotReset() +{ + buildList(); +} + +QWidgetList OrderDialog::pageList() const +{ + QWidgetList rc; + const int count = m_ui->pageList->count(); + for (int i=0; i < count; ++i) { + const int oldIndex = m_ui->pageList->item(i)->data(Qt::UserRole).toInt(); + rc.append(m_orderMap.value(oldIndex)); + } + return rc; +} + +void OrderDialog::on_upButton_clicked() +{ + const int row = m_ui->pageList->currentRow(); + if (row <= 0) + return; + + m_ui->pageList->insertItem(row - 1, m_ui->pageList->takeItem(row)); + m_ui->pageList->setCurrentRow(row - 1); +} + +void OrderDialog::on_downButton_clicked() +{ + const int row = m_ui->pageList->currentRow(); + if (row == -1 || row == m_ui->pageList->count() - 1) + return; + + m_ui->pageList->insertItem(row + 1, m_ui->pageList->takeItem(row)); + m_ui->pageList->setCurrentRow(row + 1); +} + +void OrderDialog::slotEnableButtonsAfterDnD() +{ + enableButtons(m_ui->pageList->currentRow()); +} + +void OrderDialog::on_pageList_currentRowChanged(int r) +{ + enableButtons(r); +} + +void OrderDialog::enableButtons(int r) +{ + m_ui->upButton->setEnabled(r > 0); + m_ui->downButton->setEnabled(r >= 0 && r < m_ui->pageList->count() - 1); +} + +QWidgetList OrderDialog::pagesOfContainer(const QDesignerFormEditorInterface *core, QWidget *container) +{ + QWidgetList rc; + if (QDesignerContainerExtension* ce = qt_extension(core->extensionManager(), container)) { + const int count = ce->count(); + for (int i = 0; i < count ;i ++) + rc.push_back(ce->widget(i)); + } + return rc; +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/orderdialog.ui b/src/designer/src/lib/shared/orderdialog.ui new file mode 100644 index 000000000..ae9a73488 --- /dev/null +++ b/src/designer/src/lib/shared/orderdialog.ui @@ -0,0 +1,198 @@ + + ********************************************************************* +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +********************************************************************* + qdesigner_internal::OrderDialog + + + + 0 + 0 + 467 + 310 + + + + Change Page Order + + + + + + Page Order + + + + 6 + + + 9 + + + 9 + + + 9 + + + 9 + + + + + + 344 + 0 + + + + QAbstractItemView::InternalMove + + + QAbstractItemView::ContiguousSelection + + + QListView::Snap + + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Move page up + + + + + + + Move page down + + + + + + + + 0 + 0 + + + + Qt::Vertical + + + + 20 + 99 + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Reset + + + + + + + + + buttonBox + accepted() + qdesigner_internal::OrderDialog + accept() + + + 50 + 163 + + + 6 + 151 + + + + + buttonBox + rejected() + qdesigner_internal::OrderDialog + reject() + + + 300 + 160 + + + 348 + 148 + + + + + diff --git a/src/designer/src/lib/shared/orderdialog_p.h b/src/designer/src/lib/shared/orderdialog_p.h new file mode 100644 index 000000000..00d76fb15 --- /dev/null +++ b/src/designer/src/lib/shared/orderdialog_p.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef ORDERDIALOG_P_H +#define ORDERDIALOG_P_H + +#include "shared_global_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +namespace Ui { + class OrderDialog; +} + +class QDESIGNER_SHARED_EXPORT OrderDialog: public QDialog +{ + Q_OBJECT +public: + OrderDialog(QWidget *parent); + virtual ~OrderDialog(); + + static QWidgetList pagesOfContainer(const QDesignerFormEditorInterface *core, QWidget *container); + + void setPageList(const QWidgetList &pages); + QWidgetList pageList() const; + + void setDescription(const QString &d); + + enum Format { // Display format + PageOrderFormat, // Container pages, ranging 0..[n-1] + TabOrderFormat // List of widgets, ranging 1..1 + }; + + void setFormat(Format f) { m_format = f; } + Format format() const { return m_format; } + +private slots: + void on_upButton_clicked(); + void on_downButton_clicked(); + void on_pageList_currentRowChanged(int row); + void slotEnableButtonsAfterDnD(); + void slotReset(); + +private: + void buildList(); + void enableButtons(int r); + + typedef QMap OrderMap; + OrderMap m_orderMap; + Ui::OrderDialog* m_ui; + Format m_format; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // ORDERDIALOG_P_H diff --git a/src/designer/src/lib/shared/plaintexteditor.cpp b/src/designer/src/lib/shared/plaintexteditor.cpp new file mode 100644 index 000000000..748cecc41 --- /dev/null +++ b/src/designer/src/lib/shared/plaintexteditor.cpp @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "plaintexteditor_p.h" +#include "abstractsettings_p.h" + +#include + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static const char *PlainTextDialogC = "PlainTextDialog"; +static const char *Geometry = "Geometry"; + + +namespace qdesigner_internal { + +PlainTextEditorDialog::PlainTextEditorDialog(QDesignerFormEditorInterface *core, QWidget *parent) : + QDialog(parent), + m_editor(new QPlainTextEdit), + m_core(core) +{ + setWindowTitle(tr("Edit text")); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + QVBoxLayout *vlayout = new QVBoxLayout(this); + vlayout->addWidget(m_editor); + + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal); + QPushButton *ok_button = buttonBox->button(QDialogButtonBox::Ok); + ok_button->setDefault(true); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + vlayout->addWidget(buttonBox); + + QDesignerSettingsInterface *settings = core->settingsManager(); + settings->beginGroup(QLatin1String(PlainTextDialogC)); + + if (settings->contains(QLatin1String(Geometry))) + restoreGeometry(settings->value(QLatin1String(Geometry)).toByteArray()); + + settings->endGroup(); +} + +PlainTextEditorDialog::~PlainTextEditorDialog() +{ + QDesignerSettingsInterface *settings = m_core->settingsManager(); + settings->beginGroup(QLatin1String(PlainTextDialogC)); + + settings->setValue(QLatin1String(Geometry), saveGeometry()); + settings->endGroup(); +} + +int PlainTextEditorDialog::showDialog() +{ + m_editor->setFocus(); + return exec(); +} + +void PlainTextEditorDialog::setDefaultFont(const QFont &font) +{ + m_editor->setFont(font); +} + +void PlainTextEditorDialog::setText(const QString &text) +{ + m_editor->setPlainText(text); +} + +QString PlainTextEditorDialog::text() const +{ + return m_editor->toPlainText(); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/plaintexteditor_p.h b/src/designer/src/lib/shared/plaintexteditor_p.h new file mode 100644 index 000000000..830207bbd --- /dev/null +++ b/src/designer/src/lib/shared/plaintexteditor_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef PLAINTEXTEDITOR_H +#define PLAINTEXTEDITOR_H + +#include +#include "shared_global_p.h" + +QT_BEGIN_NAMESPACE + +class QPlainTextEdit; +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +class QDESIGNER_SHARED_EXPORT PlainTextEditorDialog : public QDialog +{ + Q_OBJECT +public: + explicit PlainTextEditorDialog(QDesignerFormEditorInterface *core, QWidget *parent = 0); + ~PlainTextEditorDialog(); + + int showDialog(); + + void setDefaultFont(const QFont &font); + + void setText(const QString &text); + QString text() const; + +private: + QPlainTextEdit *m_editor; + QDesignerFormEditorInterface *m_core; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // RITCHTEXTEDITOR_H diff --git a/src/designer/src/lib/shared/plugindialog.cpp b/src/designer/src/lib/shared/plugindialog.cpp new file mode 100644 index 000000000..9b1212b39 --- /dev/null +++ b/src/designer/src/lib/shared/plugindialog.cpp @@ -0,0 +1,207 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "plugindialog_p.h" +#include "pluginmanager_p.h" +#include "qdesigner_integration_p.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +PluginDialog::PluginDialog(QDesignerFormEditorInterface *core, QWidget *parent) + : QDialog(parent +#ifdef Q_WS_MAC + , Qt::Tool +#endif + ), m_core(core) +{ + ui.setupUi(this); + + ui.message->hide(); + + const QStringList headerLabels(tr("Components")); + + ui.treeWidget->setAlternatingRowColors(false); + ui.treeWidget->setSelectionMode(QAbstractItemView::NoSelection); + ui.treeWidget->setHeaderLabels(headerLabels); + ui.treeWidget->header()->hide(); + + interfaceIcon.addPixmap(style()->standardPixmap(QStyle::SP_DirOpenIcon), + QIcon::Normal, QIcon::On); + interfaceIcon.addPixmap(style()->standardPixmap(QStyle::SP_DirClosedIcon), + QIcon::Normal, QIcon::Off); + featureIcon.addPixmap(style()->standardPixmap(QStyle::SP_FileIcon)); + + setWindowTitle(tr("Plugin Information")); + populateTreeWidget(); + + if (qobject_cast(m_core->integration())) { + QPushButton *updateButton = new QPushButton(tr("Refresh")); + const QString tooltip = tr("Scan for newly installed custom widget plugins."); + updateButton->setToolTip(tooltip); + updateButton->setWhatsThis(tooltip); + connect(updateButton, SIGNAL(clicked()), this, SLOT(updateCustomWidgetPlugins())); + ui.buttonBox->addButton(updateButton, QDialogButtonBox::ActionRole); + } +} + +void PluginDialog::populateTreeWidget() +{ + ui.treeWidget->clear(); + QDesignerPluginManager *pluginManager = m_core->pluginManager(); + const QStringList fileNames = pluginManager->registeredPlugins(); + + if (!fileNames.isEmpty()) { + QTreeWidgetItem *topLevelItem = setTopLevelItem(tr("Loaded Plugins")); + QFont boldFont = topLevelItem->font(0); + + foreach (const QString &fileName, fileNames) { + QPluginLoader loader(fileName); + const QFileInfo fileInfo(fileName); + + QTreeWidgetItem *pluginItem = setPluginItem(topLevelItem, fileInfo.fileName(), boldFont); + + if (QObject *plugin = loader.instance()) { + if (const QDesignerCustomWidgetCollectionInterface *c = qobject_cast(plugin)) { + foreach (const QDesignerCustomWidgetInterface *p, c->customWidgets()) + setItem(pluginItem, p->name(), p->toolTip(), p->whatsThis(), p->icon()); + } else { + if (const QDesignerCustomWidgetInterface *p = qobject_cast(plugin)) + setItem(pluginItem, p->name(), p->toolTip(), p->whatsThis(), p->icon()); + } + } + } + } + + const QStringList notLoadedPlugins = pluginManager->failedPlugins(); + if (!notLoadedPlugins.isEmpty()) { + QTreeWidgetItem *topLevelItem = setTopLevelItem(tr("Failed Plugins")); + const QFont boldFont = topLevelItem->font(0); + foreach (const QString &plugin, notLoadedPlugins) { + const QString failureReason = pluginManager->failureReason(plugin); + QTreeWidgetItem *pluginItem = setPluginItem(topLevelItem, plugin, boldFont); + setItem(pluginItem, failureReason, failureReason, QString(), QIcon()); + } + } + + if (ui.treeWidget->topLevelItemCount() == 0) { + ui.label->setText(tr("Qt Designer couldn't find any plugins")); + ui.treeWidget->hide(); + } else { + ui.label->setText(tr("Qt Designer found the following plugins")); + } +} + +QIcon PluginDialog::pluginIcon(const QIcon &icon) +{ + if (icon.isNull()) + return QIcon(QLatin1String(":/trolltech/formeditor/images/qtlogo.png")); + + return icon; +} + +QTreeWidgetItem* PluginDialog::setTopLevelItem(const QString &itemName) +{ + QTreeWidgetItem *topLevelItem = new QTreeWidgetItem(ui.treeWidget); + topLevelItem->setText(0, itemName); + ui.treeWidget->setItemExpanded(topLevelItem, true); + topLevelItem->setIcon(0, style()->standardPixmap(QStyle::SP_DirOpenIcon)); + + QFont boldFont = topLevelItem->font(0); + boldFont.setBold(true); + topLevelItem->setFont(0, boldFont); + + return topLevelItem; +} + +QTreeWidgetItem* PluginDialog::setPluginItem(QTreeWidgetItem *topLevelItem, + const QString &itemName, const QFont &font) +{ + QTreeWidgetItem *pluginItem = new QTreeWidgetItem(topLevelItem); + pluginItem->setFont(0, font); + pluginItem->setText(0, itemName); + ui.treeWidget->setItemExpanded(pluginItem, true); + pluginItem->setIcon(0, style()->standardPixmap(QStyle::SP_DirOpenIcon)); + + return pluginItem; +} + +void PluginDialog::setItem(QTreeWidgetItem *pluginItem, const QString &name, + const QString &toolTip, const QString &whatsThis, const QIcon &icon) +{ + QTreeWidgetItem *item = new QTreeWidgetItem(pluginItem); + item->setText(0, name); + item->setToolTip(0, toolTip); + item->setWhatsThis(0, whatsThis); + item->setIcon(0, pluginIcon(icon)); +} + +void PluginDialog::updateCustomWidgetPlugins() +{ + if (qdesigner_internal::QDesignerIntegration *integration = qobject_cast(m_core->integration())) { + const int before = m_core->widgetDataBase()->count(); + integration->updateCustomWidgetPlugins(); + const int after = m_core->widgetDataBase()->count(); + if (after > before) { + ui.message->setText(tr("New custom widget plugins have been found.")); + ui.message->show(); + } else { + ui.message->setText(QString()); + } + populateTreeWidget(); + } +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/plugindialog.ui b/src/designer/src/lib/shared/plugindialog.ui new file mode 100644 index 000000000..50d117082 --- /dev/null +++ b/src/designer/src/lib/shared/plugindialog.ui @@ -0,0 +1,136 @@ + + + ********************************************************************* +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +********************************************************************* + PluginDialog + + + + 0 + 0 + 401 + 331 + + + + Plugin Information + + + + 6 + + + 8 + + + + + TextLabel + + + true + + + + + + + Qt::ElideNone + + + + 1 + + + + + + + + TextLabel + + + true + + + + + + + 6 + + + 0 + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + buttonBox + rejected() + PluginDialog + reject() + + + 154 + 307 + + + 401 + 280 + + + + + diff --git a/src/designer/src/lib/shared/plugindialog_p.h b/src/designer/src/lib/shared/plugindialog_p.h new file mode 100644 index 000000000..0027d6e9f --- /dev/null +++ b/src/designer/src/lib/shared/plugindialog_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef PLUGINDIALOG_H +#define PLUGINDIALOG_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "ui_plugindialog.h" + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +class PluginDialog : public QDialog +{ + Q_OBJECT +public: + explicit PluginDialog(QDesignerFormEditorInterface *core, QWidget *parent = 0); + +private slots: + void updateCustomWidgetPlugins(); + +private: + void populateTreeWidget(); + QIcon pluginIcon(const QIcon &icon); + QTreeWidgetItem* setTopLevelItem(const QString &itemName); + QTreeWidgetItem* setPluginItem(QTreeWidgetItem *topLevelItem, + const QString &itemName, const QFont &font); + void setItem(QTreeWidgetItem *pluginItem, const QString &name, + const QString &toolTip, const QString &whatsThis, const QIcon &icon); + + QDesignerFormEditorInterface *m_core; + Ui::PluginDialog ui; + QIcon interfaceIcon; + QIcon featureIcon; +}; + +} + +QT_END_NAMESPACE + +#endif diff --git a/src/designer/src/lib/shared/pluginmanager.cpp b/src/designer/src/lib/shared/pluginmanager.cpp new file mode 100644 index 000000000..918fe7d07 --- /dev/null +++ b/src/designer/src/lib/shared/pluginmanager.cpp @@ -0,0 +1,786 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "pluginmanager_p.h" +#include "qdesigner_utils_p.h" +#include "qdesigner_qsettings_p.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static const char *uiElementC = "ui"; +static const char *languageAttributeC = "language"; +static const char *widgetElementC = "widget"; +static const char *displayNameAttributeC = "displayname"; +static const char *classAttributeC = "class"; +static const char *customwidgetElementC = "customwidget"; +static const char *extendsElementC = "extends"; +static const char *addPageMethodC = "addpagemethod"; +static const char *propertySpecsC = "propertyspecifications"; +static const char *stringPropertySpecC = "stringpropertyspecification"; +static const char *stringPropertyNameAttrC = "name"; +static const char *stringPropertyTypeAttrC = "type"; +static const char *stringPropertyNoTrAttrC = "notr"; +static const char *jambiLanguageC = "jambi"; + +enum { debugPluginManager = 0 }; + +/* Custom widgets: Loading custom widgets is a 2-step process: PluginManager + * scans for its plugins in the constructor. At this point, it might not be safe + * to immediately initialize the custom widgets it finds, because the rest of + * Designer is not initialized yet. + * Later on, in ensureInitialized(), the plugin instances (including static ones) + * are iterated and the custom widget plugins are initialized and added to internal + * list of custom widgets and parsed data. Should there be a parse error or a language + * mismatch, it kicks out the respective custom widget. The m_initialized flag + * is used to indicate the state. + * Later, someone might call registerNewPlugins(), which agains clears the flag via + * registerPlugin() and triggers the process again. + * Also note that Jambi fakes a custom widget collection that changes its contents + * every time the project is switched. So, custom widget plugins can actually + * disappear, and the custom widget list must be cleared and refilled in + * ensureInitialized() after registerNewPlugins. */ + +QT_BEGIN_NAMESPACE + +static QStringList unique(const QStringList &lst) +{ + const QSet s = QSet::fromList(lst); + return s.toList(); +} + +QStringList QDesignerPluginManager::defaultPluginPaths() +{ + QStringList result; + + const QStringList path_list = QCoreApplication::libraryPaths(); + + const QString designer = QLatin1String("designer"); + foreach (const QString &path, path_list) { + QString libPath = path; + libPath += QDir::separator(); + libPath += designer; + result.append(libPath); + } + + QString homeLibPath = QDir::homePath(); + homeLibPath += QDir::separator(); + homeLibPath += QLatin1String(".designer"); + homeLibPath += QDir::separator(); + homeLibPath += QLatin1String("plugins"); + + result.append(homeLibPath); + return result; +} + +// Figure out the language designer is running. ToDo: Introduce some +// Language name API to QDesignerLanguageExtension? + +static inline QString getDesignerLanguage(QDesignerFormEditorInterface *core) +{ + if (QDesignerLanguageExtension *lang = qt_extension(core->extensionManager(), core)) { + if (lang->uiExtension() == QLatin1String("jui")) + return QLatin1String(jambiLanguageC); + return QLatin1String("unknown"); + } + return QLatin1String("c++"); +} + +// ---------------- QDesignerCustomWidgetSharedData + +class QDesignerCustomWidgetSharedData : public QSharedData { +public: + // Type of a string property + typedef QPair StringPropertyType; + typedef QHash StringPropertyTypeMap; + + explicit QDesignerCustomWidgetSharedData(const QString &thePluginPath) : pluginPath(thePluginPath) {} + void clearXML(); + + QString pluginPath; + + QString xmlClassName; + QString xmlDisplayName; + QString xmlLanguage; + QString xmlAddPageMethod; + QString xmlExtends; + + StringPropertyTypeMap xmlStringPropertyTypeMap; +}; + +void QDesignerCustomWidgetSharedData::clearXML() +{ + xmlClassName.clear(); + xmlDisplayName.clear(); + xmlLanguage.clear(); + xmlAddPageMethod.clear(); + xmlExtends.clear(); + xmlStringPropertyTypeMap.clear(); +} + +// ---------------- QDesignerCustomWidgetData + +QDesignerCustomWidgetData::QDesignerCustomWidgetData(const QString &pluginPath) : + m_d(new QDesignerCustomWidgetSharedData(pluginPath)) +{ +} + +QDesignerCustomWidgetData::QDesignerCustomWidgetData(const QDesignerCustomWidgetData &o) : + m_d(o.m_d) +{ +} + +QDesignerCustomWidgetData& QDesignerCustomWidgetData::operator=(const QDesignerCustomWidgetData &o) +{ + m_d.operator=(o.m_d); + return *this; +} + +QDesignerCustomWidgetData::~QDesignerCustomWidgetData() +{ +} + +bool QDesignerCustomWidgetData::isNull() const +{ + return m_d->xmlClassName.isEmpty() || m_d->pluginPath.isEmpty(); +} + +QString QDesignerCustomWidgetData::xmlClassName() const +{ + return m_d->xmlClassName; +} + +QString QDesignerCustomWidgetData::xmlLanguage() const +{ + return m_d->xmlLanguage; +} + +QString QDesignerCustomWidgetData::xmlAddPageMethod() const +{ + return m_d->xmlAddPageMethod; +} + +QString QDesignerCustomWidgetData::xmlExtends() const +{ + return m_d->xmlExtends; +} + +QString QDesignerCustomWidgetData::xmlDisplayName() const +{ + return m_d->xmlDisplayName; +} + +QString QDesignerCustomWidgetData::pluginPath() const +{ + return m_d->pluginPath; +} + +bool QDesignerCustomWidgetData::xmlStringPropertyType(const QString &name, StringPropertyType *type) const +{ + QDesignerCustomWidgetSharedData::StringPropertyTypeMap::const_iterator it = m_d->xmlStringPropertyTypeMap.constFind(name); + if (it == m_d->xmlStringPropertyTypeMap.constEnd()) { + *type = StringPropertyType(qdesigner_internal::ValidationRichText, true); + return false; + } + *type = it.value(); + return true; +} + +// Wind a QXmlStreamReader until it finds an element. Returns index or one of FindResult +enum FindResult { FindError = -2, ElementNotFound = -1 }; + +static int findElement(const QStringList &desiredElts, QXmlStreamReader &sr) +{ + while (true) { + switch(sr.readNext()) { + case QXmlStreamReader::EndDocument: + return ElementNotFound; + case QXmlStreamReader::Invalid: + return FindError; + case QXmlStreamReader::StartElement: { + const int index = desiredElts.indexOf(sr.name().toString().toLower()); + if (index >= 0) + return index; + } + break; + default: + break; + } + } + return FindError; +} + +static inline QString msgXmlError(const QString &name, const QString &errorMessage) +{ + return QDesignerPluginManager::tr("An XML error was encountered when parsing the XML of the custom widget %1: %2").arg(name, errorMessage); +} + +static inline QString msgAttributeMissing(const QString &name) +{ + return QDesignerPluginManager::tr("A required attribute ('%1') is missing.").arg(name); +} + +static qdesigner_internal::TextPropertyValidationMode typeStringToType(const QString &v, bool *ok) +{ + *ok = true; + if (v == QLatin1String("multiline")) + return qdesigner_internal::ValidationMultiLine; + if (v == QLatin1String("richtext")) + return qdesigner_internal::ValidationRichText; + if (v == QLatin1String("stylesheet")) + return qdesigner_internal::ValidationStyleSheet; + if (v == QLatin1String("singleline")) + return qdesigner_internal::ValidationSingleLine; + if (v == QLatin1String("objectname")) + return qdesigner_internal::ValidationObjectName; + if (v == QLatin1String("objectnamescope")) + return qdesigner_internal::ValidationObjectNameScope; + if (v == QLatin1String("url")) + return qdesigner_internal::ValidationURL; + *ok = false; + return qdesigner_internal::ValidationRichText; +} + +static bool parsePropertySpecs(QXmlStreamReader &sr, + QDesignerCustomWidgetSharedData::StringPropertyTypeMap *rc, + QString *errorMessage) +{ + const QString propertySpecs = QLatin1String(propertySpecsC); + const QString stringPropertySpec = QLatin1String(stringPropertySpecC); + const QString stringPropertyTypeAttr = QLatin1String(stringPropertyTypeAttrC); + const QString stringPropertyNoTrAttr = QLatin1String(stringPropertyNoTrAttrC); + const QString stringPropertyNameAttr = QLatin1String(stringPropertyNameAttrC); + + while (!sr.atEnd()) { + switch(sr.readNext()) { + case QXmlStreamReader::StartElement: { + if (sr.name() != stringPropertySpec) { + *errorMessage = QDesignerPluginManager::tr("An invalid property specification ('%1') was encountered. Supported types: %2").arg(sr.name().toString(), stringPropertySpec); + return false; + } + const QXmlStreamAttributes atts = sr.attributes(); + const QString name = atts.value(stringPropertyNameAttr).toString(); + const QString type = atts.value(stringPropertyTypeAttr).toString(); + const QString notrS = atts.value(stringPropertyNoTrAttr).toString(); //Optional + + if (type.isEmpty()) { + *errorMessage = msgAttributeMissing(stringPropertyTypeAttr); + return false; + } + if (name.isEmpty()) { + *errorMessage = msgAttributeMissing(stringPropertyNameAttr); + return false; + } + bool typeOk; + const bool noTr = notrS == QLatin1String("true") || notrS == QLatin1String("1"); + QDesignerCustomWidgetSharedData::StringPropertyType v(typeStringToType(type, &typeOk), !noTr); + if (!typeOk) { + *errorMessage = QDesignerPluginManager::tr("'%1' is not a valid string property specification.").arg(type); + return false; + } + rc->insert(name, v); + } + break; + case QXmlStreamReader::EndElement: // Outer + if (sr.name() == propertySpecs) + return true; + default: + break; + } + } + return true; +} + +QDesignerCustomWidgetData::ParseResult + QDesignerCustomWidgetData::parseXml(const QString &xml, const QString &name, QString *errorMessage) +{ + if (debugPluginManager) + qDebug() << Q_FUNC_INFO << name; + + QDesignerCustomWidgetSharedData &data = *m_d; + data.clearXML(); + + QXmlStreamReader sr(xml); + + bool foundUI = false; + bool foundWidget = false; + ParseResult rc = ParseOk; + // Parse for the (optional) or the first element + QStringList elements; + elements.push_back(QLatin1String(uiElementC)); + elements.push_back(QLatin1String(widgetElementC)); + for (int i = 0; i < 2 && !foundWidget; i++) { + switch (findElement(elements, sr)) { + case FindError: + *errorMessage = msgXmlError(name, sr.errorString()); + return ParseError; + case ElementNotFound: + *errorMessage = QDesignerPluginManager::tr("The XML of the custom widget %1 does not contain any of the elements or .").arg(name); + return ParseError; + case 0: { // + const QXmlStreamAttributes attributes = sr.attributes(); + data.xmlLanguage = attributes.value(QLatin1String(languageAttributeC)).toString(); + data.xmlDisplayName = attributes.value(QLatin1String(displayNameAttributeC)).toString(); + foundUI = true; + } + break; + case 1: // : Do some sanity checks + data.xmlClassName = sr.attributes().value(QLatin1String(classAttributeC)).toString(); + if (data.xmlClassName.isEmpty()) { + *errorMessage = QDesignerPluginManager::tr("The class attribute for the class %1 is missing.").arg(name); + rc = ParseWarning; + } else { + if (data.xmlClassName != name) { + *errorMessage = QDesignerPluginManager::tr("The class attribute for the class %1 does not match the class name %2.").arg(data.xmlClassName, name); + rc = ParseWarning; + } + } + foundWidget = true; + break; + } + } + // Parse out the element which might be present if was there + if (!foundUI) + return rc; + elements.clear(); + elements.push_back(QLatin1String(customwidgetElementC)); + switch (findElement(elements, sr)) { + case FindError: + *errorMessage = msgXmlError(name, sr.errorString()); + return ParseError; + case ElementNotFound: + return rc; + default: + break; + } + // Find , , + elements.clear(); + elements.push_back(QLatin1String(extendsElementC)); + elements.push_back(QLatin1String(addPageMethodC)); + elements.push_back(QLatin1String(propertySpecsC)); + while (true) { + switch (findElement(elements, sr)) { + case FindError: + *errorMessage = msgXmlError(name, sr.errorString()); + return ParseError; + case ElementNotFound: + return rc; + case 0: // + data.xmlExtends = sr.readElementText(); + if (sr.tokenType() != QXmlStreamReader::EndElement) { + *errorMessage = msgXmlError(name, sr.errorString()); + return ParseError; + } + break; + case 1: // + data.xmlAddPageMethod = sr.readElementText(); + if (sr.tokenType() != QXmlStreamReader::EndElement) { + *errorMessage = msgXmlError(name, sr.errorString()); + return ParseError; + } + break; + case 2: // + if (!parsePropertySpecs(sr, &m_d->xmlStringPropertyTypeMap, errorMessage)) { + *errorMessage = msgXmlError(name, *errorMessage); + return ParseError; + } + break; + } + } + return rc; +} + +// ---------------- QDesignerPluginManagerPrivate + +class QDesignerPluginManagerPrivate { + public: + typedef QPair ClassNamePropertyNameKey; + + QDesignerPluginManagerPrivate(QDesignerFormEditorInterface *core); + + void clearCustomWidgets(); + bool addCustomWidget(QDesignerCustomWidgetInterface *c, + const QString &pluginPath, + const QString &designerLanguage); + void addCustomWidgets(const QObject *o, + const QString &pluginPath, + const QString &designerLanguage); + + QDesignerFormEditorInterface *m_core; + QStringList m_pluginPaths; + QStringList m_registeredPlugins; + // TODO: QPluginLoader also caches invalid plugins -> This seems to be dead code + QStringList m_disabledPlugins; + + typedef QMap FailedPluginMap; + FailedPluginMap m_failedPlugins; + + // Synced lists of custom widgets and their data. Note that the list + // must be ordered for collections to appear in order. + QList m_customWidgets; + QList m_customWidgetData; + + QStringList defaultPluginPaths() const; + + bool m_initialized; +}; + +QDesignerPluginManagerPrivate::QDesignerPluginManagerPrivate(QDesignerFormEditorInterface *core) : + m_core(core), + m_initialized(false) +{ +} + +void QDesignerPluginManagerPrivate::clearCustomWidgets() +{ + m_customWidgets.clear(); + m_customWidgetData.clear(); +} + +// Add a custom widget to the list if it parses correctly +// and is of the right language +bool QDesignerPluginManagerPrivate::addCustomWidget(QDesignerCustomWidgetInterface *c, + const QString &pluginPath, + const QString &designerLanguage) +{ + if (debugPluginManager) + qDebug() << Q_FUNC_INFO << c->name(); + + if (!c->isInitialized()) + c->initialize(m_core); + // Parse the XML even if the plugin is initialized as Jambi might play tricks here + QDesignerCustomWidgetData data(pluginPath); + const QString domXml = c->domXml(); + if (!domXml.isEmpty()) { // Legacy: Empty XML means: Do not show up in widget box. + QString errorMessage; + const QDesignerCustomWidgetData::ParseResult pr = data.parseXml(domXml, c->name(), &errorMessage); + switch (pr) { + case QDesignerCustomWidgetData::ParseOk: + break; + case QDesignerCustomWidgetData::ParseWarning: + qdesigner_internal::designerWarning(errorMessage); + break; + case QDesignerCustomWidgetData::ParseError: + qdesigner_internal::designerWarning(errorMessage); + return false; + } + // Does the language match? + const QString pluginLanguage = data.xmlLanguage(); + if (!pluginLanguage.isEmpty() && pluginLanguage.compare(designerLanguage, Qt::CaseInsensitive)) + return false; + } + m_customWidgets.push_back(c); + m_customWidgetData.push_back(data); + return true; +} + +// Check the plugin interface for either a custom widget or a collection and +// add all contained custom widgets. +void QDesignerPluginManagerPrivate::addCustomWidgets(const QObject *o, + const QString &pluginPath, + const QString &designerLanguage) +{ + if (QDesignerCustomWidgetInterface *c = qobject_cast(o)) { + addCustomWidget(c, pluginPath, designerLanguage); + return; + } + if (const QDesignerCustomWidgetCollectionInterface *coll = qobject_cast(o)) { + foreach(QDesignerCustomWidgetInterface *c, coll->customWidgets()) + addCustomWidget(c, pluginPath, designerLanguage); + } +} + + +// ---------------- QDesignerPluginManager +// As of 4.4, the header will be distributed with the Eclipse plugin. + +QDesignerPluginManager::QDesignerPluginManager(QDesignerFormEditorInterface *core) : + QObject(core), + m_d(new QDesignerPluginManagerPrivate(core)) +{ + m_d->m_pluginPaths = defaultPluginPaths(); + const QSettings settings(qApp->organizationName(), QDesignerQSettings::settingsApplicationName()); + m_d->m_disabledPlugins = unique(settings.value(QLatin1String("PluginManager/DisabledPlugins")).toStringList()); + + // Register plugins + updateRegisteredPlugins(); + + if (debugPluginManager) + qDebug() << "QDesignerPluginManager::disabled: " << m_d->m_disabledPlugins << " static " << m_d->m_customWidgets.size(); +} + +QDesignerPluginManager::~QDesignerPluginManager() +{ + syncSettings(); + delete m_d; +} + +QDesignerFormEditorInterface *QDesignerPluginManager::core() const +{ + return m_d->m_core; +} + +QStringList QDesignerPluginManager::findPlugins(const QString &path) +{ + if (debugPluginManager) + qDebug() << Q_FUNC_INFO << path; + const QDir dir(path); + if (!dir.exists()) + return QStringList(); + + const QFileInfoList infoList = dir.entryInfoList(QDir::Files); + if (infoList.empty()) + return QStringList(); + + // Load symbolic links but make sure all file names are unique as not + // to fall for something like 'libplugin.so.1 -> libplugin.so' + QStringList result; + const QFileInfoList::const_iterator icend = infoList.constEnd(); + for (QFileInfoList::const_iterator it = infoList.constBegin(); it != icend; ++it) { + QString fileName; + if (it->isSymLink()) { + const QFileInfo linkTarget = QFileInfo(it->symLinkTarget()); + if (linkTarget.exists() && linkTarget.isFile()) + fileName = linkTarget.absoluteFilePath(); + } else { + fileName = it->absoluteFilePath(); + } + if (!fileName.isEmpty() && QLibrary::isLibrary(fileName) && !result.contains(fileName)) + result += fileName; + } + return result; +} + +void QDesignerPluginManager::setDisabledPlugins(const QStringList &disabled_plugins) +{ + m_d->m_disabledPlugins = disabled_plugins; + updateRegisteredPlugins(); +} + +void QDesignerPluginManager::setPluginPaths(const QStringList &plugin_paths) +{ + m_d->m_pluginPaths = plugin_paths; + updateRegisteredPlugins(); +} + +QStringList QDesignerPluginManager::disabledPlugins() const +{ + return m_d->m_disabledPlugins; +} + +QStringList QDesignerPluginManager::failedPlugins() const +{ + return m_d->m_failedPlugins.keys(); +} + +QString QDesignerPluginManager::failureReason(const QString &pluginName) const +{ + return m_d->m_failedPlugins.value(pluginName); +} + +QStringList QDesignerPluginManager::registeredPlugins() const +{ + return m_d->m_registeredPlugins; +} + +QStringList QDesignerPluginManager::pluginPaths() const +{ + return m_d->m_pluginPaths; +} + +QObject *QDesignerPluginManager::instance(const QString &plugin) const +{ + if (m_d->m_disabledPlugins.contains(plugin)) + return 0; + + QPluginLoader loader(plugin); + return loader.instance(); +} + +void QDesignerPluginManager::updateRegisteredPlugins() +{ + if (debugPluginManager) + qDebug() << Q_FUNC_INFO; + m_d->m_registeredPlugins.clear(); + foreach (const QString &path, m_d->m_pluginPaths) + registerPath(path); +} + +bool QDesignerPluginManager::registerNewPlugins() +{ + if (debugPluginManager) + qDebug() << Q_FUNC_INFO; + + const int before = m_d->m_registeredPlugins.size(); + foreach (const QString &path, m_d->m_pluginPaths) + registerPath(path); + const bool newPluginsFound = m_d->m_registeredPlugins.size() > before; + // We force a re-initialize as Jambi collection might return + // different widget lists when switching projects. + m_d->m_initialized = false; + ensureInitialized(); + + return newPluginsFound; +} + +void QDesignerPluginManager::registerPath(const QString &path) +{ + if (debugPluginManager) + qDebug() << Q_FUNC_INFO << path; + QStringList candidates = findPlugins(path); + + foreach (const QString &plugin, candidates) + registerPlugin(plugin); +} + +void QDesignerPluginManager::registerPlugin(const QString &plugin) +{ + if (debugPluginManager) + qDebug() << Q_FUNC_INFO << plugin; + if (m_d->m_disabledPlugins.contains(plugin)) + return; + if (m_d->m_registeredPlugins.contains(plugin)) + return; + + QPluginLoader loader(plugin); + if (loader.isLoaded() || loader.load()) { + m_d->m_registeredPlugins += plugin; + QDesignerPluginManagerPrivate::FailedPluginMap::iterator fit = m_d->m_failedPlugins.find(plugin); + if (fit != m_d->m_failedPlugins.end()) + m_d->m_failedPlugins.erase(fit); + return; + } + + const QString errorMessage = loader.errorString(); + m_d->m_failedPlugins.insert(plugin, errorMessage); +} + + + +bool QDesignerPluginManager::syncSettings() +{ + QSettings settings(qApp->organizationName(), QDesignerQSettings::settingsApplicationName()); + settings.beginGroup(QLatin1String("PluginManager")); + settings.setValue(QLatin1String("DisabledPlugins"), m_d->m_disabledPlugins); + settings.endGroup(); + return settings.status() == QSettings::NoError; +} + +void QDesignerPluginManager::ensureInitialized() +{ + if (debugPluginManager) + qDebug() << Q_FUNC_INFO << m_d->m_initialized << m_d->m_customWidgets.size(); + + if (m_d->m_initialized) + return; + + const QString designerLanguage = getDesignerLanguage(m_d->m_core); + + m_d->clearCustomWidgets(); + // Add the static custom widgets + const QObjectList staticPluginObjects = QPluginLoader::staticInstances(); + if (!staticPluginObjects.empty()) { + const QString staticPluginPath = QCoreApplication::applicationFilePath(); + foreach(QObject *o, staticPluginObjects) + m_d->addCustomWidgets(o, staticPluginPath, designerLanguage); + } + foreach (const QString &plugin, m_d->m_registeredPlugins) + if (QObject *o = instance(plugin)) + m_d->addCustomWidgets(o, plugin, designerLanguage); + + m_d->m_initialized = true; +} + +QDesignerPluginManager::CustomWidgetList QDesignerPluginManager::registeredCustomWidgets() const +{ + const_cast(this)->ensureInitialized(); + return m_d->m_customWidgets; +} + +QDesignerCustomWidgetData QDesignerPluginManager::customWidgetData(QDesignerCustomWidgetInterface *w) const +{ + const int index = m_d->m_customWidgets.indexOf(w); + if (index == -1) + return QDesignerCustomWidgetData(); + return m_d->m_customWidgetData.at(index); +} + +QDesignerCustomWidgetData QDesignerPluginManager::customWidgetData(const QString &name) const +{ + const int count = m_d->m_customWidgets.size(); + for (int i = 0; i < count; i++) + if (m_d->m_customWidgets.at(i)->name() == name) + return m_d->m_customWidgetData.at(i); + return QDesignerCustomWidgetData(); +} + +QObjectList QDesignerPluginManager::instances() const +{ + QStringList plugins = registeredPlugins(); + + QObjectList lst; + foreach (const QString &plugin, plugins) { + if (QObject *o = instance(plugin)) + lst.append(o); + } + + return lst; +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/pluginmanager_p.h b/src/designer/src/lib/shared/pluginmanager_p.h new file mode 100644 index 000000000..34aa3041d --- /dev/null +++ b/src/designer/src/lib/shared/pluginmanager_p.h @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef PLUGINMANAGER_H +#define PLUGINMANAGER_H + +#include "shared_global_p.h" +#include "shared_enums_p.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerCustomWidgetInterface; +class QDesignerPluginManagerPrivate; + +class QDesignerCustomWidgetSharedData; + +/* Information contained in the Dom XML of a custom widget. */ +class QDESIGNER_SHARED_EXPORT QDesignerCustomWidgetData { +public: + // StringPropertyType: validation mode and translatable flag. + typedef QPair StringPropertyType; + + explicit QDesignerCustomWidgetData(const QString &pluginPath = QString()); + + enum ParseResult { ParseOk, ParseWarning, ParseError }; + ParseResult parseXml(const QString &xml, const QString &name, QString *errorMessage); + + QDesignerCustomWidgetData(const QDesignerCustomWidgetData&); + QDesignerCustomWidgetData& operator=(const QDesignerCustomWidgetData&); + ~QDesignerCustomWidgetData(); + + bool isNull() const; + + QString pluginPath() const; + + // Data as parsed from the widget's domXML(). + QString xmlClassName() const; + // Optional. The language the plugin is supposed to be used with. + QString xmlLanguage() const; + // Optional. method used to add pages to a container with a container extension + QString xmlAddPageMethod() const; + // Optional. Base class + QString xmlExtends() const; + // Optional. The name to be used in the widget box. + QString xmlDisplayName() const; + // Type of a string property + bool xmlStringPropertyType(const QString &name, StringPropertyType *type) const; + +private: + QSharedDataPointer m_d; +}; + +class QDESIGNER_SHARED_EXPORT QDesignerPluginManager: public QObject +{ + Q_OBJECT +public: + typedef QList CustomWidgetList; + + explicit QDesignerPluginManager(QDesignerFormEditorInterface *core); + virtual ~QDesignerPluginManager(); + + QDesignerFormEditorInterface *core() const; + + QObject *instance(const QString &plugin) const; + + QStringList registeredPlugins() const; + + QStringList findPlugins(const QString &path); + + QStringList pluginPaths() const; + void setPluginPaths(const QStringList &plugin_paths); + + QStringList disabledPlugins() const; + void setDisabledPlugins(const QStringList &disabled_plugins); + + QStringList failedPlugins() const; + QString failureReason(const QString &pluginName) const; + + QObjectList instances() const; + + CustomWidgetList registeredCustomWidgets() const; + QDesignerCustomWidgetData customWidgetData(QDesignerCustomWidgetInterface *w) const; + QDesignerCustomWidgetData customWidgetData(const QString &className) const; + + bool registerNewPlugins(); + +public slots: + bool syncSettings(); + void ensureInitialized(); + +private: + void updateRegisteredPlugins(); + void registerPath(const QString &path); + void registerPlugin(const QString &plugin); + +private: + static QStringList defaultPluginPaths(); + + QDesignerPluginManagerPrivate *m_d; +}; + +QT_END_NAMESPACE + +#endif // PLUGINMANAGER_H diff --git a/src/designer/src/lib/shared/previewconfigurationwidget.cpp b/src/designer/src/lib/shared/previewconfigurationwidget.cpp new file mode 100644 index 000000000..2b4506a37 --- /dev/null +++ b/src/designer/src/lib/shared/previewconfigurationwidget.cpp @@ -0,0 +1,366 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/* It is possible to link the skins as resources into Designer by specifying: + * QVFB_ROOT=$$QT_SOURCE_TREE/tools/qvfb + * RESOURCES += $$QVFB_ROOT/ClamshellPhone.qrc $$QVFB_ROOT/TouchScreenPhone.qrc ... + * in lib/shared/shared.pri. However, this exceeds a limit of Visual Studio 6. */ + +#include "previewconfigurationwidget_p.h" +#include "ui_previewconfigurationwidget.h" +#include "previewmanager_p.h" +#include "abstractsettings_p.h" +#include "shared_settings_p.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static const char *skinResourcePathC = ":/skins/"; + +QT_BEGIN_NAMESPACE + +static const char *skinExtensionC = "skin"; + +// Pair of skin name, path +typedef QPair SkinNamePath; +typedef QList Skins; +enum { SkinComboNoneIndex = 0 }; + +// find default skins (resources) +static const Skins &defaultSkins() { + static Skins rc; + if (rc.empty()) { + const QString skinPath = QLatin1String(skinResourcePathC); + QString pattern = QLatin1String("*."); + pattern += QLatin1String(skinExtensionC); + const QDir dir(skinPath, pattern); + const QFileInfoList list = dir.entryInfoList(QDir::Dirs|QDir::NoDotAndDotDot, QDir::Name); + if (list.empty()) + return rc; + const QFileInfoList::const_iterator lcend = list.constEnd(); + for (QFileInfoList::const_iterator it = list.constBegin(); it != lcend; ++it) + rc.push_back(SkinNamePath(it->baseName(), it->filePath())); + } + return rc; +} + +namespace qdesigner_internal { + +// ------------- PreviewConfigurationWidgetPrivate +class PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate { +public: + PreviewConfigurationWidgetPrivate(QDesignerFormEditorInterface *core, QGroupBox *g); + + void slotEditAppStyleSheet(); + void slotDeleteSkinEntry(); + void slotSkinChanged(int index); + + void retrieveSettings(); + void storeSettings() const; + + QAbstractButton *appStyleSheetChangeButton() const { return m_ui.m_appStyleSheetChangeButton; } + QAbstractButton *skinRemoveButton() const { return m_ui.m_skinRemoveButton; } + QComboBox *skinCombo() const { return m_ui.m_skinCombo; } + + QDesignerFormEditorInterface *m_core; + +private: + PreviewConfiguration previewConfiguration() const; + void setPreviewConfiguration(const PreviewConfiguration &pc); + + QStringList userSkins() const; + void addUserSkins(const QStringList &files); + bool canRemoveSkin(int index) const; + int browseSkin(); + + const QString m_defaultStyle; + QGroupBox *m_parent; + Ui::PreviewConfigurationWidget m_ui; + + int m_firstUserSkinIndex; + int m_browseSkinIndex; + int m_lastSkinIndex; // required in case browse fails +}; + +PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::PreviewConfigurationWidgetPrivate( + QDesignerFormEditorInterface *core, QGroupBox *g) : + m_core(core), + m_defaultStyle(PreviewConfigurationWidget::tr("Default")), + m_parent(g), + m_firstUserSkinIndex(0), + m_browseSkinIndex(0), + m_lastSkinIndex(0) +{ + m_ui.setupUi(g); + // styles + m_ui.m_styleCombo->setEditable(false); + QStringList styleItems(m_defaultStyle); + styleItems += QStyleFactory::keys(); + m_ui.m_styleCombo->addItems(styleItems); + + // sheet + m_ui.m_appStyleSheetLineEdit->setTextPropertyValidationMode(qdesigner_internal::ValidationStyleSheet); + m_ui.m_appStyleSheetClearButton->setIcon(qdesigner_internal::createIconSet(QString::fromUtf8("resetproperty.png"))); + QObject::connect(m_ui.m_appStyleSheetClearButton, SIGNAL(clicked()), m_ui.m_appStyleSheetLineEdit, SLOT(clear())); + + m_ui.m_skinRemoveButton->setIcon(qdesigner_internal::createIconSet(QString::fromUtf8("editdelete.png"))); + // skins: find default skins (resources) + m_ui.m_skinRemoveButton->setEnabled(false); + Skins skins = defaultSkins(); + skins.push_front(SkinNamePath(PreviewConfigurationWidget::tr("None"), QString())); + + const Skins::const_iterator scend = skins.constEnd(); + for (Skins::const_iterator it = skins.constBegin(); it != scend; ++it) + m_ui.m_skinCombo->addItem (it->first, QVariant(it->second)); + m_browseSkinIndex = m_firstUserSkinIndex = skins.size(); + m_ui.m_skinCombo->addItem(PreviewConfigurationWidget::tr("Browse..."), QString()); + + m_ui.m_skinCombo->setMaxVisibleItems (qMax(15, 2 * m_browseSkinIndex)); + m_ui.m_skinCombo->setEditable(false); + + retrieveSettings(); +} + +bool PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::canRemoveSkin(int index) const +{ + return index >= m_firstUserSkinIndex && index != m_browseSkinIndex; +} + +QStringList PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::userSkins() const +{ + QStringList rc; + for (int i = m_firstUserSkinIndex; i < m_browseSkinIndex; i++) + rc.push_back(m_ui.m_skinCombo->itemData(i).toString()); + return rc; +} + +void PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::addUserSkins(const QStringList &files) +{ + if (files.empty()) + return; + const QStringList ::const_iterator fcend = files.constEnd(); + for (QStringList::const_iterator it = files.constBegin(); it != fcend; ++it) { + const QFileInfo fi(*it); + if (fi.isDir() && fi.isReadable()) { + m_ui.m_skinCombo->insertItem(m_browseSkinIndex++, fi.baseName(), QVariant(*it)); + } else { + qWarning() << "Unable to access the skin directory '" << *it << "'."; + } + } +} + +PreviewConfiguration PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::previewConfiguration() const +{ + PreviewConfiguration rc; + QString style = m_ui.m_styleCombo->currentText(); + if (style == m_defaultStyle) + style.clear(); + const QString applicationStyleSheet = m_ui.m_appStyleSheetLineEdit->text(); + // Figure out skin. 0 is None by definition.. + const int skinIndex = m_ui.m_skinCombo->currentIndex(); + QString deviceSkin; + if (skinIndex != SkinComboNoneIndex && skinIndex != m_browseSkinIndex) + deviceSkin = m_ui.m_skinCombo->itemData(skinIndex).toString(); + + return PreviewConfiguration(style, applicationStyleSheet, deviceSkin); +} + +void PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::setPreviewConfiguration(const PreviewConfiguration &pc) +{ + int styleIndex = m_ui.m_styleCombo->findText(pc.style()); + if (styleIndex == -1) + styleIndex = m_ui.m_styleCombo->findText(m_defaultStyle); + m_ui.m_styleCombo->setCurrentIndex(styleIndex); + m_ui.m_appStyleSheetLineEdit->setText(pc.applicationStyleSheet()); + // find skin by file name. 0 is "none" + const QString deviceSkin = pc.deviceSkin(); + int skinIndex = deviceSkin.isEmpty() ? 0 : m_ui.m_skinCombo->findData(QVariant(deviceSkin)); + if (skinIndex == -1) { + qWarning() << "Unable to find skin '" << deviceSkin << "'."; + skinIndex = 0; + } + m_ui.m_skinCombo->setCurrentIndex(skinIndex); +} + +void PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::slotEditAppStyleSheet() +{ + StyleSheetEditorDialog dlg(m_core, m_parent, StyleSheetEditorDialog::ModeGlobal); + dlg.setText(m_ui.m_appStyleSheetLineEdit->text()); + if (dlg.exec() == QDialog::Accepted) + m_ui.m_appStyleSheetLineEdit->setText(dlg.text()); +} + +void PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::slotDeleteSkinEntry() +{ + const int index = m_ui.m_skinCombo->currentIndex(); + if (canRemoveSkin(index)) { + m_ui.m_skinCombo->setCurrentIndex(SkinComboNoneIndex); + m_ui.m_skinCombo->removeItem(index); + m_browseSkinIndex--; + } +} + +void PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::slotSkinChanged(int index) +{ + if (index == m_browseSkinIndex) { + m_ui.m_skinCombo->setCurrentIndex(browseSkin()); + } else { + m_lastSkinIndex = index; + m_ui.m_skinRemoveButton->setEnabled(canRemoveSkin(index)); + m_ui.m_skinCombo->setToolTip(index != SkinComboNoneIndex ? m_ui.m_skinCombo->itemData(index).toString() : QString()); + } +} + +void PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::retrieveSettings() +{ + QDesignerSharedSettings settings(m_core); + m_parent->setChecked(settings.isCustomPreviewConfigurationEnabled()); + setPreviewConfiguration(settings.customPreviewConfiguration()); + addUserSkins(settings.userDeviceSkins()); +} + +void PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::storeSettings() const +{ + QDesignerSharedSettings settings(m_core); + settings.setCustomPreviewConfigurationEnabled(m_parent->isChecked()); + settings.setCustomPreviewConfiguration(previewConfiguration()); + settings.setUserDeviceSkins(userSkins()); +} + +int PreviewConfigurationWidget::PreviewConfigurationWidgetPrivate::browseSkin() +{ + QFileDialog dlg(m_parent); + dlg.setFileMode(QFileDialog::DirectoryOnly); + const QString title = tr("Load Custom Device Skin"); + dlg.setWindowTitle(title); + dlg.setFilter(tr("All QVFB Skins (*.%1)").arg(QLatin1String(skinExtensionC))); + + int rc = m_lastSkinIndex; + do { + if (!dlg.exec()) + break; + + const QStringList directories = dlg.selectedFiles(); + if (directories.size() != 1) + break; + + // check: 1) name already there + const QString directory = directories.front(); + const QString name = QFileInfo(directory).baseName(); + const int existingIndex = m_ui.m_skinCombo->findText(name); + if (existingIndex != -1 && existingIndex != SkinComboNoneIndex && existingIndex != m_browseSkinIndex) { + const QString msgTitle = tr("%1 - Duplicate Skin").arg(title); + const QString msg = tr("The skin '%1' already exists.").arg(name); + QMessageBox::information(m_parent, msgTitle, msg); + break; + } + // check: 2) can read + DeviceSkinParameters parameters; + QString readError; + if (parameters.read(directory, DeviceSkinParameters::ReadSizeOnly, &readError)) { + const QString name = QFileInfo(directory).baseName(); + m_ui.m_skinCombo->insertItem(m_browseSkinIndex, name, QVariant(directory)); + rc = m_browseSkinIndex++; + + break; + } else { + const QString msgTitle = tr("%1 - Error").arg(title); + const QString msg = tr("%1 is not a valid skin directory:\n%2").arg(directory).arg(readError); + QMessageBox::warning (m_parent, msgTitle, msg); + } + } while (true); + return rc; +} + +// ------------- PreviewConfigurationWidget +PreviewConfigurationWidget::PreviewConfigurationWidget(QDesignerFormEditorInterface *core, + QWidget *parent) : + QGroupBox(parent), + m_impl(new PreviewConfigurationWidgetPrivate(core, this)) +{ + connect(m_impl->appStyleSheetChangeButton(), SIGNAL(clicked()), this, SLOT(slotEditAppStyleSheet())); + connect(m_impl->skinRemoveButton(), SIGNAL(clicked()), this, SLOT(slotDeleteSkinEntry())); + connect(m_impl->skinCombo(), SIGNAL(currentIndexChanged(int)), this, SLOT(slotSkinChanged(int))); + + m_impl->retrieveSettings(); +} + +PreviewConfigurationWidget::~PreviewConfigurationWidget() +{ + delete m_impl; +} + +void PreviewConfigurationWidget::saveState() +{ + m_impl->storeSettings(); +} + +void PreviewConfigurationWidget::slotEditAppStyleSheet() +{ + m_impl->slotEditAppStyleSheet(); +} + +void PreviewConfigurationWidget::slotDeleteSkinEntry() +{ + m_impl->slotDeleteSkinEntry(); +} + +void PreviewConfigurationWidget::slotSkinChanged(int index) +{ + m_impl->slotSkinChanged(index); +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/previewconfigurationwidget.ui b/src/designer/src/lib/shared/previewconfigurationwidget.ui new file mode 100644 index 000000000..2f18766ff --- /dev/null +++ b/src/designer/src/lib/shared/previewconfigurationwidget.ui @@ -0,0 +1,91 @@ + + PreviewConfigurationWidget + + + Form + + + Print/Preview Configuration + + + true + + + + + + Style + + + + + + + + + + Style sheet + + + + + + + + + + 149 + 0 + + + + + + + + ... + + + + + + + ... + + + + + + + + + Device skin + + + + + + + + + + + + ... + + + + + + + + + + qdesigner_internal::TextPropertyEditor + QLineEdit +
textpropertyeditor_p.h
+
+
+ + +
diff --git a/src/designer/src/lib/shared/previewconfigurationwidget_p.h b/src/designer/src/lib/shared/previewconfigurationwidget_p.h new file mode 100644 index 000000000..21ea1f197 --- /dev/null +++ b/src/designer/src/lib/shared/previewconfigurationwidget_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef PREVIEWCONFIGURATIONWIDGET_H +#define PREVIEWCONFIGURATIONWIDGET_H + +#include "shared_global_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerSettingsInterface; + +namespace qdesigner_internal { + +// ----------- PreviewConfigurationWidget: Widget to edit the preview configuration. + +class QDESIGNER_SHARED_EXPORT PreviewConfigurationWidget : public QGroupBox +{ + Q_OBJECT +public: + explicit PreviewConfigurationWidget(QDesignerFormEditorInterface *core, + QWidget *parent = 0); + virtual ~PreviewConfigurationWidget(); + void saveState(); + +private slots: + void slotEditAppStyleSheet(); + void slotDeleteSkinEntry(); + void slotSkinChanged(int); + +private: + class PreviewConfigurationWidgetPrivate; + PreviewConfigurationWidgetPrivate *m_impl; + + PreviewConfigurationWidget(const PreviewConfigurationWidget &other); + PreviewConfigurationWidget &operator =(const PreviewConfigurationWidget &other); +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // PREVIEWCONFIGURATIONWIDGET_H diff --git a/src/designer/src/lib/shared/previewmanager.cpp b/src/designer/src/lib/shared/previewmanager.cpp new file mode 100644 index 000000000..3857b7864 --- /dev/null +++ b/src/designer/src/lib/shared/previewmanager.cpp @@ -0,0 +1,943 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractsettings_p.h" +#include "previewmanager_p.h" +#include "qdesigner_formbuilder_p.h" +#include "shared_settings_p.h" +#include "shared_settings_p.h" +#include "zoomwidget_p.h" +#include "formwindowbase_p.h" +#include "widgetfactory_p.h" + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static inline int compare(const qdesigner_internal::PreviewConfiguration &pc1, const qdesigner_internal::PreviewConfiguration &pc2) +{ + int rc = pc1.style().compare(pc2.style()); + if (rc) + return rc; + rc = pc1.applicationStyleSheet().compare(pc2.applicationStyleSheet()); + if (rc) + return rc; + return pc1.deviceSkin().compare(pc2.deviceSkin()); +} + +namespace { + // ------ PreviewData (data associated with a preview window) + struct PreviewData { + PreviewData(const QPointer &widget, const QDesignerFormWindowInterface *formWindow, const qdesigner_internal::PreviewConfiguration &pc); + QPointer m_widget; + const QDesignerFormWindowInterface *m_formWindow; + qdesigner_internal::PreviewConfiguration m_configuration; + }; + + PreviewData::PreviewData(const QPointer& widget, + const QDesignerFormWindowInterface *formWindow, + const qdesigner_internal::PreviewConfiguration &pc) : + m_widget(widget), + m_formWindow(formWindow), + m_configuration(pc) + { + } +} + +namespace qdesigner_internal { + +/* In designer, we have the situation that laid-out maincontainers have + * a geometry set (which might differ from their sizeHint()). The QGraphicsItem + * should return that in its size hint, else such cases won't work */ + +class DesignerZoomProxyWidget : public ZoomProxyWidget { + Q_DISABLE_COPY(DesignerZoomProxyWidget) +public: + DesignerZoomProxyWidget(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0); +protected: + virtual QSizeF sizeHint(Qt::SizeHint which, const QSizeF & constraint = QSizeF() ) const; +}; + +DesignerZoomProxyWidget::DesignerZoomProxyWidget(QGraphicsItem *parent, Qt::WindowFlags wFlags) : + ZoomProxyWidget(parent, wFlags) +{ +} + +QSizeF DesignerZoomProxyWidget::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const +{ + if (const QWidget *w = widget()) + return QSizeF(w->size()); + return ZoomProxyWidget::sizeHint(which, constraint); +} + +// DesignerZoomWidget which returns DesignerZoomProxyWidget in its factory function +class DesignerZoomWidget : public ZoomWidget { + Q_DISABLE_COPY(DesignerZoomWidget) +public: + DesignerZoomWidget(QWidget *parent = 0); +private: + virtual QGraphicsProxyWidget *createProxyWidget(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0) const; +}; + +DesignerZoomWidget::DesignerZoomWidget(QWidget *parent) : + ZoomWidget(parent) +{ +} + +QGraphicsProxyWidget *DesignerZoomWidget::createProxyWidget(QGraphicsItem *parent, Qt::WindowFlags wFlags) const +{ + return new DesignerZoomProxyWidget(parent, wFlags); +} + +// PreviewDeviceSkin: Forwards the key events to the window and +// provides context menu with rotation options. Derived class +// can apply additional transformations to the skin. + +class PreviewDeviceSkin : public DeviceSkin +{ + Q_OBJECT +public: + enum Direction { DirectionUp, DirectionLeft, DirectionRight }; + + explicit PreviewDeviceSkin(const DeviceSkinParameters ¶meters, QWidget *parent); + virtual void setPreview(QWidget *w); + QSize screenSize() const { return m_screenSize; } + +private slots: + void slotSkinKeyPressEvent(int code, const QString& text, bool autorep); + void slotSkinKeyReleaseEvent(int code, const QString& text, bool autorep); + void slotPopupMenu(); + +protected: + virtual void populateContextMenu(QMenu *) {} + +private slots: + void slotDirection(QAction *); + +protected: + // Fit the widget in case the orientation changes (transposing screensize) + virtual void fitWidget(const QSize &size); + // Calculate the complete transformation for the skin + // (base class implementation provides rotation). + virtual QMatrix skinTransform() const; + +private: + const QSize m_screenSize; + Direction m_direction; + + QAction *m_directionUpAction; + QAction *m_directionLeftAction; + QAction *m_directionRightAction; + QAction *m_closeAction; +}; + +PreviewDeviceSkin::PreviewDeviceSkin(const DeviceSkinParameters ¶meters, QWidget *parent) : + DeviceSkin(parameters, parent), + m_screenSize(parameters.screenSize()), + m_direction(DirectionUp), + m_directionUpAction(0), + m_directionLeftAction(0), + m_directionRightAction(0), + m_closeAction(0) +{ + connect(this, SIGNAL(skinKeyPressEvent(int,QString,bool)), + this, SLOT(slotSkinKeyPressEvent(int,QString,bool))); + connect(this, SIGNAL(skinKeyReleaseEvent(int,QString,bool)), + this, SLOT(slotSkinKeyReleaseEvent(int,QString,bool))); + connect(this, SIGNAL(popupMenu()), this, SLOT(slotPopupMenu())); +} + +void PreviewDeviceSkin::setPreview(QWidget *formWidget) +{ + formWidget->setFixedSize(m_screenSize); + formWidget->setParent(this, Qt::SubWindow); + formWidget->setAutoFillBackground(true); + setView(formWidget); +} + +void PreviewDeviceSkin::slotSkinKeyPressEvent(int code, const QString& text, bool autorep) +{ + if (QWidget *focusWidget = QApplication::focusWidget()) { + QKeyEvent e(QEvent::KeyPress,code,0,text,autorep); + QApplication::sendEvent(focusWidget, &e); + } +} + +void PreviewDeviceSkin::slotSkinKeyReleaseEvent(int code, const QString& text, bool autorep) +{ + if (QWidget *focusWidget = QApplication::focusWidget()) { + QKeyEvent e(QEvent::KeyRelease,code,0,text,autorep); + QApplication::sendEvent(focusWidget, &e); + } +} + +// Create a checkable action with integer data and +// set it checked if it matches the currentState. +static inline QAction + *createCheckableActionIntData(const QString &label, + int actionValue, int currentState, + QActionGroup *ag, QObject *parent) +{ + QAction *a = new QAction(label, parent); + a->setData(actionValue); + a->setCheckable(true); + if (actionValue == currentState) + a->setChecked(true); + ag->addAction(a); + return a; +} + +void PreviewDeviceSkin::slotPopupMenu() +{ + QMenu menu(this); + // Create actions + if (!m_directionUpAction) { + QActionGroup *directionGroup = new QActionGroup(this); + connect(directionGroup, SIGNAL(triggered(QAction*)), this, SLOT(slotDirection(QAction*))); + directionGroup->setExclusive(true); + m_directionUpAction = createCheckableActionIntData(tr("&Portrait"), DirectionUp, m_direction, directionGroup, this); + //: Rotate form preview counter-clockwise + m_directionLeftAction = createCheckableActionIntData(tr("Landscape (&CCW)"), DirectionLeft, m_direction, directionGroup, this); + //: Rotate form preview clockwise + m_directionRightAction = createCheckableActionIntData(tr("&Landscape (CW)"), DirectionRight, m_direction, directionGroup, this); + m_closeAction = new QAction(tr("&Close"), this); + connect(m_closeAction, SIGNAL(triggered()), parentWidget(), SLOT(close())); + } + menu.addAction(m_directionUpAction); + menu.addAction(m_directionLeftAction); + menu.addAction(m_directionRightAction); + menu.addSeparator(); + populateContextMenu(&menu); + menu.addAction(m_closeAction); + menu.exec(QCursor::pos()); +} + +void PreviewDeviceSkin::slotDirection(QAction *a) +{ + const Direction newDirection = static_cast(a->data().toInt()); + if (m_direction == newDirection) + return; + const Qt::Orientation newOrientation = newDirection == DirectionUp ? Qt::Vertical : Qt::Horizontal; + const Qt::Orientation oldOrientation = m_direction == DirectionUp ? Qt::Vertical : Qt::Horizontal; + m_direction = newDirection; + QApplication::setOverrideCursor(Qt::WaitCursor); + if (oldOrientation != newOrientation) { + QSize size = screenSize(); + if (newOrientation == Qt::Horizontal) + size.transpose(); + fitWidget(size); + } + setTransform(skinTransform()); + QApplication::restoreOverrideCursor(); +} + +void PreviewDeviceSkin::fitWidget(const QSize &size) +{ + view()->setFixedSize(size); +} + +QMatrix PreviewDeviceSkin::skinTransform() const +{ + QMatrix newTransform; + switch (m_direction) { + case DirectionUp: + break; + case DirectionLeft: + newTransform.rotate(270.0); + break; + case DirectionRight: + newTransform.rotate(90.0); + break; + } + return newTransform; +} + +// ------------ PreviewConfigurationPrivate +class PreviewConfigurationData : public QSharedData { +public: + PreviewConfigurationData() {} + explicit PreviewConfigurationData(const QString &style, const QString &applicationStyleSheet, const QString &deviceSkin); + + QString m_style; + // Style sheet to prepend (to simulate the effect od QApplication::setSyleSheet()). + QString m_applicationStyleSheet; + QString m_deviceSkin; +}; + +PreviewConfigurationData::PreviewConfigurationData(const QString &style, const QString &applicationStyleSheet, const QString &deviceSkin) : + m_style(style), + m_applicationStyleSheet(applicationStyleSheet), + m_deviceSkin(deviceSkin) +{ +} + +/* ZoomablePreviewDeviceSkin: A Zoomable Widget Preview skin. Embeds preview + * into a ZoomWidget and this in turn into the DeviceSkin view and keeps + * Device skin zoom + ZoomWidget zoom in sync. */ + +class ZoomablePreviewDeviceSkin : public PreviewDeviceSkin +{ + Q_OBJECT +public: + explicit ZoomablePreviewDeviceSkin(const DeviceSkinParameters ¶meters, QWidget *parent); + virtual void setPreview(QWidget *w); + + int zoomPercent() const; // Device Skins have a double 'zoom' property + +public slots: + void setZoomPercent(int); + +signals: + void zoomPercentChanged(int); + +protected: + virtual void populateContextMenu(QMenu *m); + virtual QMatrix skinTransform() const; + virtual void fitWidget(const QSize &size); + +private: + ZoomMenu *m_zoomMenu; + QAction *m_zoomSubMenuAction; + ZoomWidget *m_zoomWidget; +}; + +ZoomablePreviewDeviceSkin::ZoomablePreviewDeviceSkin(const DeviceSkinParameters ¶meters, QWidget *parent) : + PreviewDeviceSkin(parameters, parent), + m_zoomMenu(new ZoomMenu(this)), + m_zoomSubMenuAction(0), + m_zoomWidget(new DesignerZoomWidget) +{ + connect(m_zoomMenu, SIGNAL(zoomChanged(int)), this, SLOT(setZoomPercent(int))); + connect(m_zoomMenu, SIGNAL(zoomChanged(int)), this, SIGNAL(zoomPercentChanged(int))); + m_zoomWidget->setZoomContextMenuEnabled(false); + m_zoomWidget->setWidgetZoomContextMenuEnabled(false); + m_zoomWidget->resize(screenSize()); + m_zoomWidget->setParent(this, Qt::SubWindow); + m_zoomWidget->setAutoFillBackground(true); + setView(m_zoomWidget); +} + +static inline qreal zoomFactor(int percent) +{ + return qreal(percent) / 100.0; +} + +static inline QSize scaleSize(int zoomPercent, const QSize &size) +{ + return zoomPercent == 100 ? size : (QSizeF(size) * zoomFactor(zoomPercent)).toSize(); +} + +void ZoomablePreviewDeviceSkin::setPreview(QWidget *formWidget) +{ + m_zoomWidget->setWidget(formWidget); + m_zoomWidget->resize(scaleSize(zoomPercent(), screenSize())); +} + +int ZoomablePreviewDeviceSkin::zoomPercent() const +{ + return m_zoomWidget->zoom(); +} + +void ZoomablePreviewDeviceSkin::setZoomPercent(int zp) +{ + if (zp == zoomPercent()) + return; + + // If not triggered by the menu itself: Update it + if (m_zoomMenu->zoom() != zp) + m_zoomMenu->setZoom(zp); + + QApplication::setOverrideCursor(Qt::WaitCursor); + m_zoomWidget->setZoom(zp); + setTransform(skinTransform()); + QApplication::restoreOverrideCursor(); +} + +void ZoomablePreviewDeviceSkin::populateContextMenu(QMenu *menu) +{ + if (!m_zoomSubMenuAction) { + m_zoomSubMenuAction = new QAction(tr("&Zoom"), this); + QMenu *zoomSubMenu = new QMenu; + m_zoomSubMenuAction->setMenu(zoomSubMenu); + m_zoomMenu->addActions(zoomSubMenu); + } + menu->addAction(m_zoomSubMenuAction); + menu->addSeparator(); +} + +QMatrix ZoomablePreviewDeviceSkin::skinTransform() const +{ + // Complete transformation consisting of base class rotation and zoom. + QMatrix rc = PreviewDeviceSkin::skinTransform(); + const int zp = zoomPercent(); + if (zp != 100) { + const qreal factor = zoomFactor(zp); + rc.scale(factor, factor); + } + return rc; +} + +void ZoomablePreviewDeviceSkin::fitWidget(const QSize &size) +{ + m_zoomWidget->resize(scaleSize(zoomPercent(), size)); +} + +// ------------- PreviewConfiguration + +static const char *styleKey = "Style"; +static const char *appStyleSheetKey = "AppStyleSheet"; +static const char *skinKey = "Skin"; + +PreviewConfiguration::PreviewConfiguration() : + m_d(new PreviewConfigurationData) +{ +} + +PreviewConfiguration::PreviewConfiguration(const QString &sty, const QString &applicationSheet, const QString &skin) : + m_d(new PreviewConfigurationData(sty, applicationSheet, skin)) +{ +} + +PreviewConfiguration::PreviewConfiguration(const PreviewConfiguration &o) : + m_d(o.m_d) +{ +} + +PreviewConfiguration &PreviewConfiguration::operator=(const PreviewConfiguration &o) +{ + m_d.operator=(o.m_d); + return *this; +} + +PreviewConfiguration::~PreviewConfiguration() +{ +} + +void PreviewConfiguration::clear() +{ + PreviewConfigurationData &d = *m_d; + d.m_style.clear(); + d.m_applicationStyleSheet.clear(); + d.m_deviceSkin.clear(); +} + +QString PreviewConfiguration::style() const +{ + return m_d->m_style; +} + +void PreviewConfiguration::setStyle(const QString &s) +{ + m_d->m_style = s; +} + +// Style sheet to prepend (to simulate the effect od QApplication::setSyleSheet()). +QString PreviewConfiguration::applicationStyleSheet() const +{ + return m_d->m_applicationStyleSheet; +} + +void PreviewConfiguration::setApplicationStyleSheet(const QString &as) +{ + m_d->m_applicationStyleSheet = as; +} + +QString PreviewConfiguration::deviceSkin() const +{ + return m_d->m_deviceSkin; +} + +void PreviewConfiguration::setDeviceSkin(const QString &s) +{ + m_d->m_deviceSkin = s; +} + +void PreviewConfiguration::toSettings(const QString &prefix, QDesignerSettingsInterface *settings) const +{ + const PreviewConfigurationData &d = *m_d; + settings->beginGroup(prefix); + settings->setValue(QLatin1String(styleKey), d.m_style); + settings->setValue(QLatin1String(appStyleSheetKey), d.m_applicationStyleSheet); + settings->setValue(QLatin1String(skinKey), d.m_deviceSkin); + settings->endGroup(); +} + +void PreviewConfiguration::fromSettings(const QString &prefix, const QDesignerSettingsInterface *settings) +{ + clear(); + QString key = prefix; + key += QLatin1Char('/'); + const int prefixSize = key.size(); + + PreviewConfigurationData &d = *m_d; + + const QVariant emptyString = QVariant(QString()); + + key += QLatin1String(styleKey); + d.m_style = settings->value(key, emptyString).toString(); + + key.replace(prefixSize, key.size() - prefixSize, QLatin1String(appStyleSheetKey)); + d.m_applicationStyleSheet = settings->value(key, emptyString).toString(); + + key.replace(prefixSize, key.size() - prefixSize, QLatin1String(skinKey)); + d.m_deviceSkin = settings->value(key, emptyString).toString(); +} + + +QDESIGNER_SHARED_EXPORT bool operator<(const PreviewConfiguration &pc1, const PreviewConfiguration &pc2) +{ + return compare(pc1, pc2) < 0; +} + +QDESIGNER_SHARED_EXPORT bool operator==(const PreviewConfiguration &pc1, const PreviewConfiguration &pc2) +{ + return compare(pc1, pc2) == 0; +} + +QDESIGNER_SHARED_EXPORT bool operator!=(const PreviewConfiguration &pc1, const PreviewConfiguration &pc2) +{ + return compare(pc1, pc2) != 0; +} + +// ------------- PreviewManagerPrivate +class PreviewManagerPrivate { +public: + PreviewManagerPrivate(PreviewManager::PreviewMode mode); + + const PreviewManager::PreviewMode m_mode; + + QPointer m_activePreview; + + typedef QList PreviewDataList; + + PreviewDataList m_previews; + + typedef QMap DeviceSkinConfigCache; + DeviceSkinConfigCache m_deviceSkinConfigCache; + + QDesignerFormEditorInterface *m_core; + bool m_updateBlocked; +}; + +PreviewManagerPrivate::PreviewManagerPrivate(PreviewManager::PreviewMode mode) : + m_mode(mode), + m_core(0), + m_updateBlocked(false) +{ +} + +// ------------- PreviewManager + +PreviewManager::PreviewManager(PreviewMode mode, QObject *parent) : + QObject(parent), + d(new PreviewManagerPrivate(mode)) +{ +} + +PreviewManager:: ~PreviewManager() +{ + delete d; +} + + +Qt::WindowFlags PreviewManager::previewWindowFlags(const QWidget *widget) const +{ +#ifdef Q_WS_WIN + Qt::WindowFlags windowFlags = (widget->windowType() == Qt::Window) ? Qt::Window | Qt::WindowMaximizeButtonHint : Qt::WindowFlags(Qt::Dialog); +#else + Q_UNUSED(widget) + // Only Dialogs have close buttons on Mac. + // On Linux, we don't want an additional task bar item and we don't want a minimize button; + // we want the preview to be on top. + Qt::WindowFlags windowFlags = Qt::Dialog; +#endif + return windowFlags; +} + +QWidget *PreviewManager::createDeviceSkinContainer(const QDesignerFormWindowInterface *fw) const +{ + return new QDialog(fw->window()); +} + +// Some widgets might require fake containers + +static QWidget *fakeContainer(QWidget *w) +{ + // Prevent a dock widget from trying to dock to Designer's main window + // (which can be found in the parent hierarchy in MDI mode) by + // providing a fake mainwindow + if (QDockWidget *dock = qobject_cast(w)) { + // Reparent: Clear modality, propagate title and resize outer container + const QSize size = w->size(); + w->setWindowModality(Qt::NonModal); + dock->setFeatures(dock->features() & ~(QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable|QDockWidget::DockWidgetClosable)); + dock->setAllowedAreas(Qt::LeftDockWidgetArea); + QMainWindow *mw = new QMainWindow; + int leftMargin, topMargin, rightMargin, bottomMargin; + mw->getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin); + mw->addDockWidget(Qt::LeftDockWidgetArea, dock); + mw->resize(size + QSize(leftMargin + rightMargin, topMargin + bottomMargin)); + return mw; + } + return w; +} + +static PreviewConfiguration configurationFromSettings(QDesignerFormEditorInterface *core, const QString &style) +{ + qdesigner_internal::PreviewConfiguration pc; + const QDesignerSharedSettings settings(core); + if (settings.isCustomPreviewConfigurationEnabled()) + pc = settings.customPreviewConfiguration(); + if (!style.isEmpty()) + pc.setStyle(style); + return pc; +} + +QWidget *PreviewManager::showPreview(const QDesignerFormWindowInterface *fw, const QString &style, int deviceProfileIndex, QString *errorMessage) +{ + return showPreview(fw, configurationFromSettings(fw->core(), style), deviceProfileIndex, errorMessage); +} + +QWidget *PreviewManager::showPreview(const QDesignerFormWindowInterface *fw, const QString &style, QString *errorMessage) +{ + return showPreview(fw, style, -1, errorMessage); +} + +QWidget *PreviewManager::createPreview(const QDesignerFormWindowInterface *fw, + const PreviewConfiguration &pc, + int deviceProfileIndex, + QString *errorMessage, + int initialZoom) +{ + if (!d->m_core) + d->m_core = fw->core(); + + const bool zoomable = initialZoom > 0; + // Figure out which profile to apply + DeviceProfile deviceProfile; + if (deviceProfileIndex >= 0) { + deviceProfile = QDesignerSharedSettings(fw->core()).deviceProfileAt(deviceProfileIndex); + } else { + if (const FormWindowBase *fwb = qobject_cast(fw)) + deviceProfile = fwb->deviceProfile(); + } + // Create + QWidget *formWidget = QDesignerFormBuilder::createPreview(fw, pc.style(), pc.applicationStyleSheet(), deviceProfile, errorMessage); + if (!formWidget) + return 0; + + const QString title = tr("%1 - [Preview]").arg(formWidget->windowTitle()); + formWidget = fakeContainer(formWidget); + formWidget->setWindowTitle(title); + + // Clear any modality settings, child widget modalities must not be higher than parent's + formWidget->setWindowModality(Qt::NonModal); + // No skin + const QString deviceSkin = pc.deviceSkin(); + if (deviceSkin.isEmpty()) { + if (zoomable) { // Embed into ZoomWidget + ZoomWidget *zw = new DesignerZoomWidget; + connect(zw->zoomMenu(), SIGNAL(zoomChanged(int)), this, SLOT(slotZoomChanged(int))); + zw->setWindowTitle(title); + zw->setWidget(formWidget); + // Keep any widgets' context menus working, do not use global menu + zw->setWidgetZoomContextMenuEnabled(true); + zw->setParent(fw->window(), previewWindowFlags(formWidget)); + // Make preview close when Widget closes (Dialog/accept, etc) + formWidget->setAttribute(Qt::WA_DeleteOnClose, true); + connect(formWidget, SIGNAL(destroyed()), zw, SLOT(close())); + zw->setZoom(initialZoom); + zw->setProperty(WidgetFactory::disableStyleCustomPaintingPropertyC, QVariant(true)); + return zw; + } + formWidget->setParent(fw->window(), previewWindowFlags(formWidget)); + formWidget->setProperty(WidgetFactory::disableStyleCustomPaintingPropertyC, QVariant(true)); + return formWidget; + } + // Embed into skin. find config in cache + PreviewManagerPrivate::DeviceSkinConfigCache::iterator it = d->m_deviceSkinConfigCache.find(deviceSkin); + if (it == d->m_deviceSkinConfigCache.end()) { + DeviceSkinParameters parameters; + if (!parameters.read(deviceSkin, DeviceSkinParameters::ReadAll, errorMessage)) { + formWidget->deleteLater(); + return 0; + } + it = d->m_deviceSkinConfigCache.insert(deviceSkin, parameters); + } + + QWidget *skinContainer = createDeviceSkinContainer(fw); + PreviewDeviceSkin *skin = 0; + if (zoomable) { + ZoomablePreviewDeviceSkin *zds = new ZoomablePreviewDeviceSkin(it.value(), skinContainer); + zds->setZoomPercent(initialZoom); + connect(zds, SIGNAL(zoomPercentChanged(int)), this, SLOT(slotZoomChanged(int))); + skin = zds; + } else { + skin = new PreviewDeviceSkin(it.value(), skinContainer); + } + skin->setPreview(formWidget); + // Make preview close when Widget closes (Dialog/accept, etc) + formWidget->setAttribute(Qt::WA_DeleteOnClose, true); + connect(formWidget, SIGNAL(destroyed()), skinContainer, SLOT(close())); + skinContainer->setWindowTitle(title); + skinContainer->setProperty(WidgetFactory::disableStyleCustomPaintingPropertyC, QVariant(true)); + return skinContainer; +} + +QWidget *PreviewManager::showPreview(const QDesignerFormWindowInterface *fw, + const PreviewConfiguration &pc, + int deviceProfileIndex, + QString *errorMessage) +{ + enum { Spacing = 10 }; + if (QWidget *existingPreviewWidget = raise(fw, pc)) + return existingPreviewWidget; + + const QDesignerSharedSettings settings(fw->core()); + const int initialZoom = settings.zoomEnabled() ? settings.zoom() : -1; + + QWidget *widget = createPreview(fw, pc, deviceProfileIndex, errorMessage, initialZoom); + if (!widget) + return 0; + // Install filter for Escape key + widget->setAttribute(Qt::WA_DeleteOnClose, true); + widget->installEventFilter(this); + + switch (d->m_mode) { + case ApplicationModalPreview: + // Cannot do this on the Mac as the dialog would have no close button + widget->setWindowModality(Qt::ApplicationModal); + break; + case SingleFormNonModalPreview: + case MultipleFormNonModalPreview: + widget->setWindowModality(Qt::NonModal); + connect(fw, SIGNAL(changed()), widget, SLOT(close())); + connect(fw, SIGNAL(destroyed()), widget, SLOT(close())); + if (d->m_mode == SingleFormNonModalPreview) + connect(fw->core()->formWindowManager(), SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)), widget, SLOT(close())); + break; + } + // Semi-smart algorithm to position previews: + // If its the first one, position relative to form. + // 2nd, attempt to tile right (for comparing styles) or cascade + const QSize size = widget->size(); + const bool firstPreview = d->m_previews.empty(); + if (firstPreview) { + widget->move(fw->mapToGlobal(QPoint(Spacing, Spacing))); + } else { + if (QWidget *lastPreview = d->m_previews.back().m_widget) { + QDesktopWidget *desktop = qApp->desktop(); + const QRect lastPreviewGeometry = lastPreview->frameGeometry(); + const QRect availGeometry = desktop->availableGeometry(desktop->screenNumber(lastPreview)); + const QPoint newPos = lastPreviewGeometry.topRight() + QPoint(Spacing, 0); + if (newPos.x() + size.width() < availGeometry.right()) + widget->move(newPos); + else + widget->move(lastPreviewGeometry.topLeft() + QPoint(Spacing, Spacing)); + } + + } + d->m_previews.push_back(PreviewData(widget, fw, pc)); + widget->show(); + if (firstPreview) + emit firstPreviewOpened(); + return widget; +} + +QWidget *PreviewManager::raise(const QDesignerFormWindowInterface *fw, const PreviewConfiguration &pc) +{ + typedef PreviewManagerPrivate::PreviewDataList PreviewDataList; + if (d->m_previews.empty()) + return false; + + // find matching window + const PreviewDataList::const_iterator cend = d->m_previews.constEnd(); + for (PreviewDataList::const_iterator it = d->m_previews.constBegin(); it != cend ;++it) { + QWidget * w = it->m_widget; + if (w && it->m_formWindow == fw && it->m_configuration == pc) { + w->raise(); + w->activateWindow(); + return w; + } + } + return 0; +} + +void PreviewManager::closeAllPreviews() +{ + typedef PreviewManagerPrivate::PreviewDataList PreviewDataList; + if (!d->m_previews.empty()) { + d->m_updateBlocked = true; + d->m_activePreview = 0; + const PreviewDataList::iterator cend = d->m_previews.end(); + for (PreviewDataList::iterator it = d->m_previews.begin(); it != cend ;++it) { + if (it->m_widget) + it->m_widget->close(); + } + d->m_previews.clear(); + d->m_updateBlocked = false; + emit lastPreviewClosed(); + } +} + +void PreviewManager::updatePreviewClosed(QWidget *w) +{ + typedef PreviewManagerPrivate::PreviewDataList PreviewDataList; + if (d->m_updateBlocked) + return; + // Purge out all 0 or widgets to be deleted + for (PreviewDataList::iterator it = d->m_previews.begin(); it != d->m_previews.end() ; ) { + QWidget *iw = it->m_widget; // Might be 0 when catching QEvent::Destroyed + if (iw == 0 || iw == w) { + it = d->m_previews.erase(it); + } else { + ++it; + } + } + if (d->m_previews.empty()) + emit lastPreviewClosed(); +} + +bool PreviewManager::eventFilter(QObject *watched, QEvent *event) +{ + // Courtesy of designer + do { + if (!watched->isWidgetType()) + break; + QWidget *previewWindow = qobject_cast(watched); + if (!previewWindow || !previewWindow->isWindow()) + break; + + switch (event->type()) { + case QEvent::KeyPress: + case QEvent::ShortcutOverride: { + const QKeyEvent *keyEvent = static_cast(event); + const int key = keyEvent->key(); + if ((key == Qt::Key_Escape +#ifdef Q_WS_MAC + || (keyEvent->modifiers() == Qt::ControlModifier && key == Qt::Key_Period) +#endif + )) { + previewWindow->close(); + return true; + } + } + break; + case QEvent::WindowActivate: + d->m_activePreview = previewWindow; + break; + case QEvent::Destroy: // We don't get QEvent::Close if someone accepts a QDialog. + updatePreviewClosed(previewWindow); + break; + case QEvent::Close: + updatePreviewClosed(previewWindow); + previewWindow->removeEventFilter (this); + break; + default: + break; + } + } while(false); + return QObject::eventFilter(watched, event); +} + +int PreviewManager::previewCount() const +{ + return d->m_previews.size(); +} + +QPixmap PreviewManager::createPreviewPixmap(const QDesignerFormWindowInterface *fw, const QString &style, int deviceProfileIndex, QString *errorMessage) +{ + return createPreviewPixmap(fw, configurationFromSettings(fw->core(), style), deviceProfileIndex, errorMessage); +} + +QPixmap PreviewManager::createPreviewPixmap(const QDesignerFormWindowInterface *fw, const QString &style, QString *errorMessage) +{ + return createPreviewPixmap(fw, style, -1, errorMessage); +} + +QPixmap PreviewManager::createPreviewPixmap(const QDesignerFormWindowInterface *fw, + const PreviewConfiguration &pc, + int deviceProfileIndex, + QString *errorMessage) +{ + QWidget *widget = createPreview(fw, pc, deviceProfileIndex, errorMessage); + if (!widget) + return QPixmap(); + const QPixmap rc = QPixmap::grabWidget(widget); + widget->deleteLater(); + return rc; +} + +void PreviewManager::slotZoomChanged(int z) +{ + if (d->m_core) { // Save the last zoom chosen by the user. + QDesignerSharedSettings settings(d->m_core); + settings.setZoom(z); + } +} +} + +QT_END_NAMESPACE + +#include "previewmanager.moc" diff --git a/src/designer/src/lib/shared/previewmanager_p.h b/src/designer/src/lib/shared/previewmanager_p.h new file mode 100644 index 000000000..3ca8619ce --- /dev/null +++ b/src/designer/src/lib/shared/previewmanager_p.h @@ -0,0 +1,184 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef PREVIEWMANAGER_H +#define PREVIEWMANAGER_H + +#include "shared_global_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QWidget; +class QPixmap; +class QAction; +class QActionGroup; +class QMenu; +class QWidget; +class QDesignerSettingsInterface; + +namespace qdesigner_internal { + +// ----------- PreviewConfiguration + +class PreviewConfigurationData; + +class QDESIGNER_SHARED_EXPORT PreviewConfiguration { +public: + PreviewConfiguration(); + explicit PreviewConfiguration(const QString &style, + const QString &applicationStyleSheet = QString(), + const QString &deviceSkin = QString()); + + PreviewConfiguration(const PreviewConfiguration&); + PreviewConfiguration& operator=(const PreviewConfiguration&); + ~PreviewConfiguration(); + + QString style() const; + void setStyle(const QString &); + + // Style sheet to prepend (to simulate the effect od QApplication::setSyleSheet()). + QString applicationStyleSheet() const; + void setApplicationStyleSheet(const QString &); + + QString deviceSkin() const; + void setDeviceSkin(const QString &); + + void clear(); + void toSettings(const QString &prefix, QDesignerSettingsInterface *settings) const; + void fromSettings(const QString &prefix, const QDesignerSettingsInterface *settings); + +private: + QSharedDataPointer m_d; +}; + +QDESIGNER_SHARED_EXPORT bool operator<(const PreviewConfiguration &pc1, const PreviewConfiguration &pc2); +QDESIGNER_SHARED_EXPORT bool operator==(const PreviewConfiguration &pc1, const PreviewConfiguration &pc2); +QDESIGNER_SHARED_EXPORT bool operator!=(const PreviewConfiguration &pc1, const PreviewConfiguration &pc2); + +// ----------- Preview window manager. +// Maintains a list of preview widgets with their associated form windows and configuration. + +class PreviewManagerPrivate; + +class QDESIGNER_SHARED_EXPORT PreviewManager : public QObject +{ + Q_OBJECT +public: + + enum PreviewMode { + // Modal preview. Do not use on Macs as dialogs would have no close button + ApplicationModalPreview, + // Non modal previewing of one form in different configurations (closes if form window changes) + SingleFormNonModalPreview, + // Non modal previewing of several forms in different configurations + MultipleFormNonModalPreview }; + + explicit PreviewManager(PreviewMode mode, QObject *parent); + virtual ~PreviewManager(); + + // Show preview. Raise existing preview window if there is one with a matching + // configuration, else create a new preview. + QWidget *showPreview(const QDesignerFormWindowInterface *, const PreviewConfiguration &pc, int deviceProfileIndex /*=-1*/, QString *errorMessage); + // Convenience that creates a preview using a configuration taken from the settings. + QWidget *showPreview(const QDesignerFormWindowInterface *, const QString &style, int deviceProfileIndex /*=-1*/, QString *errorMessage); + QWidget *showPreview(const QDesignerFormWindowInterface *, const QString &style, QString *errorMessage); + + int previewCount() const; + + // Create a pixmap for printing. + QPixmap createPreviewPixmap(const QDesignerFormWindowInterface *fw, const PreviewConfiguration &pc, int deviceProfileIndex /*=-1*/, QString *errorMessage); + // Convenience that creates a pixmap using a configuration taken from the settings. + QPixmap createPreviewPixmap(const QDesignerFormWindowInterface *fw, const QString &style, int deviceProfileIndex /*=-1*/, QString *errorMessage); + QPixmap createPreviewPixmap(const QDesignerFormWindowInterface *fw, const QString &style, QString *errorMessage); + + virtual bool eventFilter(QObject *watched, QEvent *event); + +public slots: + void closeAllPreviews(); + +signals: + void firstPreviewOpened(); + void lastPreviewClosed(); + +private slots: + void slotZoomChanged(int); + +private: + + virtual Qt::WindowFlags previewWindowFlags(const QWidget *widget) const; + virtual QWidget *createDeviceSkinContainer(const QDesignerFormWindowInterface *) const; + + QWidget *raise(const QDesignerFormWindowInterface *, const PreviewConfiguration &pc); + QWidget *createPreview(const QDesignerFormWindowInterface *, + const PreviewConfiguration &pc, + int deviceProfileIndex /* = -1 */, + QString *errorMessage, + /*Disabled by default, <0 */ + int initialZoom = -1); + + void updatePreviewClosed(QWidget *w); + + PreviewManagerPrivate *d; + + PreviewManager(const PreviewManager &other); + PreviewManager &operator =(const PreviewManager &other); +}; +} + +QT_END_NAMESPACE + +#endif // PREVIEWMANAGER_H diff --git a/src/designer/src/lib/shared/promotionmodel.cpp b/src/designer/src/lib/shared/promotionmodel.cpp new file mode 100644 index 000000000..deab66fa1 --- /dev/null +++ b/src/designer/src/lib/shared/promotionmodel.cpp @@ -0,0 +1,220 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "promotionmodel_p.h" +#include "widgetdatabase_p.h" + +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace { + typedef QList StandardItemList; + + // Model columns. + enum { ClassNameColumn, IncludeFileColumn, IncludeTypeColumn, ReferencedColumn, NumColumns }; + + // Create a model row. + StandardItemList modelRow() { + StandardItemList rc; + for (int i = 0; i < NumColumns; i++) { + rc.push_back(new QStandardItem()); + } + return rc; + } + + // Create a model row for a base class (read-only, cannot be selected). + StandardItemList baseModelRow(const QDesignerWidgetDataBaseItemInterface *dbItem) { + StandardItemList rc = modelRow(); + + rc[ClassNameColumn]->setText(dbItem->name()); + for (int i = 0; i < NumColumns; i++) { + rc[i]->setFlags(Qt::ItemIsEnabled); + } + return rc; + } + + // Create an editable model row for a promoted class. + StandardItemList promotedModelRow(const QDesignerWidgetDataBaseInterface *widgetDataBase, + QDesignerWidgetDataBaseItemInterface *dbItem, + bool referenced = false) { + + const int index = widgetDataBase->indexOf(dbItem); + + // Associate user data: database index and enabled flag + QVariantList userDataList; + userDataList.push_back(QVariant(index)); + userDataList.push_back(QVariant(referenced)); + const QVariant userData(userDataList); + + StandardItemList rc = modelRow(); + // name + rc[ClassNameColumn]->setText(dbItem->name()); + rc[ClassNameColumn]->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable); + rc[ClassNameColumn]->setData(userData); + // header + const qdesigner_internal::IncludeSpecification spec = qdesigner_internal::includeSpecification(dbItem->includeFile()); + rc[IncludeFileColumn]->setText(spec.first); + rc[IncludeFileColumn]->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable); + rc[IncludeFileColumn]->setData(userData); + // global include + rc[IncludeTypeColumn]->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable|Qt::ItemIsUserCheckable); + rc[IncludeTypeColumn]->setData(userData); + rc[IncludeTypeColumn]->setCheckState(spec.second == qdesigner_internal::IncludeGlobal ? Qt::Checked : Qt::Unchecked); + // referenced + rc[ReferencedColumn]->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEnabled); + rc[ClassNameColumn]->setData(userData); + if (!referenced) { + //: Usage of promoted widgets + static const QString notUsed = QCoreApplication::translate("PromotionModel", "Not used"); + rc[ReferencedColumn]->setText(notUsed); + } + return rc; + } +} + +namespace qdesigner_internal { + + PromotionModel::PromotionModel(QDesignerFormEditorInterface *core) : + m_core(core) + { + connect(this, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(slotItemChanged(QStandardItem*))); + } + + void PromotionModel::initializeHeaders() { + setColumnCount(NumColumns); + QStringList horizontalLabels(tr("Name")); + horizontalLabels += tr("Header file"); + horizontalLabels += tr("Global include"); + horizontalLabels += tr("Usage"); + setHorizontalHeaderLabels (horizontalLabels); + } + + void PromotionModel::updateFromWidgetDatabase() { + typedef QDesignerPromotionInterface::PromotedClasses PromotedClasses; + + clear(); + initializeHeaders(); + + // retrieve list of pairs from DB and convert into a tree structure. + // Set the item index as user data on the item. + const PromotedClasses promotedClasses = m_core->promotion()->promotedClasses(); + + if (promotedClasses.empty()) + return; + + const QSet usedPromotedClasses = m_core->promotion()->referencedPromotedClassNames(); + + QDesignerWidgetDataBaseInterface *widgetDataBase = m_core->widgetDataBase(); + QDesignerWidgetDataBaseItemInterface *baseClass = 0; + QStandardItem *baseItem = 0; + + const PromotedClasses::const_iterator bcend = promotedClasses.constEnd(); + for (PromotedClasses::const_iterator it = promotedClasses.constBegin(); it != bcend; ++it) { + // Start a new base class? + if (baseClass != it->baseItem) { + baseClass = it->baseItem; + const StandardItemList baseRow = baseModelRow(it->baseItem); + baseItem = baseRow.front(); + appendRow(baseRow); + } + Q_ASSERT(baseItem); + // Append derived + baseItem->appendRow(promotedModelRow(widgetDataBase, it->promotedItem, usedPromotedClasses.contains(it->promotedItem->name()))); + } + } + + void PromotionModel::slotItemChanged(QStandardItem * changedItem) { + // Retrieve DB item + bool referenced; + QDesignerWidgetDataBaseItemInterface *dbItem = databaseItem(changedItem, &referenced); + Q_ASSERT(dbItem); + // Change header or type + switch (changedItem->column()) { + case ClassNameColumn: + emit classNameChanged(dbItem, changedItem->text()); + break; + case IncludeTypeColumn: + case IncludeFileColumn: { + // Get both file and type items via parent. + const QStandardItem *baseClassItem = changedItem->parent(); + const QStandardItem *fileItem = baseClassItem->child(changedItem->row(), IncludeFileColumn); + const QStandardItem *typeItem = baseClassItem->child(changedItem->row(), IncludeTypeColumn); + emit includeFileChanged(dbItem, buildIncludeFile(fileItem->text(), typeItem->checkState() == Qt::Checked ? IncludeGlobal : IncludeLocal)); + } + break; + } + } + + QDesignerWidgetDataBaseItemInterface *PromotionModel::databaseItemAt(const QModelIndex &index, bool *referenced) const { + if (const QStandardItem *item = itemFromIndex (index)) + return databaseItem(item, referenced); + + *referenced = false; + return 0; + } + + QDesignerWidgetDataBaseItemInterface *PromotionModel::databaseItem(const QStandardItem * item, bool *referenced) const { + // Decode user data associated with item. + const QVariant data = item->data(); + if (data.type() != QVariant::List) { + *referenced = false; + return 0; + } + + const QVariantList dataList = data.toList(); + const int index = dataList[0].toInt(); + *referenced = dataList[1].toBool(); + return m_core->widgetDataBase()->item(index); + } + + QModelIndex PromotionModel::indexOfClass(const QString &className) const { + const StandardItemList matches = findItems (className, Qt::MatchFixedString|Qt::MatchCaseSensitive|Qt::MatchRecursive); + return matches.empty() ? QModelIndex() : indexFromItem (matches.front()); + } +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/promotionmodel_p.h b/src/designer/src/lib/shared/promotionmodel_p.h new file mode 100644 index 000000000..214efb135 --- /dev/null +++ b/src/designer/src/lib/shared/promotionmodel_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef PROMOTIONMODEL_H +#define PROMOTIONMODEL_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerWidgetDataBaseItemInterface; + +namespace qdesigner_internal { + + // Item model representing the promoted widgets. + class PromotionModel : public QStandardItemModel { + Q_OBJECT + + public: + explicit PromotionModel(QDesignerFormEditorInterface *core); + + void updateFromWidgetDatabase(); + + // Return item at model index or 0. + QDesignerWidgetDataBaseItemInterface *databaseItemAt(const QModelIndex &, bool *referenced) const; + + QModelIndex indexOfClass(const QString &className) const; + + signals: + void includeFileChanged(QDesignerWidgetDataBaseItemInterface *, const QString &includeFile); + void classNameChanged(QDesignerWidgetDataBaseItemInterface *, const QString &newName); + + private slots: + void slotItemChanged(QStandardItem * item); + + private: + void initializeHeaders(); + // Retrieve data base item of item or return 0. + QDesignerWidgetDataBaseItemInterface *databaseItem(const QStandardItem * item, bool *referenced) const; + + QDesignerFormEditorInterface *m_core; + }; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // PROMOTIONMODEL_H diff --git a/src/designer/src/lib/shared/promotiontaskmenu.cpp b/src/designer/src/lib/shared/promotiontaskmenu.cpp new file mode 100644 index 000000000..dc76ef6cf --- /dev/null +++ b/src/designer/src/lib/shared/promotiontaskmenu.cpp @@ -0,0 +1,361 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "promotiontaskmenu_p.h" +#include "qdesigner_promotiondialog_p.h" +#include "widgetfactory_p.h" +#include "metadatabase_p.h" +#include "widgetdatabase_p.h" +#include "qdesigner_command_p.h" +#include "signalslotdialog_p.h" +#include "qdesigner_objectinspector_p.h" +#include "abstractintrospection_p.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static QAction *separatorAction(QObject *parent) +{ + QAction *rc = new QAction(parent); + rc->setSeparator(true); + return rc; +} + +static inline QDesignerLanguageExtension *languageExtension(QDesignerFormEditorInterface *core) +{ + return qt_extension(core->extensionManager(), core); +} + +namespace qdesigner_internal { + +PromotionTaskMenu::PromotionTaskMenu(QWidget *widget,Mode mode, QObject *parent) : + QObject(parent), + m_mode(mode), + m_widget(widget), + m_promotionMapper(0), + m_globalEditAction(new QAction(tr("Promoted widgets..."), this)), + m_EditPromoteToAction(new QAction(tr("Promote to ..."), this)), + m_EditSignalsSlotsAction(new QAction(tr("Change signals/slots..."), this)), + m_promoteLabel(tr("Promote to")), + m_demoteLabel(tr("Demote to %1")) +{ + connect(m_globalEditAction, SIGNAL(triggered()), this, SLOT(slotEditPromotedWidgets())); + connect(m_EditPromoteToAction, SIGNAL(triggered()), this, SLOT(slotEditPromoteTo())); + connect(m_EditSignalsSlotsAction, SIGNAL(triggered()), this, SLOT(slotEditSignalsSlots())); +} + +PromotionTaskMenu::Mode PromotionTaskMenu::mode() const +{ + return m_mode; +} + +void PromotionTaskMenu::setMode(Mode m) +{ + m_mode = m; +} + +void PromotionTaskMenu::setWidget(QWidget *widget) +{ + m_widget = widget; +} + +void PromotionTaskMenu::setPromoteLabel(const QString &promoteLabel) +{ + m_promoteLabel = promoteLabel; +} + +void PromotionTaskMenu::setEditPromoteToLabel(const QString &promoteEditLabel) +{ + m_EditPromoteToAction->setText(promoteEditLabel); +} + +void PromotionTaskMenu::setDemoteLabel(const QString &demoteLabel) +{ + m_demoteLabel = demoteLabel; +} + +PromotionTaskMenu::PromotionState PromotionTaskMenu::createPromotionActions(QDesignerFormWindowInterface *formWindow) +{ + // clear out old + if (!m_promotionActions.empty()) { + qDeleteAll(m_promotionActions); + m_promotionActions.clear(); + } + // No promotion of main container + if (formWindow->mainContainer() == m_widget) + return NotApplicable; + + // Check for a homogenous selection + const PromotionSelectionList promotionSelection = promotionSelectionList(formWindow); + + if (promotionSelection.empty()) + return NoHomogenousSelection; + + QDesignerFormEditorInterface *core = formWindow->core(); + // if it is promoted: demote only. + if (isPromoted(formWindow->core(), m_widget)) { + const QString label = m_demoteLabel.arg( promotedExtends(core , m_widget)); + QAction *demoteAction = new QAction(label, this); + connect(demoteAction, SIGNAL(triggered()), this, SLOT(slotDemoteFromCustomWidget())); + m_promotionActions.push_back(demoteAction); + return CanDemote; + } + // figure out candidates + const QString baseClassName = WidgetFactory::classNameOf(core, m_widget); + const WidgetDataBaseItemList candidates = promotionCandidates(core->widgetDataBase(), baseClassName ); + if (candidates.empty()) { + // Is this thing promotable at all? + return QDesignerPromotionDialog::baseClassNames(core->promotion()).contains(baseClassName) ? CanPromote : NotApplicable; + } + // Set up a signal mapper to associate class names + if (!m_promotionMapper) { + m_promotionMapper = new QSignalMapper(this); + connect(m_promotionMapper, SIGNAL(mapped(QString)), this, SLOT(slotPromoteToCustomWidget(QString))); + } + + QMenu *candidatesMenu = new QMenu(); + // Create a sub menu + const WidgetDataBaseItemList::const_iterator cend = candidates.constEnd(); + // Set up actions and map class names + for (WidgetDataBaseItemList::const_iterator it = candidates.constBegin(); it != cend; ++it) { + const QString customClassName = (*it)->name(); + QAction *action = new QAction((*it)->name(), this); + connect(action, SIGNAL(triggered()), m_promotionMapper, SLOT(map())); + m_promotionMapper->setMapping(action, customClassName); + candidatesMenu->addAction(action); + } + // Sub menu action + QAction *subMenuAction = new QAction(m_promoteLabel, this); + subMenuAction->setMenu(candidatesMenu); + m_promotionActions.push_back(subMenuAction); + return CanPromote; +} + +void PromotionTaskMenu::addActions(unsigned separatorFlags, ActionList &actionList) +{ + addActions(formWindow(), separatorFlags, actionList); +} + +void PromotionTaskMenu::addActions(QDesignerFormWindowInterface *fw, unsigned flags, + ActionList &actionList) +{ + Q_ASSERT(m_widget); + const int previousSize = actionList.size(); + const PromotionState promotionState = createPromotionActions(fw); + + // Promotion candidates/demote + actionList += m_promotionActions; + + // Edit action depending on context + switch (promotionState) { + case CanPromote: + actionList += m_EditPromoteToAction; + break; + case CanDemote: + if (!(flags & SuppressGlobalEdit)) + actionList += m_globalEditAction; + if (!languageExtension(fw->core())) { + actionList += separatorAction(this); + actionList += m_EditSignalsSlotsAction; + } + break; + default: + if (!(flags & SuppressGlobalEdit)) + actionList += m_globalEditAction; + break; + } + // Add separators if required + if (actionList.size() > previousSize) { + if (flags & LeadingSeparator) + actionList.insert(previousSize, separatorAction(this)); + if (flags & TrailingSeparator) + actionList += separatorAction(this); + } +} + +void PromotionTaskMenu::addActions(QDesignerFormWindowInterface *fw, unsigned flags, QMenu *menu) +{ + ActionList actionList; + addActions(fw, flags, actionList); + menu->addActions(actionList); +} + +void PromotionTaskMenu::addActions(unsigned flags, QMenu *menu) +{ + addActions(formWindow(), flags, menu); +} + +void PromotionTaskMenu::promoteTo(QDesignerFormWindowInterface *fw, const QString &customClassName) +{ + Q_ASSERT(m_widget); + PromoteToCustomWidgetCommand *cmd = new PromoteToCustomWidgetCommand(fw); + cmd->init(promotionSelectionList(fw), customClassName); + fw->commandHistory()->push(cmd); +} + + +void PromotionTaskMenu::slotPromoteToCustomWidget(const QString &customClassName) +{ + promoteTo(formWindow(), customClassName); +} + +void PromotionTaskMenu::slotDemoteFromCustomWidget() +{ + QDesignerFormWindowInterface *fw = formWindow(); + const PromotionSelectionList promotedWidgets = promotionSelectionList(fw); + Q_ASSERT(!promotedWidgets.empty() && isPromoted(fw->core(), promotedWidgets.front())); + + // ### use the undo stack + DemoteFromCustomWidgetCommand *cmd = new DemoteFromCustomWidgetCommand(fw); + cmd->init(promotedWidgets); + fw->commandHistory()->push(cmd); +} + +void PromotionTaskMenu::slotEditPromoteTo() +{ + Q_ASSERT(m_widget); + // Check whether invoked over a promotable widget + QDesignerFormWindowInterface *fw = formWindow(); + QDesignerFormEditorInterface *core = fw->core(); + const QString base_class_name = WidgetFactory::classNameOf(core, m_widget); + Q_ASSERT(QDesignerPromotionDialog::baseClassNames(core->promotion()).contains(base_class_name)); + // Show over promotable widget + QString promoteToClassName; + QDialog *promotionEditor = 0; + if (QDesignerLanguageExtension *lang = languageExtension(core)) + promotionEditor = lang->createPromotionDialog(core, base_class_name, &promoteToClassName, fw); + if (!promotionEditor) + promotionEditor = new QDesignerPromotionDialog(core, fw, base_class_name, &promoteToClassName); + if (promotionEditor->exec() == QDialog::Accepted && !promoteToClassName.isEmpty()) { + promoteTo(fw, promoteToClassName); + } + delete promotionEditor; +} + +void PromotionTaskMenu::slotEditPromotedWidgets() +{ + // Global context, show over non-promotable widget + QDesignerFormWindowInterface *fw = formWindow(); + if (!fw) + return; + editPromotedWidgets(fw->core(), fw); +} + +PromotionTaskMenu::PromotionSelectionList PromotionTaskMenu::promotionSelectionList(QDesignerFormWindowInterface *formWindow) const +{ + // In multi selection mode, check for a homogenous selection (same class, same promotion state) + // and return the list if this is the case. Also make sure m_widget + // is the last widget in the list so that it is re-selected as the last + // widget by the promotion commands. + + PromotionSelectionList rc; + + if (m_mode != ModeSingleWidget) { + QDesignerFormEditorInterface *core = formWindow->core(); + const QDesignerIntrospectionInterface *intro = core->introspection(); + const QString className = intro->metaObject(m_widget)->className(); + const bool promoted = isPromoted(formWindow->core(), m_widget); + // Just in case someone plugged an old-style Object Inspector + if (QDesignerObjectInspector *designerObjectInspector = qobject_cast(core->objectInspector())) { + Selection s; + designerObjectInspector->getSelection(s); + // Find objects of similar state + const QWidgetList &source = m_mode == ModeManagedMultiSelection ? s.managed : s.unmanaged; + const QWidgetList::const_iterator cend = source.constEnd(); + for (QWidgetList::const_iterator it = source.constBegin(); it != cend; ++it) { + QWidget *w = *it; + if (w != m_widget) { + // Selection state mismatch + if (intro->metaObject(w)->className() != className || isPromoted(core, w) != promoted) + return PromotionSelectionList(); + rc.push_back(w); + } + } + } + } + + rc.push_back(m_widget); + return rc; +} + +QDesignerFormWindowInterface *PromotionTaskMenu::formWindow() const +{ + // Use the QObject overload of QDesignerFormWindowInterface::findFormWindow since that works + // for QDesignerMenus also. + QObject *o = m_widget; + QDesignerFormWindowInterface *result = QDesignerFormWindowInterface::findFormWindow(o); + Q_ASSERT(result != 0); + return result; +} + +void PromotionTaskMenu::editPromotedWidgets(QDesignerFormEditorInterface *core, QWidget* parent) { + QDesignerLanguageExtension *lang = languageExtension(core); + // Show over non-promotable widget + QDialog *promotionEditor = 0; + if (lang) + lang->createPromotionDialog(core, parent); + if (!promotionEditor) + promotionEditor = new QDesignerPromotionDialog(core, parent); + promotionEditor->exec(); + delete promotionEditor; +} + +void PromotionTaskMenu::slotEditSignalsSlots() +{ + QDesignerFormWindowInterface *fw = formWindow(); + if (!fw) + return; + SignalSlotDialog::editPromotedClass(fw->core(), m_widget, fw); +} +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/promotiontaskmenu_p.h b/src/designer/src/lib/shared/promotiontaskmenu_p.h new file mode 100644 index 000000000..94bf78729 --- /dev/null +++ b/src/designer/src/lib/shared/promotiontaskmenu_p.h @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef PROMOTIONTASKMENU_H +#define PROMOTIONTASKMENU_H + +#include "shared_global_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QDesignerFormEditorInterface; + +class QAction; +class QMenu; +class QWidget; +class QSignalMapper; + +namespace qdesigner_internal { + +// A helper class for creating promotion context menus and handling promotion actions. + +class QDESIGNER_SHARED_EXPORT PromotionTaskMenu: public QObject +{ + Q_OBJECT +public: + enum Mode { + ModeSingleWidget, + ModeManagedMultiSelection, + ModeUnmanagedMultiSelection + }; + + explicit PromotionTaskMenu(QWidget *widget,Mode mode = ModeManagedMultiSelection, QObject *parent = 0); + + Mode mode() const; + void setMode(Mode m); + + void setWidget(QWidget *widget); + + // Set menu labels + void setPromoteLabel(const QString &promoteLabel); + void setEditPromoteToLabel(const QString &promoteEditLabel); + // Defaults to "Demote to %1".arg(class). + void setDemoteLabel(const QString &demoteLabel); + + typedef QList ActionList; + + enum AddFlags { LeadingSeparator = 1, TrailingSeparator = 2, SuppressGlobalEdit = 4}; + + // Adds a list of promotion actions according to the current promotion state of the widget. + void addActions(QDesignerFormWindowInterface *fw, unsigned flags, ActionList &actionList); + // Convenience that finds the form window. + void addActions(unsigned flags, ActionList &actionList); + + void addActions(QDesignerFormWindowInterface *fw, unsigned flags, QMenu *menu); + void addActions(unsigned flags, QMenu *menu); + + // Pop up the editor in a global context. + static void editPromotedWidgets(QDesignerFormEditorInterface *core, QWidget* parent); + +private slots: + void slotPromoteToCustomWidget(const QString &customClassName); + void slotDemoteFromCustomWidget(); + void slotEditPromotedWidgets(); + void slotEditPromoteTo(); + void slotEditSignalsSlots(); + +private: + void promoteTo(QDesignerFormWindowInterface *fw, const QString &customClassName); + + enum PromotionState { NotApplicable, NoHomogenousSelection, CanPromote, CanDemote }; + PromotionState createPromotionActions(QDesignerFormWindowInterface *formWindow); + QDesignerFormWindowInterface *formWindow() const; + + typedef QList > PromotionSelectionList; + PromotionSelectionList promotionSelectionList(QDesignerFormWindowInterface *formWindow) const; + + Mode m_mode; + + QPointer m_widget; + + QSignalMapper *m_promotionMapper; + // Per-Widget actions + QList m_promotionActions; + + QAction *m_globalEditAction; + QAction *m_EditPromoteToAction; + QAction *m_EditSignalsSlotsAction; + + QString m_promoteLabel; + QString m_demoteLabel; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // PROMOTIONTASKMENU_H diff --git a/src/designer/src/lib/shared/propertylineedit.cpp b/src/designer/src/lib/shared/propertylineedit.cpp new file mode 100644 index 000000000..29dff63ab --- /dev/null +++ b/src/designer/src/lib/shared/propertylineedit.cpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "propertylineedit_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + PropertyLineEdit::PropertyLineEdit(QWidget *parent) : + QLineEdit(parent), m_wantNewLine(false) + { + } + + bool PropertyLineEdit::event(QEvent *e) + { + // handle 'Select all' here as it is not done in the QLineEdit + if (e->type() == QEvent::ShortcutOverride && !isReadOnly()) { + QKeyEvent* ke = static_cast (e); + if (ke->modifiers() & Qt::ControlModifier) { + if(ke->key() == Qt::Key_A) { + ke->accept(); + return true; + } + } + } + return QLineEdit::event(e); + } + + void PropertyLineEdit::insertNewLine() { + insertText(QLatin1String("\\n")); + } + + void PropertyLineEdit::insertText(const QString &text) { + // position cursor after new text and grab focus + const int oldCursorPosition = cursorPosition (); + insert(text); + setCursorPosition (oldCursorPosition + text.length()); + setFocus(Qt::OtherFocusReason); + } + + void PropertyLineEdit::contextMenuEvent(QContextMenuEvent *event) { + QMenu *menu = createStandardContextMenu (); + + if (m_wantNewLine) { + menu->addSeparator(); + QAction* nlAction = menu->addAction(tr("Insert line break")); + connect(nlAction, SIGNAL(triggered()), this, SLOT(insertNewLine())); + } + + menu->exec(event->globalPos()); + } +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/propertylineedit_p.h b/src/designer/src/lib/shared/propertylineedit_p.h new file mode 100644 index 000000000..b968b18bf --- /dev/null +++ b/src/designer/src/lib/shared/propertylineedit_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef PROPERTYLINEEDIT_H +#define PROPERTYLINEEDIT_H + +#include "shared_global_p.h" + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + + // A line edit with a special context menu allowing for adding (escaped) new lines + class PropertyLineEdit : public QLineEdit { + Q_OBJECT + public: + explicit PropertyLineEdit(QWidget *parent); + void setWantNewLine(bool nl) { m_wantNewLine = nl; } + bool wantNewLine() const { return m_wantNewLine; } + + bool event(QEvent *e); + protected: + void contextMenuEvent (QContextMenuEvent *event ); + private slots: + void insertNewLine(); + private: + void insertText(const QString &); + bool m_wantNewLine; + }; +} + +QT_END_NAMESPACE + +#endif // PROPERTYLINEEDIT_H diff --git a/src/designer/src/lib/shared/qdesigner_command.cpp b/src/designer/src/lib/shared/qdesigner_command.cpp new file mode 100644 index 000000000..f4e250d89 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_command.cpp @@ -0,0 +1,2968 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_command_p.h" +#include "qdesigner_propertycommand_p.h" +#include "qdesigner_utils_p.h" +#include "layout_p.h" +#include "qlayout_widget_p.h" +#include "qdesigner_widget_p.h" +#include "qdesigner_menu_p.h" +#include "shared_enums_p.h" +#include "metadatabase_p.h" +#include "formwindowbase_p.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +Q_DECLARE_METATYPE(QWidgetList) + +QT_BEGIN_NAMESPACE + +static inline void setPropertySheetWindowTitle(const QDesignerFormEditorInterface *core, QObject *o, const QString &t) +{ + if (QDesignerPropertySheetExtension *sheet = qt_extension(core->extensionManager(), o)) { + const int idx = sheet->indexOf(QLatin1String("windowTitle")); + if (idx != -1) { + sheet->setProperty(idx, t); + sheet->setChanged(idx, true); + } + } +} + +namespace qdesigner_internal { + +// Helpers for the dynamic properties that store Z/Widget order +static const char *widgetOrderPropertyC = "_q_widgetOrder"; +static const char *zOrderPropertyC = "_q_zOrder"; + +static void addToWidgetListDynamicProperty(QWidget *parentWidget, QWidget *widget, const char *name, int index = -1) +{ + QWidgetList list = qvariant_cast(parentWidget->property(name)); + list.removeAll(widget); + if (index >= 0 && index < list.size()) { + list.insert(index, widget); + } else { + list.append(widget); + } + parentWidget->setProperty(name, QVariant::fromValue(list)); +} + +static int removeFromWidgetListDynamicProperty(QWidget *parentWidget, QWidget *widget, const char *name) +{ + QWidgetList list = qvariant_cast(parentWidget->property(name)); + const int firstIndex = list.indexOf(widget); + if (firstIndex != -1) { + list.removeAll(widget); + parentWidget->setProperty(name, QVariant::fromValue(list)); + } + return firstIndex; +} + +// ---- InsertWidgetCommand ---- +InsertWidgetCommand::InsertWidgetCommand(QDesignerFormWindowInterface *formWindow) : + QDesignerFormWindowCommand(QString(), formWindow), + m_insertMode(QDesignerLayoutDecorationExtension::InsertWidgetMode), + m_layoutHelper(0), + m_widgetWasManaged(false) +{ +} + +InsertWidgetCommand::~InsertWidgetCommand() +{ + delete m_layoutHelper; +} + +void InsertWidgetCommand::init(QWidget *widget, bool already_in_form, int layoutRow, int layoutColumn) +{ + m_widget = widget; + + setText(QApplication::translate("Command", "Insert '%1'").arg(widget->objectName())); + + QWidget *parentWidget = m_widget->parentWidget(); + QDesignerFormEditorInterface *core = formWindow()->core(); + QDesignerLayoutDecorationExtension *deco = qt_extension(core->extensionManager(), parentWidget); + + m_insertMode = deco ? deco->currentInsertMode() : QDesignerLayoutDecorationExtension::InsertWidgetMode; + if (layoutRow >= 0 && layoutColumn >= 0) { + m_cell.first = layoutRow; + m_cell.second = layoutColumn; + } else { + m_cell = deco ? deco->currentCell() : qMakePair(0, 0); + } + m_widgetWasManaged = already_in_form; +} + +static void recursiveUpdate(QWidget *w) +{ + w->update(); + + const QObjectList &l = w->children(); + const QObjectList::const_iterator cend = l.end(); + for ( QObjectList::const_iterator it = l.begin(); it != cend; ++it) { + if (QWidget *w = qobject_cast(*it)) + recursiveUpdate(w); + } +} + +void InsertWidgetCommand::redo() +{ + QWidget *parentWidget = m_widget->parentWidget(); + Q_ASSERT(parentWidget); + + addToWidgetListDynamicProperty(parentWidget, m_widget, widgetOrderPropertyC); + addToWidgetListDynamicProperty(parentWidget, m_widget, zOrderPropertyC); + + QDesignerFormEditorInterface *core = formWindow()->core(); + QDesignerLayoutDecorationExtension *deco = qt_extension(core->extensionManager(), parentWidget); + + if (deco != 0) { + const LayoutInfo::Type type = LayoutInfo::layoutType(core, LayoutInfo::managedLayout(core, parentWidget)); + m_layoutHelper = LayoutHelper::createLayoutHelper(type); + m_layoutHelper->pushState(core, parentWidget); + if (type == LayoutInfo::Grid) { + switch (m_insertMode) { + case QDesignerLayoutDecorationExtension::InsertRowMode: { + deco->insertRow(m_cell.first); + } break; + + case QDesignerLayoutDecorationExtension::InsertColumnMode: { + deco->insertColumn(m_cell.second); + } break; + + default: break; + } // end switch + } + deco->insertWidget(m_widget, m_cell); + } + + if (!m_widgetWasManaged) + formWindow()->manageWidget(m_widget); + m_widget->show(); + formWindow()->emitSelectionChanged(); + + if (parentWidget && parentWidget->layout()) { + recursiveUpdate(parentWidget); + parentWidget->layout()->invalidate(); + } + + refreshBuddyLabels(); +} + +void InsertWidgetCommand::undo() +{ + QWidget *parentWidget = m_widget->parentWidget(); + + QDesignerFormEditorInterface *core = formWindow()->core(); + QDesignerLayoutDecorationExtension *deco = qt_extension(core->extensionManager(), parentWidget); + + if (deco) { + deco->removeWidget(m_widget); + m_layoutHelper->popState(core, parentWidget); + } + + if (!m_widgetWasManaged) { + formWindow()->unmanageWidget(m_widget); + m_widget->hide(); + } + + removeFromWidgetListDynamicProperty(parentWidget, m_widget, widgetOrderPropertyC); + removeFromWidgetListDynamicProperty(parentWidget, m_widget, zOrderPropertyC); + + formWindow()->emitSelectionChanged(); + + refreshBuddyLabels(); +} + +void InsertWidgetCommand::refreshBuddyLabels() +{ + typedef QList LabelList; + + const LabelList label_list = formWindow()->findChildren(); + if (label_list.empty()) + return; + + const QString buddyProperty = QLatin1String("buddy"); + const QByteArray objectNameU8 = m_widget->objectName().toUtf8(); + // Re-set the buddy (The sheet locates the object by name and sets it) + const LabelList::const_iterator cend = label_list.constEnd(); + for (LabelList::const_iterator it = label_list.constBegin(); it != cend; ++it ) { + if (QDesignerPropertySheetExtension* sheet = propertySheet(*it)) { + const int idx = sheet->indexOf(buddyProperty); + if (idx != -1) { + const QVariant value = sheet->property(idx); + if (value.toByteArray() == objectNameU8) + sheet->setProperty(idx, value); + } + } + } +} + +// ---- ChangeZOrderCommand ---- +ChangeZOrderCommand::ChangeZOrderCommand(QDesignerFormWindowInterface *formWindow) + : QDesignerFormWindowCommand(QString(), formWindow) +{ +} + +void ChangeZOrderCommand::init(QWidget *widget) +{ + Q_ASSERT(widget); + + m_widget = widget; + + setText(QApplication::translate("Command", "Change Z-order of '%1'").arg(widget->objectName())); + + m_oldParentZOrder = qvariant_cast(widget->parentWidget()->property("_q_zOrder")); + const int index = m_oldParentZOrder.indexOf(m_widget); + if (index != -1 && index + 1 < m_oldParentZOrder.count()) + m_oldPreceding = m_oldParentZOrder.at(index + 1); +} + +void ChangeZOrderCommand::redo() +{ + m_widget->parentWidget()->setProperty("_q_zOrder", QVariant::fromValue(reorderWidget(m_oldParentZOrder, m_widget))); + + reorder(m_widget); +} + +void ChangeZOrderCommand::undo() +{ + m_widget->parentWidget()->setProperty("_q_zOrder", QVariant::fromValue(m_oldParentZOrder)); + + if (m_oldPreceding) + m_widget->stackUnder(m_oldPreceding); + else + m_widget->raise(); +} + +// ---- RaiseWidgetCommand ---- +RaiseWidgetCommand::RaiseWidgetCommand(QDesignerFormWindowInterface *formWindow) + : ChangeZOrderCommand(formWindow) +{ +} + +void RaiseWidgetCommand::init(QWidget *widget) +{ + ChangeZOrderCommand::init(widget); + setText(QApplication::translate("Command", "Raise '%1'").arg(widget->objectName())); +} + +QWidgetList RaiseWidgetCommand::reorderWidget(const QWidgetList &list, QWidget *widget) const +{ + QWidgetList l = list; + l.removeAll(widget); + l.append(widget); + return l; +} + +void RaiseWidgetCommand::reorder(QWidget *widget) const +{ + widget->raise(); +} + +// ---- LowerWidgetCommand ---- +LowerWidgetCommand::LowerWidgetCommand(QDesignerFormWindowInterface *formWindow) + : ChangeZOrderCommand(formWindow) +{ +} + +QWidgetList LowerWidgetCommand::reorderWidget(const QWidgetList &list, QWidget *widget) const +{ + QWidgetList l = list; + l.removeAll(widget); + l.prepend(widget); + return l; +} + +void LowerWidgetCommand::init(QWidget *widget) +{ + ChangeZOrderCommand::init(widget); + setText(QApplication::translate("Command", "Lower '%1'").arg(widget->objectName())); +} + +void LowerWidgetCommand::reorder(QWidget *widget) const +{ + widget->lower(); +} + +// ---- ManageWidgetCommandHelper +ManageWidgetCommandHelper::ManageWidgetCommandHelper() : + m_widget(0) +{ +} + +void ManageWidgetCommandHelper::init(const QDesignerFormWindowInterface *fw, QWidget *widget) +{ + m_widget = widget; + m_managedChildren.clear(); + + const QWidgetList children = m_widget->findChildren(); + if (children.empty()) + return; + + m_managedChildren.reserve(children.size()); + const QWidgetList::const_iterator lcend = children.constEnd(); + for (QWidgetList::const_iterator it = children.constBegin(); it != lcend; ++it) + if (fw->isManaged(*it)) + m_managedChildren.push_back(*it); +} + +void ManageWidgetCommandHelper::init(QWidget *widget, const WidgetVector &managedChildren) +{ + m_widget = widget; + m_managedChildren = managedChildren; +} + +void ManageWidgetCommandHelper::manage(QDesignerFormWindowInterface *fw) +{ + // Manage the managed children after parent + fw->manageWidget(m_widget); + if (!m_managedChildren.empty()) { + const WidgetVector::const_iterator lcend = m_managedChildren.constEnd(); + for (WidgetVector::const_iterator it = m_managedChildren.constBegin(); it != lcend; ++it) + fw->manageWidget(*it); + } +} + +void ManageWidgetCommandHelper::unmanage(QDesignerFormWindowInterface *fw) +{ + // Unmanage the managed children first + if (!m_managedChildren.empty()) { + const WidgetVector::const_iterator lcend = m_managedChildren.constEnd(); + for (WidgetVector::const_iterator it = m_managedChildren.constBegin(); it != lcend; ++it) + fw->unmanageWidget(*it); + } + fw->unmanageWidget(m_widget); +} + +// ---- DeleteWidgetCommand ---- +DeleteWidgetCommand::DeleteWidgetCommand(QDesignerFormWindowInterface *formWindow) : + QDesignerFormWindowCommand(QString(), formWindow), + m_layoutType(LayoutInfo::NoLayout), + m_layoutHelper(0), + m_flags(0), + m_splitterIndex(-1), + m_layoutSimplified(false), + m_formItem(0), + m_tabOrderIndex(-1), + m_widgetOrderIndex(-1), + m_zOrderIndex(-1) +{ +} + +DeleteWidgetCommand::~DeleteWidgetCommand() +{ + delete m_layoutHelper; +} + +void DeleteWidgetCommand::init(QWidget *widget, unsigned flags) +{ + m_widget = widget; + m_parentWidget = widget->parentWidget(); + m_geometry = widget->geometry(); + m_flags = flags; + m_layoutType = LayoutInfo::NoLayout; + m_splitterIndex = -1; + bool isManaged; // Check for a managed layout + QLayout *layout; + m_layoutType = LayoutInfo::laidoutWidgetType(formWindow()->core(), m_widget, &isManaged, &layout); + if (!isManaged) + m_layoutType = LayoutInfo::NoLayout; + switch (m_layoutType) { + case LayoutInfo::HSplitter: + case LayoutInfo::VSplitter: { + QSplitter *splitter = qobject_cast(m_parentWidget); + Q_ASSERT(splitter); + m_splitterIndex = splitter->indexOf(widget); + } + break; + case LayoutInfo::NoLayout: + break; + default: + m_layoutHelper = LayoutHelper::createLayoutHelper(m_layoutType); + m_layoutPosition = m_layoutHelper->itemInfo(layout, m_widget); + break; + } + + m_formItem = formWindow()->core()->metaDataBase()->item(formWindow()); + m_tabOrderIndex = m_formItem->tabOrder().indexOf(widget); + + // Build the list of managed children + m_manageHelper.init(formWindow(), m_widget); + + setText(QApplication::translate("Command", "Delete '%1'").arg(widget->objectName())); +} + +void DeleteWidgetCommand::redo() +{ + formWindow()->clearSelection(); + QDesignerFormEditorInterface *core = formWindow()->core(); + + if (QDesignerContainerExtension *c = qt_extension(core->extensionManager(), m_parentWidget)) { + const int count = c->count(); + for (int i=0; iwidget(i) == m_widget) { + c->remove(i); + return; + } + } + } + + m_widgetOrderIndex = removeFromWidgetListDynamicProperty(m_parentWidget, m_widget, widgetOrderPropertyC); + m_zOrderIndex = removeFromWidgetListDynamicProperty(m_parentWidget, m_widget, zOrderPropertyC); + + if (QDesignerLayoutDecorationExtension *deco = qt_extension(core->extensionManager(), m_parentWidget)) + deco->removeWidget(m_widget); + + if (m_layoutHelper) + switch (m_layoutType) { + case LayoutInfo::NoLayout: + case LayoutInfo::HSplitter: + case LayoutInfo::VSplitter: + break; + default: + // Attempt to simplify grids if a row/column becomes empty + m_layoutSimplified = (m_flags & DoNotSimplifyLayout) ? false : m_layoutHelper->canSimplify(core, m_parentWidget, m_layoutPosition); + if (m_layoutSimplified) { + m_layoutHelper->pushState(core, m_parentWidget); + m_layoutHelper->simplify(core, m_parentWidget, m_layoutPosition); + } + break; + } + + if (!(m_flags & DoNotUnmanage)) + m_manageHelper.unmanage(formWindow()); + + m_widget->setParent(formWindow()); + m_widget->hide(); + + if (m_tabOrderIndex != -1) { + QList tab_order = m_formItem->tabOrder(); + tab_order.removeAt(m_tabOrderIndex); + m_formItem->setTabOrder(tab_order); + } +} + +void DeleteWidgetCommand::undo() +{ + QDesignerFormEditorInterface *core = formWindow()->core(); + formWindow()->clearSelection(); + + m_widget->setParent(m_parentWidget); + + if (QDesignerContainerExtension *c = qt_extension(core->extensionManager(), m_parentWidget)) { + c->addWidget(m_widget); + return; + } + + addToWidgetListDynamicProperty(m_parentWidget, m_widget, widgetOrderPropertyC, m_widgetOrderIndex); + addToWidgetListDynamicProperty(m_parentWidget, m_widget, zOrderPropertyC, m_zOrderIndex); + + m_widget->setGeometry(m_geometry); + + if (!(m_flags & DoNotUnmanage)) + m_manageHelper.manage(formWindow()); + // ### set up alignment + switch (m_layoutType) { + case LayoutInfo::NoLayout: + break; + case LayoutInfo::HSplitter: + case LayoutInfo::VSplitter: { + QSplitter *splitter = qobject_cast(m_widget->parent()); + Q_ASSERT(splitter); + splitter->insertWidget(m_splitterIndex, m_widget); + } break; + default: { + Q_ASSERT(m_layoutHelper); + if (m_layoutSimplified) + m_layoutHelper->popState(core, m_parentWidget); + QLayout *layout = LayoutInfo::managedLayout(core, m_parentWidget); + Q_ASSERT(m_layoutType == LayoutInfo::layoutType(core, layout)); + m_layoutHelper->insertWidget(layout, m_layoutPosition, m_widget); + } + break; + } + + m_widget->show(); + + if (m_tabOrderIndex != -1) { + QList tab_order = m_formItem->tabOrder(); + tab_order.insert(m_tabOrderIndex, m_widget); + m_formItem->setTabOrder(tab_order); + } +} + +// ---- ReparentWidgetCommand ---- +ReparentWidgetCommand::ReparentWidgetCommand(QDesignerFormWindowInterface *formWindow) + : QDesignerFormWindowCommand(QString(), formWindow) +{ +} + +void ReparentWidgetCommand::init(QWidget *widget, QWidget *parentWidget) +{ + Q_ASSERT(widget); + + m_widget = widget; + m_oldParentWidget = widget->parentWidget(); + m_newParentWidget = parentWidget; + + m_oldPos = m_widget->pos(); + m_newPos = m_newParentWidget->mapFromGlobal(m_oldParentWidget->mapToGlobal(m_oldPos)); + + setText(QApplication::translate("Command", "Reparent '%1'").arg(widget->objectName())); + + m_oldParentList = qvariant_cast(m_oldParentWidget->property("_q_widgetOrder")); + m_oldParentZOrder = qvariant_cast(m_oldParentWidget->property("_q_zOrder")); +} + +void ReparentWidgetCommand::redo() +{ + m_widget->setParent(m_newParentWidget); + m_widget->move(m_newPos); + + QWidgetList oldList = m_oldParentList; + oldList.removeAll(m_widget); + m_oldParentWidget->setProperty("_q_widgetOrder", QVariant::fromValue(oldList)); + + QWidgetList newList = qvariant_cast(m_newParentWidget->property("_q_widgetOrder")); + newList.append(m_widget); + m_newParentWidget->setProperty("_q_widgetOrder", QVariant::fromValue(newList)); + + QWidgetList oldZOrder = m_oldParentZOrder; + oldZOrder.removeAll(m_widget); + m_oldParentWidget->setProperty("_q_zOrder", QVariant::fromValue(oldZOrder)); + + QWidgetList newZOrder = qvariant_cast(m_newParentWidget->property("_q_zOrder")); + newZOrder.append(m_widget); + m_newParentWidget->setProperty("_q_zOrder", QVariant::fromValue(newZOrder)); + + m_widget->show(); + core()->objectInspector()->setFormWindow(formWindow()); +} + +void ReparentWidgetCommand::undo() +{ + m_widget->setParent(m_oldParentWidget); + m_widget->move(m_oldPos); + + m_oldParentWidget->setProperty("_q_widgetOrder", QVariant::fromValue(m_oldParentList)); + + QWidgetList newList = qvariant_cast(m_newParentWidget->property("_q_widgetOrder")); + newList.removeAll(m_widget); + m_newParentWidget->setProperty("_q_widgetOrder", QVariant::fromValue(newList)); + + m_oldParentWidget->setProperty("_q_zOrder", QVariant::fromValue(m_oldParentZOrder)); + + QWidgetList newZOrder = qvariant_cast(m_newParentWidget->property("_q_zOrder")); + m_newParentWidget->setProperty("_q_zOrder", QVariant::fromValue(newZOrder)); + + m_widget->show(); + core()->objectInspector()->setFormWindow(formWindow()); +} + +PromoteToCustomWidgetCommand::PromoteToCustomWidgetCommand + (QDesignerFormWindowInterface *formWindow) + : QDesignerFormWindowCommand(QApplication::translate("Command", "Promote to custom widget"), formWindow) +{ +} + +void PromoteToCustomWidgetCommand::init(const WidgetList &widgets,const QString &customClassName) +{ + m_widgets = widgets; + m_customClassName = customClassName; +} + +void PromoteToCustomWidgetCommand::redo() +{ + foreach (QWidget *w, m_widgets) { + if (w) + promoteWidget(core(), w, m_customClassName); + } + updateSelection(); +} + +void PromoteToCustomWidgetCommand::updateSelection() +{ + // Update class names in ObjectInspector, PropertyEditor + QDesignerFormWindowInterface *fw = formWindow(); + QDesignerFormEditorInterface *core = fw->core(); + core->objectInspector()->setFormWindow(fw); + if (QObject *o = core->propertyEditor()->object()) + core->propertyEditor()->setObject(o); +} + +void PromoteToCustomWidgetCommand::undo() +{ + foreach (QWidget *w, m_widgets) { + if (w) + demoteWidget(core(), w); + } + updateSelection(); +} + +// ---- DemoteFromCustomWidgetCommand ---- + +DemoteFromCustomWidgetCommand::DemoteFromCustomWidgetCommand + (QDesignerFormWindowInterface *formWindow) : + QDesignerFormWindowCommand(QApplication::translate("Command", "Demote from custom widget"), formWindow), + m_promote_cmd(formWindow) +{ +} + +void DemoteFromCustomWidgetCommand::init(const WidgetList &promoted) +{ + m_promote_cmd.init(promoted, promotedCustomClassName(core(), promoted.front())); +} + +void DemoteFromCustomWidgetCommand::redo() +{ + m_promote_cmd.undo(); +} + +void DemoteFromCustomWidgetCommand::undo() +{ + m_promote_cmd.redo(); +} + +// ---------- CursorSelectionState +CursorSelectionState::CursorSelectionState() +{ +} + +void CursorSelectionState::save(const QDesignerFormWindowInterface *formWindow) +{ + const QDesignerFormWindowCursorInterface *cursor = formWindow->cursor(); + m_selection.clear(); + m_current = cursor->current(); + if (cursor->hasSelection()) { + const int count = cursor->selectedWidgetCount(); + for(int i = 0; i < count; i++) + m_selection.push_back(cursor->selectedWidget(i)); + } +} + +void CursorSelectionState::restore(QDesignerFormWindowInterface *formWindow) const +{ + if (m_selection.empty()) { + formWindow->clearSelection(true); + } else { + // Select current as last + formWindow->clearSelection(false); + const WidgetPointerList::const_iterator cend = m_selection.constEnd(); + for (WidgetPointerList::const_iterator it = m_selection.constBegin(); it != cend; ++it) + if (QWidget *w = *it) + if (w != m_current) + formWindow->selectWidget(*it, true); + if (m_current) + formWindow->selectWidget(m_current, true); + } +} + +// ---- LayoutCommand ---- + +LayoutCommand::LayoutCommand(QDesignerFormWindowInterface *formWindow) : + QDesignerFormWindowCommand(QString(), formWindow), + m_setup(false) +{ +} + +LayoutCommand::~LayoutCommand() +{ + delete m_layout; +} + +void LayoutCommand::init(QWidget *parentWidget, const QWidgetList &widgets, + LayoutInfo::Type layoutType, QWidget *layoutBase, + bool reparentLayoutWidget) +{ + m_parentWidget = parentWidget; + m_widgets = widgets; + formWindow()->simplifySelection(&m_widgets); + m_layout = Layout::createLayout(widgets, parentWidget, formWindow(), layoutBase, layoutType); + m_layout->setReparentLayoutWidget(reparentLayoutWidget); + + switch (layoutType) { + case LayoutInfo::Grid: + setText(QApplication::translate("Command", "Lay out using grid")); + break; + case LayoutInfo::VBox: + setText(QApplication::translate("Command", "Lay out vertically")); + break; + case LayoutInfo::HBox: + setText(QApplication::translate("Command", "Lay out horizontally")); + break; + default: + break; + } + // Delayed setup to avoid confusion in case we are chained + // with a BreakLayout in a morph layout macro + m_setup = false; +} + +void LayoutCommand::redo() +{ + if (!m_setup) { + m_layout->setup(); + m_cursorSelectionState.save(formWindow()); + m_setup = true; + } + m_layout->doLayout(); + core()->objectInspector()->setFormWindow(formWindow()); +} + +void LayoutCommand::undo() +{ + QDesignerFormEditorInterface *core = formWindow()->core(); + + QWidget *lb = m_layout->layoutBaseWidget(); + QDesignerLayoutDecorationExtension *deco = qt_extension(core->extensionManager(), lb); + m_layout->undoLayout(); + delete deco; // release the extension + + // ### generalize (put in function) + if (!m_layoutBase && lb != 0 && !(qobject_cast(lb) || qobject_cast(lb))) { + core->metaDataBase()->add(lb); + lb->show(); + } + m_cursorSelectionState.restore(formWindow()); + core->objectInspector()->setFormWindow(formWindow()); +} + +// ---- BreakLayoutCommand ---- +BreakLayoutCommand::BreakLayoutCommand(QDesignerFormWindowInterface *formWindow) : + QDesignerFormWindowCommand(QApplication::translate("Command", "Break layout"), formWindow), + m_layoutHelper(0), + m_properties(0), + m_propertyMask(0) +{ +} + +BreakLayoutCommand::~BreakLayoutCommand() +{ + delete m_layoutHelper; + delete m_layout; + delete m_properties; +} + +const LayoutProperties *BreakLayoutCommand::layoutProperties() const +{ + return m_properties; +} + +int BreakLayoutCommand::propertyMask() const +{ + return m_propertyMask; +} + +void BreakLayoutCommand::init(const QWidgetList &widgets, QWidget *layoutBase, bool reparentLayoutWidget) +{ + enum Type { SplitterLayout, LayoutHasMarginSpacing, LayoutHasState }; + + const QDesignerFormEditorInterface *core = formWindow()->core(); + m_widgets = widgets; + m_layoutBase = core->widgetFactory()->containerOfWidget(layoutBase); + QLayout *layoutToBeBroken; + const LayoutInfo::Type layoutType = LayoutInfo::managedLayoutType(core, m_layoutBase, &layoutToBeBroken); + m_layout = Layout::createLayout(widgets, m_layoutBase, formWindow(), layoutBase, layoutType); + m_layout->setReparentLayoutWidget(reparentLayoutWidget); + + Type type = LayoutHasState; + switch (layoutType) { + case LayoutInfo::NoLayout: + case LayoutInfo::HSplitter: + case LayoutInfo::VSplitter: + type = SplitterLayout; + break; + case LayoutInfo::HBox: + case LayoutInfo::VBox: // Margin/spacing need to be saved + type = LayoutHasMarginSpacing; + break; + default: // Margin/spacing need to be saved + has a state (empty rows/columns of a grid) + type = LayoutHasState; + break; + } + Q_ASSERT(m_layout != 0); + m_layout->sort(); + + + if (type >= LayoutHasMarginSpacing) { + m_properties = new LayoutProperties; + m_propertyMask = m_properties->fromPropertySheet(core, layoutToBeBroken, LayoutProperties::AllProperties); + } + if (type >= LayoutHasState) + m_layoutHelper = LayoutHelper::createLayoutHelper(layoutType); + m_cursorSelectionState.save(formWindow()); +} + +void BreakLayoutCommand::redo() +{ + if (!m_layout) + return; + + QDesignerFormEditorInterface *core = formWindow()->core(); + QWidget *lb = m_layout->layoutBaseWidget(); + QDesignerLayoutDecorationExtension *deco = qt_extension(core->extensionManager(), lb); + formWindow()->clearSelection(false); + if (m_layoutHelper) + m_layoutHelper->pushState(core, m_layoutBase); + m_layout->breakLayout(); + delete deco; // release the extension + + foreach (QWidget *widget, m_widgets) { + widget->resize(widget->size().expandedTo(QSize(16, 16))); + } + // Update unless we are in an intermediate state of morphing layout + // in which a QLayoutWidget will have no layout at all. + if (m_layout->reparentLayoutWidget()) + core->objectInspector()->setFormWindow(formWindow()); +} + +void BreakLayoutCommand::undo() +{ + if (!m_layout) + return; + + formWindow()->clearSelection(false); + m_layout->doLayout(); + if (m_layoutHelper) + m_layoutHelper->popState(formWindow()->core(), m_layoutBase); + + QLayout *layoutToRestored = LayoutInfo::managedLayout(formWindow()->core(), m_layoutBase); + if (m_properties && m_layoutBase && layoutToRestored) + m_properties->toPropertySheet(formWindow()->core(), layoutToRestored, m_propertyMask); + m_cursorSelectionState.restore(formWindow()); + core()->objectInspector()->setFormWindow(formWindow()); +} +// ---- SimplifyLayoutCommand +SimplifyLayoutCommand::SimplifyLayoutCommand(QDesignerFormWindowInterface *formWindow) : + QDesignerFormWindowCommand(QApplication::translate("Command", "Simplify Grid Layout"), formWindow), + m_area(0, 0, 32767, 32767), + m_layoutBase(0), + m_layoutHelper(0), + m_layoutSimplified(false) +{ +} + +SimplifyLayoutCommand::~SimplifyLayoutCommand() +{ + delete m_layoutHelper; +} + +bool SimplifyLayoutCommand::canSimplify(QDesignerFormEditorInterface *core, const QWidget *w, int *layoutType) +{ + if (!w) + return false; + QLayout *layout; + const LayoutInfo::Type type = LayoutInfo::managedLayoutType(core, w, &layout); + if (layoutType) + *layoutType = type; + if (!layout) + return false; + switch (type) { // Known negatives + case LayoutInfo::NoLayout: + case LayoutInfo::UnknownLayout: + case LayoutInfo::HSplitter: + case LayoutInfo::VSplitter: + case LayoutInfo::HBox: + case LayoutInfo::VBox: + return false; + default: + break; + } + switch (type) { + case LayoutInfo::Grid: + return QLayoutSupport::canSimplifyQuickCheck(qobject_cast(layout)); + case LayoutInfo::Form: + return QLayoutSupport::canSimplifyQuickCheck(qobject_cast(layout)); + default: + break; + } + return false; +} + +bool SimplifyLayoutCommand::init(QWidget *layoutBase) +{ + QDesignerFormEditorInterface *core = formWindow()->core(); + m_layoutSimplified = false; + int type; + if (canSimplify(core, layoutBase, &type)) { + m_layoutBase = layoutBase; + m_layoutHelper = LayoutHelper::createLayoutHelper(type); + m_layoutSimplified = m_layoutHelper->canSimplify(core, layoutBase, m_area); + } + return m_layoutSimplified; +} + +void SimplifyLayoutCommand::redo() +{ + const QDesignerFormEditorInterface *core = formWindow()->core(); + if (m_layoutSimplified) { + m_layoutHelper->pushState(core, m_layoutBase); + m_layoutHelper->simplify(core, m_layoutBase, m_area); + } +} +void SimplifyLayoutCommand::undo() +{ + if (m_layoutSimplified) + m_layoutHelper->popState(formWindow()->core(), m_layoutBase); +} + +// ---- ToolBoxCommand ---- +ToolBoxCommand::ToolBoxCommand(QDesignerFormWindowInterface *formWindow) : + QDesignerFormWindowCommand(QString(), formWindow), + m_index(-1) +{ +} + +ToolBoxCommand::~ToolBoxCommand() +{ +} + +void ToolBoxCommand::init(QToolBox *toolBox) +{ + m_toolBox = toolBox; + m_index = m_toolBox->currentIndex(); + m_widget = m_toolBox->widget(m_index); + m_itemText = m_toolBox->itemText(m_index); + m_itemIcon = m_toolBox->itemIcon(m_index); +} + +void ToolBoxCommand::removePage() +{ + m_toolBox->removeItem(m_index); + + m_widget->hide(); + m_widget->setParent(formWindow()); + formWindow()->clearSelection(); + formWindow()->selectWidget(m_toolBox, true); + +} + +void ToolBoxCommand::addPage() +{ + m_widget->setParent(m_toolBox); + m_toolBox->insertItem(m_index, m_widget, m_itemIcon, m_itemText); + m_toolBox->setCurrentIndex(m_index); + + QDesignerPropertySheetExtension *sheet = qt_extension(formWindow()->core()->extensionManager(), m_toolBox); + if (sheet) { + qdesigner_internal::PropertySheetStringValue itemText(m_itemText); + sheet->setProperty(sheet->indexOf(QLatin1String("currentItemText")), QVariant::fromValue(itemText)); + } + + m_widget->show(); + formWindow()->clearSelection(); + formWindow()->selectWidget(m_toolBox, true); +} + +// ---- MoveToolBoxPageCommand ---- +MoveToolBoxPageCommand::MoveToolBoxPageCommand(QDesignerFormWindowInterface *formWindow) : + ToolBoxCommand(formWindow), + m_newIndex(-1), + m_oldIndex(-1) +{ +} + +MoveToolBoxPageCommand::~MoveToolBoxPageCommand() +{ +} + +void MoveToolBoxPageCommand::init(QToolBox *toolBox, QWidget *page, int newIndex) +{ + ToolBoxCommand::init(toolBox); + setText(QApplication::translate("Command", "Move Page")); + + m_widget = page; + m_oldIndex = m_toolBox->indexOf(m_widget); + m_itemText = m_toolBox->itemText(m_oldIndex); + m_itemIcon = m_toolBox->itemIcon(m_oldIndex); + m_newIndex = newIndex; +} + +void MoveToolBoxPageCommand::redo() +{ + m_toolBox->removeItem(m_oldIndex); + m_toolBox->insertItem(m_newIndex, m_widget, m_itemIcon, m_itemText); +} + +void MoveToolBoxPageCommand::undo() +{ + m_toolBox->removeItem(m_newIndex); + m_toolBox->insertItem(m_oldIndex, m_widget, m_itemIcon, m_itemText); +} + +// ---- DeleteToolBoxPageCommand ---- +DeleteToolBoxPageCommand::DeleteToolBoxPageCommand(QDesignerFormWindowInterface *formWindow) + : ToolBoxCommand(formWindow) +{ +} + +DeleteToolBoxPageCommand::~DeleteToolBoxPageCommand() +{ +} + +void DeleteToolBoxPageCommand::init(QToolBox *toolBox) +{ + ToolBoxCommand::init(toolBox); + setText(QApplication::translate("Command", "Delete Page")); +} + +void DeleteToolBoxPageCommand::redo() +{ + removePage(); + cheapUpdate(); +} + +void DeleteToolBoxPageCommand::undo() +{ + addPage(); + cheapUpdate(); +} + +// ---- AddToolBoxPageCommand ---- +AddToolBoxPageCommand::AddToolBoxPageCommand(QDesignerFormWindowInterface *formWindow) + : ToolBoxCommand(formWindow) +{ +} + +AddToolBoxPageCommand::~AddToolBoxPageCommand() +{ +} + +void AddToolBoxPageCommand::init(QToolBox *toolBox) +{ + init(toolBox, InsertBefore); +} + +void AddToolBoxPageCommand::init(QToolBox *toolBox, InsertionMode mode) +{ + m_toolBox = toolBox; + + m_index = m_toolBox->currentIndex(); + if (mode == InsertAfter) + m_index++; + m_widget = new QDesignerWidget(formWindow(), m_toolBox); + m_itemText = QApplication::translate("Command", "Page"); + m_itemIcon = QIcon(); + m_widget->setObjectName(QLatin1String("page")); + formWindow()->ensureUniqueObjectName(m_widget); + + setText(QApplication::translate("Command", "Insert Page")); + + QDesignerFormEditorInterface *core = formWindow()->core(); + core->metaDataBase()->add(m_widget); +} + +void AddToolBoxPageCommand::redo() +{ + addPage(); + cheapUpdate(); +} + +void AddToolBoxPageCommand::undo() +{ + removePage(); + cheapUpdate(); +} + +// ---- TabWidgetCommand ---- +TabWidgetCommand::TabWidgetCommand(QDesignerFormWindowInterface *formWindow) : + QDesignerFormWindowCommand(QString(), formWindow), + m_index(-1) +{ +} + +TabWidgetCommand::~TabWidgetCommand() +{ +} + +void TabWidgetCommand::init(QTabWidget *tabWidget) +{ + m_tabWidget = tabWidget; + m_index = m_tabWidget->currentIndex(); + m_widget = m_tabWidget->widget(m_index); + m_itemText = m_tabWidget->tabText(m_index); + m_itemIcon = m_tabWidget->tabIcon(m_index); +} + +void TabWidgetCommand::removePage() +{ + m_tabWidget->removeTab(m_index); + + m_widget->hide(); + m_widget->setParent(formWindow()); + m_tabWidget->setCurrentIndex(qMin(m_index, m_tabWidget->count())); + + formWindow()->clearSelection(); + formWindow()->selectWidget(m_tabWidget, true); +} + +void TabWidgetCommand::addPage() +{ + m_widget->setParent(0); + m_tabWidget->insertTab(m_index, m_widget, m_itemIcon, m_itemText); + m_widget->show(); + m_tabWidget->setCurrentIndex(m_index); + + QDesignerPropertySheetExtension *sheet = qt_extension(formWindow()->core()->extensionManager(), m_tabWidget); + if (sheet) { + qdesigner_internal::PropertySheetStringValue itemText(m_itemText); + sheet->setProperty(sheet->indexOf(QLatin1String("currentTabText")), QVariant::fromValue(itemText)); + } + + formWindow()->clearSelection(); + formWindow()->selectWidget(m_tabWidget, true); +} + +// ---- DeleteTabPageCommand ---- +DeleteTabPageCommand::DeleteTabPageCommand(QDesignerFormWindowInterface *formWindow) + : TabWidgetCommand(formWindow) +{ +} + +DeleteTabPageCommand::~DeleteTabPageCommand() +{ +} + +void DeleteTabPageCommand::init(QTabWidget *tabWidget) +{ + TabWidgetCommand::init(tabWidget); + setText(QApplication::translate("Command", "Delete Page")); +} + +void DeleteTabPageCommand::redo() +{ + removePage(); + cheapUpdate(); +} + +void DeleteTabPageCommand::undo() +{ + addPage(); + cheapUpdate(); +} + +// ---- AddTabPageCommand ---- +AddTabPageCommand::AddTabPageCommand(QDesignerFormWindowInterface *formWindow) + : TabWidgetCommand(formWindow) +{ +} + +AddTabPageCommand::~AddTabPageCommand() +{ +} + +void AddTabPageCommand::init(QTabWidget *tabWidget) +{ + init(tabWidget, InsertBefore); +} + +void AddTabPageCommand::init(QTabWidget *tabWidget, InsertionMode mode) +{ + m_tabWidget = tabWidget; + + m_index = m_tabWidget->currentIndex(); + if (mode == InsertAfter) + m_index++; + m_widget = new QDesignerWidget(formWindow(), m_tabWidget); + m_itemText = QApplication::translate("Command", "Page"); + m_itemIcon = QIcon(); + m_widget->setObjectName(QLatin1String("tab")); + formWindow()->ensureUniqueObjectName(m_widget); + + setText(QApplication::translate("Command", "Insert Page")); + + QDesignerFormEditorInterface *core = formWindow()->core(); + core->metaDataBase()->add(m_widget); +} + +void AddTabPageCommand::redo() +{ + addPage(); + cheapUpdate(); +} + +void AddTabPageCommand::undo() +{ + removePage(); + cheapUpdate(); +} + +// ---- MoveTabPageCommand ---- +MoveTabPageCommand::MoveTabPageCommand(QDesignerFormWindowInterface *formWindow) : + TabWidgetCommand(formWindow), + m_newIndex(-1), + m_oldIndex(-1) +{ +} + +MoveTabPageCommand::~MoveTabPageCommand() +{ +} + +void MoveTabPageCommand::init(QTabWidget *tabWidget, QWidget *page, + const QIcon &icon, const QString &label, + int index, int newIndex) +{ + TabWidgetCommand::init(tabWidget); + setText(QApplication::translate("Command", "Move Page")); + + m_page = page; + m_newIndex = newIndex; + m_oldIndex = index; + m_label = label; + m_icon = icon; +} + +void MoveTabPageCommand::redo() +{ + m_tabWidget->removeTab(m_oldIndex); + m_tabWidget->insertTab(m_newIndex, m_page, m_icon, m_label); + m_tabWidget->setCurrentIndex(m_newIndex); +} + +void MoveTabPageCommand::undo() +{ + m_tabWidget->removeTab(m_newIndex); + m_tabWidget->insertTab(m_oldIndex, m_page, m_icon, m_label); + m_tabWidget->setCurrentIndex(m_oldIndex); +} + +// ---- StackedWidgetCommand ---- +StackedWidgetCommand::StackedWidgetCommand(QDesignerFormWindowInterface *formWindow) : + QDesignerFormWindowCommand(QString(), formWindow), + m_index(-1) +{ +} + +StackedWidgetCommand::~StackedWidgetCommand() +{ +} + +void StackedWidgetCommand::init(QStackedWidget *stackedWidget) +{ + m_stackedWidget = stackedWidget; + m_index = m_stackedWidget->currentIndex(); + m_widget = m_stackedWidget->widget(m_index); +} + +void StackedWidgetCommand::removePage() +{ + m_stackedWidget->removeWidget(m_stackedWidget->widget(m_index)); + + m_widget->hide(); + m_widget->setParent(formWindow()); + + formWindow()->clearSelection(); + formWindow()->selectWidget(m_stackedWidget, true); +} + +void StackedWidgetCommand::addPage() +{ + m_stackedWidget->insertWidget(m_index, m_widget); + + m_widget->show(); + m_stackedWidget->setCurrentIndex(m_index); + + formWindow()->clearSelection(); + formWindow()->selectWidget(m_stackedWidget, true); +} + +// ---- MoveStackedWidgetCommand ---- +MoveStackedWidgetCommand::MoveStackedWidgetCommand(QDesignerFormWindowInterface *formWindow) : + StackedWidgetCommand(formWindow), + m_newIndex(-1), + m_oldIndex(-1) +{ +} + +MoveStackedWidgetCommand::~MoveStackedWidgetCommand() +{ +} + +void MoveStackedWidgetCommand::init(QStackedWidget *stackedWidget, QWidget *page, int newIndex) +{ + StackedWidgetCommand::init(stackedWidget); + setText(QApplication::translate("Command", "Move Page")); + + m_widget = page; + m_newIndex = newIndex; + m_oldIndex = m_stackedWidget->indexOf(m_widget); +} + +void MoveStackedWidgetCommand::redo() +{ + m_stackedWidget->removeWidget(m_widget); + m_stackedWidget->insertWidget(m_newIndex, m_widget); +} + +void MoveStackedWidgetCommand::undo() +{ + m_stackedWidget->removeWidget(m_widget); + m_stackedWidget->insertWidget(m_oldIndex, m_widget); +} + +// ---- DeleteStackedWidgetPageCommand ---- +DeleteStackedWidgetPageCommand::DeleteStackedWidgetPageCommand(QDesignerFormWindowInterface *formWindow) + : StackedWidgetCommand(formWindow) +{ +} + +DeleteStackedWidgetPageCommand::~DeleteStackedWidgetPageCommand() +{ +} + +void DeleteStackedWidgetPageCommand::init(QStackedWidget *stackedWidget) +{ + StackedWidgetCommand::init(stackedWidget); + setText(QApplication::translate("Command", "Delete Page")); +} + +void DeleteStackedWidgetPageCommand::redo() +{ + removePage(); + cheapUpdate(); +} + +void DeleteStackedWidgetPageCommand::undo() +{ + addPage(); + cheapUpdate(); +} + +// ---- AddStackedWidgetPageCommand ---- +AddStackedWidgetPageCommand::AddStackedWidgetPageCommand(QDesignerFormWindowInterface *formWindow) + : StackedWidgetCommand(formWindow) +{ +} + +AddStackedWidgetPageCommand::~AddStackedWidgetPageCommand() +{ +} + +void AddStackedWidgetPageCommand::init(QStackedWidget *stackedWidget) +{ + init(stackedWidget, InsertBefore); +} + +void AddStackedWidgetPageCommand::init(QStackedWidget *stackedWidget, InsertionMode mode) +{ + m_stackedWidget = stackedWidget; + + m_index = m_stackedWidget->currentIndex(); + if (mode == InsertAfter) + m_index++; + m_widget = new QDesignerWidget(formWindow(), m_stackedWidget); + m_widget->setObjectName(QLatin1String("page")); + formWindow()->ensureUniqueObjectName(m_widget); + + setText(QApplication::translate("Command", "Insert Page")); + + QDesignerFormEditorInterface *core = formWindow()->core(); + core->metaDataBase()->add(m_widget); +} + +void AddStackedWidgetPageCommand::redo() +{ + addPage(); + cheapUpdate(); +} + +void AddStackedWidgetPageCommand::undo() +{ + removePage(); + cheapUpdate(); +} + +// ---- TabOrderCommand ---- +TabOrderCommand::TabOrderCommand(QDesignerFormWindowInterface *formWindow) + : QDesignerFormWindowCommand(QApplication::translate("Command", "Change Tab order"), formWindow), + m_widgetItem(0) +{ +} + +void TabOrderCommand::init(const QList &newTabOrder) +{ + QDesignerFormEditorInterface *core = formWindow()->core(); + Q_ASSERT(core); + + m_widgetItem = core->metaDataBase()->item(formWindow()); + Q_ASSERT(m_widgetItem); + m_oldTabOrder = m_widgetItem->tabOrder(); + m_newTabOrder = newTabOrder; +} + +void TabOrderCommand::redo() +{ + m_widgetItem->setTabOrder(m_newTabOrder); +} + +void TabOrderCommand::undo() +{ + m_widgetItem->setTabOrder(m_oldTabOrder); +} + +// ---- CreateMenuBarCommand ---- +CreateMenuBarCommand::CreateMenuBarCommand(QDesignerFormWindowInterface *formWindow) + : QDesignerFormWindowCommand(QApplication::translate("Command", "Create Menu Bar"), formWindow) +{ +} + +void CreateMenuBarCommand::init(QMainWindow *mainWindow) +{ + m_mainWindow = mainWindow; + QDesignerFormEditorInterface *core = formWindow()->core(); + m_menuBar = qobject_cast(core->widgetFactory()->createWidget(QLatin1String("QMenuBar"), m_mainWindow)); + core->widgetFactory()->initialize(m_menuBar); +} + +void CreateMenuBarCommand::redo() +{ + QDesignerFormEditorInterface *core = formWindow()->core(); + QDesignerContainerExtension *c; + c = qt_extension(core->extensionManager(), m_mainWindow); + c->addWidget(m_menuBar); + + m_menuBar->setObjectName(QLatin1String("menuBar")); + formWindow()->ensureUniqueObjectName(m_menuBar); + core->metaDataBase()->add(m_menuBar); + formWindow()->emitSelectionChanged(); + m_menuBar->setFocus(); +} + +void CreateMenuBarCommand::undo() +{ + QDesignerFormEditorInterface *core = formWindow()->core(); + QDesignerContainerExtension *c; + c = qt_extension(core->extensionManager(), m_mainWindow); + for (int i = 0; i < c->count(); ++i) { + if (c->widget(i) == m_menuBar) { + c->remove(i); + break; + } + } + + core->metaDataBase()->remove(m_menuBar); + formWindow()->emitSelectionChanged(); +} + +// ---- DeleteMenuBarCommand ---- +DeleteMenuBarCommand::DeleteMenuBarCommand(QDesignerFormWindowInterface *formWindow) + : QDesignerFormWindowCommand(QApplication::translate("Command", "Delete Menu Bar"), formWindow) +{ +} + +void DeleteMenuBarCommand::init(QMenuBar *menuBar) +{ + m_menuBar = menuBar; + m_mainWindow = qobject_cast(menuBar->parentWidget()); +} + +void DeleteMenuBarCommand::redo() +{ + if (m_mainWindow) { + QDesignerContainerExtension *c; + c = qt_extension(core()->extensionManager(), m_mainWindow); + Q_ASSERT(c != 0); + for (int i=0; icount(); ++i) { + if (c->widget(i) == m_menuBar) { + c->remove(i); + break; + } + } + } + + core()->metaDataBase()->remove(m_menuBar); + m_menuBar->hide(); + m_menuBar->setParent(formWindow()); + formWindow()->emitSelectionChanged(); +} + +void DeleteMenuBarCommand::undo() +{ + if (m_mainWindow) { + m_menuBar->setParent(m_mainWindow); + QDesignerContainerExtension *c; + c = qt_extension(core()->extensionManager(), m_mainWindow); + + c->addWidget(m_menuBar); + + core()->metaDataBase()->add(m_menuBar); + m_menuBar->show(); + formWindow()->emitSelectionChanged(); + } +} + +// ---- CreateStatusBarCommand ---- +CreateStatusBarCommand::CreateStatusBarCommand(QDesignerFormWindowInterface *formWindow) + : QDesignerFormWindowCommand(QApplication::translate("Command", "Create Status Bar"), formWindow) +{ +} + +void CreateStatusBarCommand::init(QMainWindow *mainWindow) +{ + m_mainWindow = mainWindow; + QDesignerFormEditorInterface *core = formWindow()->core(); + m_statusBar = qobject_cast(core->widgetFactory()->createWidget(QLatin1String("QStatusBar"), m_mainWindow)); + core->widgetFactory()->initialize(m_statusBar); +} + +void CreateStatusBarCommand::redo() +{ + QDesignerFormEditorInterface *core = formWindow()->core(); + QDesignerContainerExtension *c; + c = qt_extension(core->extensionManager(), m_mainWindow); + c->addWidget(m_statusBar); + + m_statusBar->setObjectName(QLatin1String("statusBar")); + formWindow()->ensureUniqueObjectName(m_statusBar); + core->metaDataBase()->add(m_statusBar); + formWindow()->emitSelectionChanged(); +} + +void CreateStatusBarCommand::undo() +{ + QDesignerFormEditorInterface *core = formWindow()->core(); + QDesignerContainerExtension *c = qt_extension(core->extensionManager(), m_mainWindow); + for (int i = 0; i < c->count(); ++i) { + if (c->widget(i) == m_statusBar) { + c->remove(i); + break; + } + } + + core->metaDataBase()->remove(m_statusBar); + formWindow()->emitSelectionChanged(); +} + +// ---- DeleteStatusBarCommand ---- +DeleteStatusBarCommand::DeleteStatusBarCommand(QDesignerFormWindowInterface *formWindow) + : QDesignerFormWindowCommand(QApplication::translate("Command", "Delete Status Bar"), formWindow) +{ +} + +void DeleteStatusBarCommand::init(QStatusBar *statusBar) +{ + m_statusBar = statusBar; + m_mainWindow = qobject_cast(statusBar->parentWidget()); +} + +void DeleteStatusBarCommand::redo() +{ + if (m_mainWindow) { + QDesignerContainerExtension *c = qt_extension(core()->extensionManager(), m_mainWindow); + Q_ASSERT(c != 0); + for (int i=0; icount(); ++i) { + if (c->widget(i) == m_statusBar) { + c->remove(i); + break; + } + } + } + + core()->metaDataBase()->remove(m_statusBar); + m_statusBar->hide(); + m_statusBar->setParent(formWindow()); + formWindow()->emitSelectionChanged(); +} + +void DeleteStatusBarCommand::undo() +{ + if (m_mainWindow) { + m_statusBar->setParent(m_mainWindow); + QDesignerContainerExtension *c = qt_extension(core()->extensionManager(), m_mainWindow); + + c->addWidget(m_statusBar); + + core()->metaDataBase()->add(m_statusBar); + m_statusBar->show(); + formWindow()->emitSelectionChanged(); + } +} + +// ---- AddToolBarCommand ---- +AddToolBarCommand::AddToolBarCommand(QDesignerFormWindowInterface *formWindow) + : QDesignerFormWindowCommand(QApplication::translate("Command", "Add Tool Bar"), formWindow) +{ +} + +void AddToolBarCommand::init(QMainWindow *mainWindow) +{ + m_mainWindow = mainWindow; + QDesignerWidgetFactoryInterface * wf = formWindow()->core()->widgetFactory(); + // Pass on 0 parent first to avoid reparenting flicker. + m_toolBar = qobject_cast(wf->createWidget(QLatin1String("QToolBar"), 0)); + wf->initialize(m_toolBar); + m_toolBar->hide(); +} + +void AddToolBarCommand::redo() +{ + QDesignerFormEditorInterface *core = formWindow()->core(); + core->metaDataBase()->add(m_toolBar); + + QDesignerContainerExtension *c = qt_extension(core->extensionManager(), m_mainWindow); + c->addWidget(m_toolBar); + + m_toolBar->setObjectName(QLatin1String("toolBar")); + formWindow()->ensureUniqueObjectName(m_toolBar); + setPropertySheetWindowTitle(core, m_toolBar, m_toolBar->objectName()); + formWindow()->emitSelectionChanged(); +} + +void AddToolBarCommand::undo() +{ + QDesignerFormEditorInterface *core = formWindow()->core(); + core->metaDataBase()->remove(m_toolBar); + QDesignerContainerExtension *c = qt_extension(core->extensionManager(), m_mainWindow); + for (int i = 0; i < c->count(); ++i) { + if (c->widget(i) == m_toolBar) { + c->remove(i); + break; + } + } + formWindow()->emitSelectionChanged(); +} + +// ---- DockWidgetCommand:: ---- +DockWidgetCommand::DockWidgetCommand(const QString &description, QDesignerFormWindowInterface *formWindow) + : QDesignerFormWindowCommand(description, formWindow) +{ +} + +DockWidgetCommand::~DockWidgetCommand() +{ +} + +void DockWidgetCommand::init(QDockWidget *dockWidget) +{ + m_dockWidget = dockWidget; +} + +// ---- AddDockWidgetCommand ---- +AddDockWidgetCommand::AddDockWidgetCommand(QDesignerFormWindowInterface *formWindow) + : QDesignerFormWindowCommand(QApplication::translate("Command", "Add Dock Window"), formWindow) +{ +} + +void AddDockWidgetCommand::init(QMainWindow *mainWindow, QDockWidget *dockWidget) +{ + m_mainWindow = mainWindow; + m_dockWidget = dockWidget; +} + +void AddDockWidgetCommand::init(QMainWindow *mainWindow) +{ + m_mainWindow = mainWindow; + QDesignerFormEditorInterface *core = formWindow()->core(); + m_dockWidget = qobject_cast(core->widgetFactory()->createWidget(QLatin1String("QDockWidget"), m_mainWindow)); +} + +void AddDockWidgetCommand::redo() +{ + QDesignerFormEditorInterface *core = formWindow()->core(); + QDesignerContainerExtension *c = qt_extension(core->extensionManager(), m_mainWindow); + c->addWidget(m_dockWidget); + + m_dockWidget->setObjectName(QLatin1String("dockWidget")); + formWindow()->ensureUniqueObjectName(m_dockWidget); + formWindow()->manageWidget(m_dockWidget); + formWindow()->emitSelectionChanged(); +} + +void AddDockWidgetCommand::undo() +{ + QDesignerFormEditorInterface *core = formWindow()->core(); + QDesignerContainerExtension *c = qt_extension(core->extensionManager(), m_mainWindow); + for (int i = 0; i < c->count(); ++i) { + if (c->widget(i) == m_dockWidget) { + c->remove(i); + break; + } + } + + formWindow()->unmanageWidget(m_dockWidget); + formWindow()->emitSelectionChanged(); +} + +// ---- AdjustWidgetSizeCommand ---- +AdjustWidgetSizeCommand::AdjustWidgetSizeCommand(QDesignerFormWindowInterface *formWindow) + : QDesignerFormWindowCommand(QString(), formWindow) +{ +} + +void AdjustWidgetSizeCommand::init(QWidget *widget) +{ + m_widget = widget; + setText(QApplication::translate("Command", "Adjust Size of '%1'").arg(widget->objectName())); +} + +QWidget *AdjustWidgetSizeCommand::widgetForAdjust() const +{ + QDesignerFormWindowInterface *fw = formWindow(); + // Return the outer, embedding widget if it is the main container + if (Utils::isCentralWidget(fw, m_widget)) + return fw->core()->integration()->containerWindow(m_widget); + return m_widget; +} + +void AdjustWidgetSizeCommand::redo() +{ + QWidget *aw = widgetForAdjust(); + m_geometry = aw->geometry(); + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + aw->adjustSize(); + const bool isMainContainer = aw != m_widget; + if (!isMainContainer) { + /* When doing adjustsize on a selected non-laid out child that has been enlarged + * and pushed partially over the top/left edge[s], it is possible that it "disappears" + * when shrinking. In that case, move it back so that it remains visible. */ + if (aw->parentWidget()->layout() == 0) { + const QRect contentsRect = aw->parentWidget()->contentsRect(); + const QRect newGeometry = aw->geometry(); + QPoint newPos = m_geometry.topLeft(); + if (newGeometry.bottom() <= contentsRect.y()) + newPos.setY(contentsRect.y()); + if (newGeometry.right() <= contentsRect.x()) + newPos.setX(contentsRect.x()); + if (newPos != m_geometry.topLeft()) + aw->move(newPos); + } + } + updatePropertyEditor(); +} + +void AdjustWidgetSizeCommand::undo() +{ + QWidget *aw = widgetForAdjust(); + aw->resize(m_geometry.size()); + if (m_geometry.topLeft() != aw->geometry().topLeft()) + aw->move(m_geometry.topLeft()); + updatePropertyEditor(); +} + +void AdjustWidgetSizeCommand::updatePropertyEditor() const +{ + if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) { + if (propertyEditor->object() == m_widget) + propertyEditor->setPropertyValue(QLatin1String("geometry"), m_widget->geometry(), true); + } +} +// ------------ ChangeFormLayoutItemRoleCommand + +ChangeFormLayoutItemRoleCommand::ChangeFormLayoutItemRoleCommand(QDesignerFormWindowInterface *formWindow) : + QDesignerFormWindowCommand(QApplication::translate("Command", "Change Form Layout Item Geometry"), formWindow), + m_operation(SpanningToLabel) +{ +} + +void ChangeFormLayoutItemRoleCommand::init(QWidget *widget, Operation op) +{ + m_widget = widget; + m_operation = op; +} + +void ChangeFormLayoutItemRoleCommand::redo() +{ + doOperation(m_operation); +} + +void ChangeFormLayoutItemRoleCommand::undo() +{ + doOperation(reverseOperation(m_operation)); +} + +ChangeFormLayoutItemRoleCommand::Operation ChangeFormLayoutItemRoleCommand::reverseOperation(Operation op) +{ + switch (op) { + case SpanningToLabel: + return LabelToSpanning; + case SpanningToField: + return FieldToSpanning; + case LabelToSpanning: + return SpanningToLabel; + case FieldToSpanning: + return SpanningToField; + } + return SpanningToField; +} + +void ChangeFormLayoutItemRoleCommand::doOperation(Operation op) +{ + QFormLayout *fl = ChangeFormLayoutItemRoleCommand::managedFormLayoutOf(formWindow()->core(), m_widget); + const int index = fl->indexOf(m_widget); + Q_ASSERT(index != -1); + int row; + QFormLayout::ItemRole role; + fl->getItemPosition (index, &row, &role); + Q_ASSERT(index != -1); + QLayoutItem *item = fl->takeAt(index); + const QRect area = QRect(0, row, 2, 1); + switch (op) { + case SpanningToLabel: + fl->setItem(row, QFormLayout::LabelRole, item); + QLayoutSupport::createEmptyCells(fl); + break; + case SpanningToField: + fl->setItem(row, QFormLayout::FieldRole, item); + QLayoutSupport::createEmptyCells(fl); + break; + case LabelToSpanning: + case FieldToSpanning: + QLayoutSupport::removeEmptyCells(fl, area); + fl->setItem(row, QFormLayout::SpanningRole, item); + break; + } +} + +unsigned ChangeFormLayoutItemRoleCommand::possibleOperations(QDesignerFormEditorInterface *core, QWidget *w) +{ + QFormLayout *fl = managedFormLayoutOf(core, w); + if (!fl) + return 0; + const int index = fl->indexOf(w); + if (index == -1) + return 0; + int row, col, colspan; + getFormLayoutItemPosition(fl, index, &row, &col, 0, &colspan); + // Spanning item? + if (colspan > 1) + return SpanningToLabel|SpanningToField; + // Is the neighbouring column free, that is, can the current item be expanded? + const QFormLayout::ItemRole neighbouringRole = col == 0 ? QFormLayout::FieldRole : QFormLayout::LabelRole; + const bool empty = LayoutInfo::isEmptyItem(fl->itemAt(row, neighbouringRole)); + if (empty) + return col == 0 ? LabelToSpanning : FieldToSpanning; + return 0; +} + +QFormLayout *ChangeFormLayoutItemRoleCommand::managedFormLayoutOf(QDesignerFormEditorInterface *core, QWidget *w) +{ + if (QLayout *layout = LayoutInfo::managedLayout(core, w->parentWidget())) + if (QFormLayout *fl = qobject_cast(layout)) + return fl; + return 0; +} + +// ---- ChangeLayoutItemGeometry ---- +ChangeLayoutItemGeometry::ChangeLayoutItemGeometry(QDesignerFormWindowInterface *formWindow) + : QDesignerFormWindowCommand(QApplication::translate("Command", "Change Layout Item Geometry"), formWindow) +{ +} + +void ChangeLayoutItemGeometry::init(QWidget *widget, int row, int column, int rowspan, int colspan) +{ + m_widget = widget; + Q_ASSERT(m_widget->parentWidget() != 0); + + QLayout *layout = LayoutInfo::managedLayout(formWindow()->core(), m_widget->parentWidget()); + Q_ASSERT(layout != 0); + + QGridLayout *grid = qobject_cast(layout); + Q_ASSERT(grid != 0); + + const int itemIndex = grid->indexOf(m_widget); + Q_ASSERT(itemIndex != -1); + + int current_row, current_column, current_rowspan, current_colspan; + grid->getItemPosition(itemIndex, ¤t_row, ¤t_column, ¤t_rowspan, ¤t_colspan); + + m_oldInfo.setRect(current_column, current_row, current_colspan, current_rowspan); + m_newInfo.setRect(column, row, colspan, rowspan); +} + +void ChangeLayoutItemGeometry::changeItemPosition(const QRect &g) +{ + QLayout *layout = LayoutInfo::managedLayout(formWindow()->core(), m_widget->parentWidget()); + Q_ASSERT(layout != 0); + + QGridLayout *grid = qobject_cast(layout); + Q_ASSERT(grid != 0); + + const int itemIndex = grid->indexOf(m_widget); + Q_ASSERT(itemIndex != -1); + + QLayoutItem *item = grid->takeAt(itemIndex); + delete item; + + if (!QLayoutSupport::removeEmptyCells(grid, g)) + qWarning() << "ChangeLayoutItemGeometry::changeItemPosition: Nonempty cell at " << g << '.'; + + grid->addWidget(m_widget, g.top(), g.left(), g.height(), g.width()); + + grid->invalidate(); + grid->activate(); + + QLayoutSupport::createEmptyCells(grid); + + formWindow()->clearSelection(false); + formWindow()->selectWidget(m_widget, true); +} + +void ChangeLayoutItemGeometry::redo() +{ + changeItemPosition(m_newInfo); +} + +void ChangeLayoutItemGeometry::undo() +{ + changeItemPosition(m_oldInfo); +} + +// ---- ContainerWidgetCommand ---- +ContainerWidgetCommand::ContainerWidgetCommand(QDesignerFormWindowInterface *formWindow) : + QDesignerFormWindowCommand(QString(), formWindow), + m_index(-1) +{ +} + +ContainerWidgetCommand::~ContainerWidgetCommand() +{ +} + +QDesignerContainerExtension *ContainerWidgetCommand::containerExtension() const +{ + QExtensionManager *mgr = core()->extensionManager(); + return qt_extension(mgr, m_containerWidget); +} + +void ContainerWidgetCommand::init(QWidget *containerWidget) +{ + m_containerWidget = containerWidget; + + if (QDesignerContainerExtension *c = containerExtension()) { + m_index = c->currentIndex(); + m_widget = c->widget(m_index); + } +} + +void ContainerWidgetCommand::removePage() +{ + if (QDesignerContainerExtension *c = containerExtension()) { + if (const int count = c->count()) { + // Undo add after last? + const int deleteIndex = m_index >= 0 ? m_index : count - 1; + c->remove(deleteIndex); + m_widget->hide(); + m_widget->setParent(formWindow()); + } + } +} + +void ContainerWidgetCommand::addPage() +{ + if (QDesignerContainerExtension *c = containerExtension()) { + int newCurrentIndex; + if (m_index >= 0) { + c->insertWidget(m_index, m_widget); + newCurrentIndex = m_index; + } else { + c->addWidget(m_widget); + newCurrentIndex = c->count() -1 ; + } + m_widget->show(); + c->setCurrentIndex(newCurrentIndex); + } +} + +// ---- DeleteContainerWidgetPageCommand ---- +DeleteContainerWidgetPageCommand::DeleteContainerWidgetPageCommand(QDesignerFormWindowInterface *formWindow) + : ContainerWidgetCommand(formWindow) +{ +} + +DeleteContainerWidgetPageCommand::~DeleteContainerWidgetPageCommand() +{ +} + +void DeleteContainerWidgetPageCommand::init(QWidget *containerWidget, ContainerType ct) +{ + ContainerWidgetCommand::init(containerWidget); + switch (ct) { + case WizardContainer: + case PageContainer: + setText(QApplication::translate("Command", "Delete Page")); + break; + case MdiContainer: + setText(QApplication::translate("Command", "Delete Subwindow")); + break; + } +} + +void DeleteContainerWidgetPageCommand::redo() +{ + removePage(); + cheapUpdate(); +} + +void DeleteContainerWidgetPageCommand::undo() +{ + addPage(); + cheapUpdate(); +} + +// ---- AddContainerWidgetPageCommand ---- +AddContainerWidgetPageCommand::AddContainerWidgetPageCommand(QDesignerFormWindowInterface *formWindow) + : ContainerWidgetCommand(formWindow) +{ +} + +AddContainerWidgetPageCommand::~AddContainerWidgetPageCommand() +{ +} + +void AddContainerWidgetPageCommand::init(QWidget *containerWidget, ContainerType ct, InsertionMode mode) +{ + m_containerWidget = containerWidget; + + if (QDesignerContainerExtension *c = containerExtension()) { + m_index = c->currentIndex(); + if (m_index >= 0 && mode == InsertAfter) + m_index++; + m_widget = 0; + const QDesignerFormEditorInterface *core = formWindow()->core(); + switch (ct) { + case PageContainer: + setText(QApplication::translate("Command", "Insert Page")); + m_widget = new QDesignerWidget(formWindow(), m_containerWidget); + m_widget->setObjectName(QLatin1String("page")); + break; + case MdiContainer: + setText(QApplication::translate("Command", "Insert Subwindow")); + m_widget = new QDesignerWidget(formWindow(), m_containerWidget); + m_widget->setObjectName(QLatin1String("subwindow")); + setPropertySheetWindowTitle(core, m_widget, QApplication::translate("Command", "Subwindow")); + break; + case WizardContainer: // Apply style, don't manage + m_widget = core->widgetFactory()->createWidget(QLatin1String("QWizardPage"), 0); + break; + } + formWindow()->ensureUniqueObjectName(m_widget); + core->metaDataBase()->add(m_widget); + } +} + +void AddContainerWidgetPageCommand::redo() +{ + addPage(); + cheapUpdate(); +} + +void AddContainerWidgetPageCommand::undo() +{ + removePage(); + cheapUpdate(); +} + +ChangeCurrentPageCommand::ChangeCurrentPageCommand(QDesignerFormWindowInterface *formWindow) + : + QDesignerFormWindowCommand(QString(), formWindow), m_oldIndex(0), m_newIndex(0) +{ +} + +ChangeCurrentPageCommand::~ChangeCurrentPageCommand() +{ +} + +QDesignerContainerExtension *ChangeCurrentPageCommand::containerExtension() const +{ + QExtensionManager *mgr = core()->extensionManager(); + return qt_extension(mgr, m_containerWidget); +} + +void ChangeCurrentPageCommand::init(QWidget *containerWidget, int newIndex) +{ + m_containerWidget = containerWidget; + + if (QDesignerContainerExtension *c = containerExtension()) { + m_newIndex = newIndex; + m_oldIndex = c->currentIndex(); + m_widget = c->widget(m_oldIndex); + } +} + +void ChangeCurrentPageCommand::redo() +{ + containerExtension()->setCurrentIndex(m_newIndex); +} + +void ChangeCurrentPageCommand::undo() +{ + containerExtension()->setCurrentIndex(m_oldIndex); +} + +static int itemRoles[] = { + Qt::DecorationPropertyRole, + Qt::DisplayPropertyRole, + Qt::ToolTipPropertyRole, + Qt::StatusTipPropertyRole, + Qt::WhatsThisPropertyRole, + Qt::FontRole, + Qt::TextAlignmentRole, + Qt::BackgroundRole, + Qt::ForegroundRole, + Qt::CheckStateRole, + -1 +}; + +template +static void copyRoleFromItem(ItemData *id, int role, const T *item) +{ + QVariant v = item->data(role); + if (v.isValid()) + id->m_properties.insert(role, v); +} + +template +static void copyRolesFromItem(ItemData *id, const T *item, bool editor) +{ + static const int defaultFlags = T().flags(); + + for (int i = 0; itemRoles[i] != -1; i++) + copyRoleFromItem(id, itemRoles[i], item); + + if (editor) + copyRoleFromItem(id, ItemFlagsShadowRole, item); + else if (item->flags() != defaultFlags) + id->m_properties.insert(ItemFlagsShadowRole, QVariant::fromValue((int)item->flags())); +} + +template +static void copyRolesToItem(const ItemData *id, T *item, DesignerIconCache *iconCache, bool editor) +{ + QHash::const_iterator it = id->m_properties.constBegin(), + end = id->m_properties.constEnd(); + for (; it != end; ++it) + if (it.value().isValid()) { + if (!editor && it.key() == ItemFlagsShadowRole) { + item->setFlags((Qt::ItemFlags)it.value().toInt()); + } else { + item->setData(it.key(), it.value()); + switch (it.key()) { + case Qt::DecorationPropertyRole: + if (iconCache) + item->setIcon(iconCache->icon(qvariant_cast(it.value()))); + break; + case Qt::DisplayPropertyRole: + item->setText(qvariant_cast(it.value()).value()); + break; + case Qt::ToolTipPropertyRole: + item->setToolTip(qvariant_cast(it.value()).value()); + break; + case Qt::StatusTipPropertyRole: + item->setStatusTip(qvariant_cast(it.value()).value()); + break; + case Qt::WhatsThisPropertyRole: + item->setWhatsThis(qvariant_cast(it.value()).value()); + break; + } + } + } + + if (editor) + item->setFlags(item->flags() | Qt::ItemIsEditable); +} + +ItemData::ItemData(const QListWidgetItem *item, bool editor) +{ + copyRolesFromItem(this, item, editor); +} + +QListWidgetItem *ItemData::createListItem(DesignerIconCache *iconCache, bool editor) const +{ + QListWidgetItem *item = new QListWidgetItem(); + copyRolesToItem(this, item, iconCache, editor); + return item; +} + +ItemData::ItemData(const QTableWidgetItem *item, bool editor) +{ + copyRolesFromItem(this, item, editor); +} + +QTableWidgetItem *ItemData::createTableItem(DesignerIconCache *iconCache, bool editor) const +{ + QTableWidgetItem *item = new QTableWidgetItem; + copyRolesToItem(this, item, iconCache, editor); + return item; +} + +static void copyRoleFromItem(ItemData *id, int role, const QTreeWidgetItem *item, int column) +{ + QVariant v = item->data(column, role); + if (v.isValid()) + id->m_properties.insert(role, v); +} + +ItemData::ItemData(const QTreeWidgetItem *item, int column) +{ + copyRoleFromItem(this, Qt::EditRole, item, column); + PropertySheetStringValue str(item->text(column)); + m_properties.insert(Qt::DisplayPropertyRole, QVariant::fromValue(str)); + + for (int i = 0; itemRoles[i] != -1; i++) + copyRoleFromItem(this, itemRoles[i], item, column); +} + +void ItemData::fillTreeItemColumn(QTreeWidgetItem *item, int column, DesignerIconCache *iconCache) const +{ + QHash::const_iterator it = m_properties.constBegin(), end = m_properties.constEnd(); + for (; it != end; ++it) + if (it.value().isValid()) { + item->setData(column, it.key(), it.value()); + switch (it.key()) { + case Qt::DecorationPropertyRole: + if (iconCache) + item->setIcon(column, iconCache->icon(qvariant_cast(it.value()))); + break; + case Qt::DisplayPropertyRole: + item->setText(column, qvariant_cast(it.value()).value()); + break; + case Qt::ToolTipPropertyRole: + item->setToolTip(column, qvariant_cast(it.value()).value()); + break; + case Qt::StatusTipPropertyRole: + item->setStatusTip(column, qvariant_cast(it.value()).value()); + break; + case Qt::WhatsThisPropertyRole: + item->setWhatsThis(column, qvariant_cast(it.value()).value()); + break; + } + } +} + +ListContents::ListContents(const QTreeWidgetItem *item) +{ + for (int i = 0; i < item->columnCount(); i++) + m_items.append(ItemData(item, i)); +} + +QTreeWidgetItem *ListContents::createTreeItem(DesignerIconCache *iconCache) const +{ + QTreeWidgetItem *item = new QTreeWidgetItem; + int i = 0; + foreach (const ItemData &id, m_items) + id.fillTreeItemColumn(item, i++, iconCache); + return item; +} + +void ListContents::createFromListWidget(const QListWidget *listWidget, bool editor) +{ + m_items.clear(); + + for (int i = 0; i < listWidget->count(); i++) + m_items.append(ItemData(listWidget->item(i), editor)); +} + +void ListContents::applyToListWidget(QListWidget *listWidget, DesignerIconCache *iconCache, bool editor) const +{ + listWidget->clear(); + + int i = 0; + foreach (const ItemData &entry, m_items) { + if (!entry.isValid()) + new QListWidgetItem(TableWidgetContents::defaultHeaderText(i), listWidget); + else + listWidget->addItem(entry.createListItem(iconCache, editor)); + i++; + } +} + +void ListContents::createFromComboBox(const QComboBox *comboBox) +{ + m_items.clear(); + + const int count = comboBox->count(); + for (int i = 0; i < count; i++) { + // We might encounter items added in a custom combo + // constructor. Ignore those. + const QVariant textValue = comboBox->itemData(i, Qt::DisplayPropertyRole); + if (!textValue.isNull()) { + ItemData entry; + entry.m_properties.insert(Qt::DisplayPropertyRole, textValue); + const QVariant iconValue = comboBox->itemData(i, Qt::DecorationPropertyRole); + if (!iconValue.isNull()) + entry.m_properties.insert(Qt::DecorationPropertyRole, iconValue); + m_items.append(entry); + } + } +} + +void ListContents::applyToComboBox(QComboBox *comboBox, DesignerIconCache *iconCache) const +{ + comboBox->clear(); + + foreach (const ItemData &hash, m_items) { + QIcon icon; + if (iconCache) + icon = iconCache->icon(qvariant_cast( + hash.m_properties[Qt::DecorationPropertyRole])); + QVariant var = hash.m_properties[Qt::DisplayPropertyRole]; + PropertySheetStringValue str = qvariant_cast(var); + comboBox->addItem(icon, str.value()); + comboBox->setItemData(comboBox->count() - 1, + var, + Qt::DisplayPropertyRole); + comboBox->setItemData(comboBox->count() - 1, + hash.m_properties[Qt::DecorationPropertyRole], + Qt::DecorationPropertyRole); + } +} + +// --------- TableWidgetContents + +TableWidgetContents::TableWidgetContents() : + m_columnCount(0), + m_rowCount(0) +{ +} + +void TableWidgetContents::clear() +{ + m_horizontalHeader.m_items.clear(); + m_verticalHeader.m_items.clear(); + m_items.clear(); + m_columnCount = 0; + m_rowCount = 0; +} + +QString TableWidgetContents::defaultHeaderText(int i) +{ + return QString::number(i + 1); +} + +bool TableWidgetContents::nonEmpty(const QTableWidgetItem *item, int headerColumn) +{ + static int defaultFlags = QTableWidgetItem().flags(); + + if (item->flags() != defaultFlags) + return true; + + QString text = qvariant_cast(item->data(Qt::DisplayPropertyRole)).value(); + if (!text.isEmpty()) { + if (headerColumn < 0 || text != defaultHeaderText(headerColumn)) + return true; + } else { + // FIXME: This doesn't seem to make sense + return true; + } + + for (int i = 0; itemRoles[i] != -1; i++) + if (itemRoles[i] != Qt::DisplayPropertyRole && item->data(itemRoles[i]).isValid()) + return true; + + return false; +} + +void TableWidgetContents::insertHeaderItem(const QTableWidgetItem *item, int i, ListContents *header, bool editor) +{ + if (nonEmpty(item, i)) + header->m_items.append(ItemData(item, editor)); + else + header->m_items.append(ItemData()); +} + +void TableWidgetContents::fromTableWidget(const QTableWidget *tableWidget, bool editor) +{ + clear(); + m_columnCount = tableWidget->columnCount(); + m_rowCount = tableWidget->rowCount(); + // horiz header: Legacy behaviour: auto-generate number for empty items + for (int col = 0; col < m_columnCount; col++) + if (const QTableWidgetItem *item = tableWidget->horizontalHeaderItem(col)) + insertHeaderItem(item, col, &m_horizontalHeader, editor); + // vertical header: Legacy behaviour: auto-generate number for empty items + for (int row = 0; row < m_rowCount; row++) + if (const QTableWidgetItem *item = tableWidget->verticalHeaderItem(row)) + insertHeaderItem(item, row, &m_verticalHeader, editor); + // cell data + for (int col = 0; col < m_columnCount; col++) + for (int row = 0; row < m_rowCount; row++) + if (const QTableWidgetItem *item = tableWidget->item(row, col)) + if (nonEmpty(item, -1)) + m_items.insert(CellRowColumnAddress(row, col), ItemData(item, editor)); +} + +void TableWidgetContents::applyToTableWidget(QTableWidget *tableWidget, DesignerIconCache *iconCache, bool editor) const +{ + tableWidget->clear(); + + tableWidget->setColumnCount(m_columnCount); + tableWidget->setRowCount(m_rowCount); + + // horiz header + int col = 0; + foreach (const ItemData &id, m_horizontalHeader.m_items) { + if (id.isValid()) + tableWidget->setHorizontalHeaderItem(col, id.createTableItem(iconCache, editor)); + col++; + } + // vertical header + int row = 0; + foreach (const ItemData &id, m_verticalHeader.m_items) { + if (id.isValid()) + tableWidget->setVerticalHeaderItem(row, id.createTableItem(iconCache, editor)); + row++; + } + // items + const TableItemMap::const_iterator icend = m_items.constEnd(); + for (TableItemMap::const_iterator it = m_items.constBegin(); it != icend; ++ it) + tableWidget->setItem(it.key().first, it.key().second, it.value().createTableItem(iconCache, editor)); +} + +bool TableWidgetContents::operator==(const TableWidgetContents &rhs) const +{ + if (m_columnCount != rhs.m_columnCount || m_rowCount != rhs.m_rowCount) + return false; + + return m_horizontalHeader.m_items == rhs.m_horizontalHeader.m_items && + m_verticalHeader.m_items == rhs.m_verticalHeader.m_items && + m_items == rhs.m_items; +} + +// ---- ChangeTableContentsCommand ---- +ChangeTableContentsCommand::ChangeTableContentsCommand(QDesignerFormWindowInterface *formWindow) : + QDesignerFormWindowCommand(QApplication::translate("Command", "Change Table Contents"), + formWindow), m_iconCache(0) +{ + FormWindowBase *fwb = qobject_cast(formWindow); + if (fwb) + m_iconCache = fwb->iconCache(); +} + +void ChangeTableContentsCommand::init(QTableWidget *tableWidget, + const TableWidgetContents &oldCont, const TableWidgetContents &newCont) +{ + m_tableWidget = tableWidget; + m_oldContents = oldCont; + m_newContents = newCont; +} + +void ChangeTableContentsCommand::redo() +{ + m_newContents.applyToTableWidget(m_tableWidget, m_iconCache, false); + QMetaObject::invokeMethod(m_tableWidget, "updateGeometries"); +} + +void ChangeTableContentsCommand::undo() +{ + m_oldContents.applyToTableWidget(m_tableWidget, m_iconCache, false); + QMetaObject::invokeMethod(m_tableWidget, "updateGeometries"); +} + +// --------- TreeWidgetContents +TreeWidgetContents::ItemContents::ItemContents(const QTreeWidgetItem *item, bool editor) : + ListContents(item) +{ + static const int defaultFlags = QTreeWidgetItem().flags(); + + if (editor) { + QVariant v = item->data(0, ItemFlagsShadowRole); + m_itemFlags = v.isValid() ? v.toInt() : -1; + } else { + m_itemFlags = (item->flags() != defaultFlags) ? (int)item->flags() : -1; + } + + for (int i = 0; i < item->childCount(); i++) + m_children.append(ItemContents(item->child(i), editor)); +} + +QTreeWidgetItem *TreeWidgetContents::ItemContents::createTreeItem(DesignerIconCache *iconCache, bool editor) const +{ + QTreeWidgetItem *item = ListContents::createTreeItem(iconCache); + + if (editor) + item->setFlags(item->flags() | Qt::ItemIsEditable); + + if (m_itemFlags != -1) { + if (editor) + item->setData(0, ItemFlagsShadowRole, QVariant::fromValue(m_itemFlags)); + else + item->setFlags((Qt::ItemFlags)m_itemFlags); + } + + foreach (const ItemContents &ic, m_children) + item->addChild(ic.createTreeItem(iconCache, editor)); + + return item; +} + +bool TreeWidgetContents::ItemContents::operator==(const TreeWidgetContents::ItemContents &rhs) const +{ + return + m_itemFlags == rhs.m_itemFlags && + m_items == rhs.m_items && + m_children == rhs.m_children; +} + +void TreeWidgetContents::clear() +{ + m_headerItem.m_items.clear(); + m_rootItems.clear(); +} + +void TreeWidgetContents::fromTreeWidget(const QTreeWidget *treeWidget, bool editor) +{ + clear(); + m_headerItem = ListContents(treeWidget->headerItem()); + for (int col = 0; col < treeWidget->topLevelItemCount(); col++) + m_rootItems.append(ItemContents(treeWidget->topLevelItem(col), editor)); +} + +void TreeWidgetContents::applyToTreeWidget(QTreeWidget *treeWidget, DesignerIconCache *iconCache, bool editor) const +{ + treeWidget->clear(); + + treeWidget->setColumnCount(m_headerItem.m_items.count()); + treeWidget->setHeaderItem(m_headerItem.createTreeItem(iconCache)); + foreach (const ItemContents &ic, m_rootItems) + treeWidget->addTopLevelItem(ic.createTreeItem(iconCache, editor)); + treeWidget->expandAll(); +} + +bool TreeWidgetContents::operator==(const TreeWidgetContents &rhs) const +{ + return + m_headerItem == rhs.m_headerItem && + m_rootItems == rhs.m_rootItems; +} + +// ---- ChangeTreeContentsCommand ---- +ChangeTreeContentsCommand::ChangeTreeContentsCommand(QDesignerFormWindowInterface *formWindow) + : QDesignerFormWindowCommand(QApplication::translate("Command", "Change Tree Contents"), formWindow), + m_iconCache(0) +{ + FormWindowBase *fwb = qobject_cast(formWindow); + if (fwb) + m_iconCache = fwb->iconCache(); +} + +void ChangeTreeContentsCommand::init(QTreeWidget *treeWidget, + const TreeWidgetContents &oldState, const TreeWidgetContents &newState) +{ + m_treeWidget = treeWidget; + m_oldState = oldState; + m_newState = newState; +} + +void ChangeTreeContentsCommand::redo() +{ + m_newState.applyToTreeWidget(m_treeWidget, m_iconCache, false); +} + +void ChangeTreeContentsCommand::undo() +{ + m_oldState.applyToTreeWidget(m_treeWidget, m_iconCache, false); +} + +// ---- ChangeListContentsCommand ---- +ChangeListContentsCommand::ChangeListContentsCommand(QDesignerFormWindowInterface *formWindow) + : QDesignerFormWindowCommand(QString(), formWindow), m_iconCache(0) +{ + FormWindowBase *fwb = qobject_cast(formWindow); + if (fwb) + m_iconCache = fwb->iconCache(); +} + +void ChangeListContentsCommand::init(QListWidget *listWidget, + const ListContents &oldItems, const ListContents &items) +{ + m_listWidget = listWidget; + m_comboBox = 0; + + m_newItemsState = items; + m_oldItemsState = oldItems; +} + +void ChangeListContentsCommand::init(QComboBox *comboBox, + const ListContents &oldItems, const ListContents &items) +{ + m_listWidget = 0; + m_comboBox = comboBox; + + m_newItemsState = items; + m_oldItemsState = oldItems; +} + +void ChangeListContentsCommand::redo() +{ + if (m_listWidget) + m_newItemsState.applyToListWidget(m_listWidget, m_iconCache, false); + else if (m_comboBox) + m_newItemsState.applyToComboBox(m_comboBox, m_iconCache); +} + +void ChangeListContentsCommand::undo() +{ + if (m_listWidget) + m_oldItemsState.applyToListWidget(m_listWidget, m_iconCache, false); + else if (m_comboBox) + m_oldItemsState.applyToComboBox(m_comboBox, m_iconCache); +} + +// ---- AddActionCommand ---- + +AddActionCommand::AddActionCommand(QDesignerFormWindowInterface *formWindow) : + QDesignerFormWindowCommand(QApplication::translate("Command", "Add action"), formWindow) +{ + m_action = 0; +} + +void AddActionCommand::init(QAction *action) +{ + Q_ASSERT(m_action == 0); + m_action = action; +} + +void AddActionCommand::redo() +{ + core()->actionEditor()->setFormWindow(formWindow()); + core()->actionEditor()->manageAction(m_action); +} + +void AddActionCommand::undo() +{ + core()->actionEditor()->setFormWindow(formWindow()); + core()->actionEditor()->unmanageAction(m_action); +} + +// ---- RemoveActionCommand ---- + +RemoveActionCommand::RemoveActionCommand(QDesignerFormWindowInterface *formWindow) : + QDesignerFormWindowCommand(QApplication::translate("Command", "Remove action"), formWindow), + m_action(0) +{ +} + +static RemoveActionCommand::ActionData findActionIn(QAction *action) +{ + RemoveActionCommand::ActionData result; + // We only want menus and toolbars, no toolbuttons. + foreach (QWidget *widget, action->associatedWidgets()) + if (qobject_cast(widget) || qobject_cast(widget)) { + const QList actionList = widget->actions(); + const int size = actionList.size(); + for (int i = 0; i < size; ++i) { + if (actionList.at(i) == action) { + QAction *before = 0; + if (i + 1 < size) + before = actionList.at(i + 1); + result.append(RemoveActionCommand::ActionDataItem(before, widget)); + break; + } + } + } + return result; +} + +void RemoveActionCommand::init(QAction *action) +{ + Q_ASSERT(m_action == 0); + m_action = action; + + m_actionData = findActionIn(action); +} + +void RemoveActionCommand::redo() +{ + QDesignerFormWindowInterface *fw = formWindow(); + foreach (const ActionDataItem &item, m_actionData) { + item.widget->removeAction(m_action); + } + // Notify components (for example, signal slot editor) + if (qdesigner_internal::FormWindowBase *fwb = qobject_cast(fw)) + fwb->emitObjectRemoved(m_action); + + core()->actionEditor()->setFormWindow(fw); + core()->actionEditor()->unmanageAction(m_action); + if (!m_actionData.empty()) + core()->objectInspector()->setFormWindow(fw); +} + +void RemoveActionCommand::undo() +{ + core()->actionEditor()->setFormWindow(formWindow()); + core()->actionEditor()->manageAction(m_action); + foreach (const ActionDataItem &item, m_actionData) { + item.widget->insertAction(item.before, m_action); + } + if (!m_actionData.empty()) + core()->objectInspector()->setFormWindow(formWindow()); +} + +// ---- ActionInsertionCommand ---- + +ActionInsertionCommand::ActionInsertionCommand(const QString &text, QDesignerFormWindowInterface *formWindow) : + QDesignerFormWindowCommand(text, formWindow), + m_parentWidget(0), + m_action(0), + m_beforeAction(0), + m_update(false) +{ +} + +void ActionInsertionCommand::init(QWidget *parentWidget, QAction *action, QAction *beforeAction, bool update) +{ + Q_ASSERT(m_parentWidget == 0); + Q_ASSERT(m_action == 0); + + m_parentWidget = parentWidget; + m_action = action; + m_beforeAction = beforeAction; + m_update = update; +} + +void ActionInsertionCommand::insertAction() +{ + Q_ASSERT(m_action != 0); + Q_ASSERT(m_parentWidget != 0); + + if (m_beforeAction) + m_parentWidget->insertAction(m_beforeAction, m_action); + else + m_parentWidget->addAction(m_action); + + if (m_update) { + cheapUpdate(); + if (QMenu *menu = m_action->menu()) + selectUnmanagedObject(menu); + else + selectUnmanagedObject(m_action); + PropertyHelper::triggerActionChanged(m_action); // Update Used column in action editor. + } +} +void ActionInsertionCommand::removeAction() +{ + Q_ASSERT(m_action != 0); + Q_ASSERT(m_parentWidget != 0); + + if (QDesignerMenu *menu = qobject_cast(m_parentWidget)) + menu->hideSubMenu(); + + m_parentWidget->removeAction(m_action); + + if (m_update) { + cheapUpdate(); + selectUnmanagedObject(m_parentWidget); + PropertyHelper::triggerActionChanged(m_action); // Update Used column in action editor. + } +} + +InsertActionIntoCommand::InsertActionIntoCommand(QDesignerFormWindowInterface *formWindow) : + ActionInsertionCommand(QApplication::translate("Command", "Add action"), formWindow) +{ +} +// ---- RemoveActionFromCommand ---- + +RemoveActionFromCommand::RemoveActionFromCommand(QDesignerFormWindowInterface *formWindow) : + ActionInsertionCommand(QApplication::translate("Command", "Remove action"), formWindow) +{ +} + +// ---- AddMenuActionCommand ---- + +MenuActionCommand::MenuActionCommand(const QString &text, QDesignerFormWindowInterface *formWindow) : + QDesignerFormWindowCommand(text, formWindow), + m_action(0), + m_actionBefore(0), + m_menuParent(0), + m_associatedWidget(0), + m_objectToSelect(0) +{ +} + +void MenuActionCommand::init(QAction *action, QAction *actionBefore, + QWidget *associatedWidget, QWidget *objectToSelect) +{ + QMenu *menu = action->menu(); + Q_ASSERT(menu); + m_menuParent = menu->parentWidget(); + m_action = action; + m_actionBefore = actionBefore; + m_associatedWidget = associatedWidget; + m_objectToSelect = objectToSelect; +} + +void MenuActionCommand::insertMenu() +{ + core()->metaDataBase()->add(m_action); + QMenu *menu = m_action->menu(); + if (m_menuParent && menu->parentWidget() != m_menuParent) + menu->setParent(m_menuParent); + core()->metaDataBase()->add(menu); + m_associatedWidget->insertAction(m_actionBefore, m_action); + cheapUpdate(); + selectUnmanagedObject(menu); +} + +void MenuActionCommand::removeMenu() +{ + m_action->menu()->setParent(0); + QMenu *menu = m_action->menu(); + core()->metaDataBase()->remove(menu); + menu->setParent(0); + core()->metaDataBase()->remove(m_action); + m_associatedWidget->removeAction(m_action); + cheapUpdate(); + selectUnmanagedObject(m_objectToSelect); +} + +AddMenuActionCommand::AddMenuActionCommand(QDesignerFormWindowInterface *formWindow) : + MenuActionCommand(QApplication::translate("Command", "Add menu"), formWindow) +{ +} + +// ---- RemoveMenuActionCommand ---- +RemoveMenuActionCommand::RemoveMenuActionCommand(QDesignerFormWindowInterface *formWindow) : + MenuActionCommand(QApplication::translate("Command", "Remove menu"), formWindow) +{ +} + +// ---- CreateSubmenuCommand ---- +CreateSubmenuCommand::CreateSubmenuCommand(QDesignerFormWindowInterface *formWindow) : + QDesignerFormWindowCommand(QApplication::translate("Command", "Create submenu"), formWindow), + m_action(0), + m_menu(0), + m_objectToSelect(0) +{ +} + +void CreateSubmenuCommand::init(QDesignerMenu *menu, QAction *action, QObject *objectToSelect) +{ + m_menu = menu; + m_action = action; + m_objectToSelect = objectToSelect; +} + +void CreateSubmenuCommand::redo() +{ + m_menu->createRealMenuAction(m_action); + cheapUpdate(); + if (m_objectToSelect) + selectUnmanagedObject(m_objectToSelect); +} + +void CreateSubmenuCommand::undo() +{ + m_menu->removeRealMenu(m_action); + cheapUpdate(); + selectUnmanagedObject(m_menu); +} + +// ---- DeleteToolBarCommand ---- +DeleteToolBarCommand::DeleteToolBarCommand(QDesignerFormWindowInterface *formWindow) + : QDesignerFormWindowCommand(QApplication::translate("Command", "Delete Tool Bar"), formWindow) +{ +} + +void DeleteToolBarCommand::init(QToolBar *toolBar) +{ + m_toolBar = toolBar; + m_mainWindow = qobject_cast(toolBar->parentWidget()); +} + +void DeleteToolBarCommand::redo() +{ + if (m_mainWindow) { + QDesignerContainerExtension *c = qt_extension(core()->extensionManager(), m_mainWindow); + Q_ASSERT(c != 0); + for (int i=0; icount(); ++i) { + if (c->widget(i) == m_toolBar) { + c->remove(i); + break; + } + } + } + + core()->metaDataBase()->remove(m_toolBar); + m_toolBar->hide(); + m_toolBar->setParent(formWindow()); + formWindow()->emitSelectionChanged(); +} + +void DeleteToolBarCommand::undo() +{ + if (m_mainWindow) { + m_toolBar->setParent(m_mainWindow); + QDesignerContainerExtension *c = qt_extension(core()->extensionManager(), m_mainWindow); + + c->addWidget(m_toolBar); + + core()->metaDataBase()->add(m_toolBar); + m_toolBar->show(); + formWindow()->emitSelectionChanged(); + } +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_command2.cpp b/src/designer/src/lib/shared/qdesigner_command2.cpp new file mode 100644 index 000000000..2b0a5a21a --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_command2.cpp @@ -0,0 +1,221 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_command2_p.h" +#include "formwindowbase_p.h" +#include "layoutinfo_p.h" +#include "qdesigner_command_p.h" +#include "widgetfactory_p.h" +#include "qlayout_widget_p.h" + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +MorphLayoutCommand::MorphLayoutCommand(QDesignerFormWindowInterface *formWindow) : + QDesignerFormWindowCommand(QString(), formWindow), + m_breakLayoutCommand(new BreakLayoutCommand(formWindow)), + m_layoutCommand(new LayoutCommand(formWindow)), + m_newType(LayoutInfo::VBox), + m_layoutBase(0) +{ +} + +MorphLayoutCommand::~MorphLayoutCommand() +{ + delete m_layoutCommand; + delete m_breakLayoutCommand; +} + +bool MorphLayoutCommand::init(QWidget *w, int newType) +{ + int oldType; + QDesignerFormWindowInterface *fw = formWindow(); + if (!canMorph(fw, w, &oldType) || oldType == newType) + return false; + m_layoutBase = w; + m_newType = newType; + // Find all managed widgets + m_widgets.clear(); + const QLayout *layout = LayoutInfo::managedLayout(fw->core(), w); + const int count = layout->count(); + for (int i = 0; i < count ; i++) { + if (QWidget *w = layout->itemAt(i)->widget()) + if (fw->isManaged(w)) + m_widgets.push_back(w); + } + const bool reparentLayoutWidget = false; // leave QLayoutWidget intact + m_breakLayoutCommand->init(m_widgets, m_layoutBase, reparentLayoutWidget); + m_layoutCommand->init(m_layoutBase, m_widgets, static_cast(m_newType), m_layoutBase, reparentLayoutWidget); + setText(formatDescription(core(), m_layoutBase, oldType, newType)); + return true; +} + +bool MorphLayoutCommand::canMorph(const QDesignerFormWindowInterface *formWindow, QWidget *w, int *ptrToCurrentType) +{ + if (ptrToCurrentType) + *ptrToCurrentType = LayoutInfo::NoLayout; + // We want a managed widget or a container page + // with a level-0 managed layout + QDesignerFormEditorInterface *core = formWindow->core(); + QLayout *layout = LayoutInfo::managedLayout(core, w); + if (!layout) + return false; + const LayoutInfo::Type type = LayoutInfo::layoutType(core, layout); + if (ptrToCurrentType) + *ptrToCurrentType = type; + switch (type) { + case LayoutInfo::HBox: + case LayoutInfo::VBox: + case LayoutInfo::Grid: + case LayoutInfo::Form: + return true; + break; + case LayoutInfo::NoLayout: + case LayoutInfo::HSplitter: // Nothing doing + case LayoutInfo::VSplitter: + case LayoutInfo::UnknownLayout: + break; + } + return false; +} + +void MorphLayoutCommand::redo() +{ + m_breakLayoutCommand->redo(); + m_layoutCommand->redo(); + /* Transfer applicable properties which is a cross-section of the modified + * properties except object name. */ + if (const LayoutProperties *properties = m_breakLayoutCommand->layoutProperties()) { + const int oldMask = m_breakLayoutCommand->propertyMask(); + QLayout *newLayout = LayoutInfo::managedLayout(core(), m_layoutBase); + const int newMask = LayoutProperties::visibleProperties(newLayout); + const int applicableMask = (oldMask & newMask) & ~LayoutProperties::ObjectNameProperty; + if (applicableMask) + properties->toPropertySheet(core(), newLayout, applicableMask); + } +} + +void MorphLayoutCommand::undo() +{ + m_layoutCommand->undo(); + m_breakLayoutCommand->undo(); +} + +QString MorphLayoutCommand::formatDescription(QDesignerFormEditorInterface * /* core*/, const QWidget *w, int oldType, int newType) +{ + const QString oldName = LayoutInfo::layoutName(static_cast(oldType)); + const QString newName = LayoutInfo::layoutName(static_cast(newType)); + const QString widgetName = qobject_cast(w) ? w->layout()->objectName() : w->objectName(); + return QApplication::translate("Command", "Change layout of '%1' from %2 to %3").arg(widgetName, oldName, newName); +} + +LayoutAlignmentCommand::LayoutAlignmentCommand(QDesignerFormWindowInterface *formWindow) : + QDesignerFormWindowCommand(QApplication::translate("Command", "Change layout alignment"), formWindow), + m_newAlignment(0), m_oldAlignment(0), m_widget(0) +{ +} + +bool LayoutAlignmentCommand::init(QWidget *w, Qt::Alignment alignment) +{ + bool enabled; + m_newAlignment = alignment; + m_oldAlignment = LayoutAlignmentCommand::alignmentOf(core(), w, &enabled); + m_widget = w; + return enabled; +} + +void LayoutAlignmentCommand::redo() +{ + LayoutAlignmentCommand::applyAlignment(core(), m_widget, m_newAlignment); +} + +void LayoutAlignmentCommand::undo() +{ + LayoutAlignmentCommand::applyAlignment(core(), m_widget, m_oldAlignment); +} + +// Find out alignment and return whether command is enabled. +Qt::Alignment LayoutAlignmentCommand::alignmentOf(const QDesignerFormEditorInterface *core, QWidget *w, bool *enabledIn) +{ + bool managed; + QLayout *layout; + + if (enabledIn) + *enabledIn = false; + // Can only work on a managed layout + const LayoutInfo::Type type = LayoutInfo::laidoutWidgetType(core, w, &managed, &layout); + const bool enabled = layout && managed && + (type == LayoutInfo::HBox || type == LayoutInfo::VBox + || type == LayoutInfo::Grid); + if (!enabled) + return Qt::Alignment(0); + // Get alignment + const int index = layout->indexOf(w); + Q_ASSERT(index >= 0); + if (enabledIn) + *enabledIn = true; + return layout->itemAt(index)->alignment(); +} + +void LayoutAlignmentCommand::applyAlignment(const QDesignerFormEditorInterface *core, QWidget *w, Qt::Alignment a) +{ + // Find layout and apply to item + QLayout *layout; + LayoutInfo::laidoutWidgetType(core, w, 0, &layout); + if (layout) { + const int index = layout->indexOf(w); + if (index >= 0) { + layout->itemAt(index)->setAlignment(a); + layout->update(); + } + } +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_command2_p.h b/src/designer/src/lib/shared/qdesigner_command2_p.h new file mode 100644 index 000000000..0a6cce88e --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_command2_p.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_COMMAND2_H +#define QDESIGNER_COMMAND2_H + +#include "shared_global_p.h" +#include "qdesigner_formwindowcommand_p.h" + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class LayoutCommand; +class BreakLayoutCommand; + +/* This command changes the type of a managed layout on a widget (including + * red layouts of type 'QLayoutWidget') into another type, maintaining the + * applicable properties. It does this by chaining BreakLayoutCommand and + * LayoutCommand, parametrizing them not to actually delete/reparent + * QLayoutWidget's. */ + +class QDESIGNER_SHARED_EXPORT MorphLayoutCommand : public QDesignerFormWindowCommand { + Q_DISABLE_COPY(MorphLayoutCommand) +public: + explicit MorphLayoutCommand(QDesignerFormWindowInterface *formWindow); + virtual ~MorphLayoutCommand(); + + bool init(QWidget *w, int newType); + + static bool canMorph(const QDesignerFormWindowInterface *formWindow, QWidget *w, int *ptrToCurrentType = 0); + + virtual void redo(); + virtual void undo(); + +private: + static QString formatDescription(QDesignerFormEditorInterface *core, const QWidget *w, int oldType, int newType); + + BreakLayoutCommand *m_breakLayoutCommand; + LayoutCommand *m_layoutCommand; + int m_newType; + QWidgetList m_widgets; + QWidget *m_layoutBase; +}; + +// Change the alignment of a widget in a managed grid/box layout cell. +class LayoutAlignmentCommand : public QDesignerFormWindowCommand { + Q_DISABLE_COPY(LayoutAlignmentCommand) +public: + explicit LayoutAlignmentCommand(QDesignerFormWindowInterface *formWindow); + + bool init(QWidget *w, Qt::Alignment alignment); + + virtual void redo(); + virtual void undo(); + + // Find out alignment and return whether command is enabled. + static Qt::Alignment alignmentOf(const QDesignerFormEditorInterface *core, QWidget *w, bool *enabled = 0); + +private: + static void applyAlignment(const QDesignerFormEditorInterface *core, QWidget *w, Qt::Alignment a); + + Qt::Alignment m_newAlignment; + Qt::Alignment m_oldAlignment; + QWidget *m_widget; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QDESIGNER_COMMAND2_H diff --git a/src/designer/src/lib/shared/qdesigner_command_p.h b/src/designer/src/lib/shared/qdesigner_command_p.h new file mode 100644 index 000000000..323cec5e5 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_command_p.h @@ -0,0 +1,1136 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_COMMAND_H +#define QDESIGNER_COMMAND_H + +#include "shared_global_p.h" +#include "shared_enums_p.h" +#include "layoutinfo_p.h" +#include "qdesigner_utils_p.h" +#include "qdesigner_formwindowcommand_p.h" +#include "qdesigner_formeditorcommand_p.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerContainerExtension; +class QDesignerMetaDataBaseItemInterface; +class QDesignerMenu; + +class QMenuBar; +class QStatusBar; +class QToolBar; +class QToolBox; +class QTabWidget; +class QTableWidget; +class QTableWidgetItem; +class QTreeWidget; +class QTreeWidgetItem; +class QListWidget; +class QListWidgetItem; +class QComboBox; +class QStackedWidget; +class QDockWidget; +class QMainWindow; +class QFormLayout; + +namespace qdesigner_internal { + +class Layout; +class LayoutHelper; +class PropertySheetIconValue; +class DesignerIconCache; +struct LayoutProperties; + +class QDESIGNER_SHARED_EXPORT InsertWidgetCommand: public QDesignerFormWindowCommand +{ + +public: + explicit InsertWidgetCommand(QDesignerFormWindowInterface *formWindow); + ~InsertWidgetCommand(); + + void init(QWidget *widget, bool already_in_form = false, int layoutRow = -1, int layoutColumn = -1); + + virtual void redo(); + virtual void undo(); + +private: + void refreshBuddyLabels(); + + QPointer m_widget; + QDesignerLayoutDecorationExtension::InsertMode m_insertMode; + QPair m_cell; + LayoutHelper* m_layoutHelper; + bool m_widgetWasManaged; +}; + +class QDESIGNER_SHARED_EXPORT ChangeZOrderCommand: public QDesignerFormWindowCommand +{ + +public: + explicit ChangeZOrderCommand(QDesignerFormWindowInterface *formWindow); + + void init(QWidget *widget); + + virtual void redo(); + virtual void undo(); +protected: + virtual QWidgetList reorderWidget(const QWidgetList &list, QWidget *widget) const = 0; + virtual void reorder(QWidget *widget) const = 0; + +private: + QPointer m_widget; + QPointer m_oldPreceding; + QList m_oldParentZOrder; +}; + +class QDESIGNER_SHARED_EXPORT RaiseWidgetCommand: public ChangeZOrderCommand +{ + +public: + explicit RaiseWidgetCommand(QDesignerFormWindowInterface *formWindow); + + void init(QWidget *widget); + +protected: + virtual QWidgetList reorderWidget(const QWidgetList &list, QWidget *widget) const; + virtual void reorder(QWidget *widget) const; +}; + +class QDESIGNER_SHARED_EXPORT LowerWidgetCommand: public ChangeZOrderCommand +{ + +public: + explicit LowerWidgetCommand(QDesignerFormWindowInterface *formWindow); + + void init(QWidget *widget); + +protected: + virtual QWidgetList reorderWidget(const QWidgetList &list, QWidget *widget) const; + virtual void reorder(QWidget *widget) const; +}; + +class QDESIGNER_SHARED_EXPORT AdjustWidgetSizeCommand: public QDesignerFormWindowCommand +{ + +public: + explicit AdjustWidgetSizeCommand(QDesignerFormWindowInterface *formWindow); + + void init(QWidget *widget); + + virtual void redo(); + virtual void undo(); + +private: + QWidget *widgetForAdjust() const; + bool adjustNonLaidOutMainContainer(QWidget *integrationContainer); + void updatePropertyEditor() const; + + QPointer m_widget; + QRect m_geometry; +}; + +// Helper to correctly unmanage a widget and its children for delete operations +class QDESIGNER_SHARED_EXPORT ManageWidgetCommandHelper { +public: + typedef QVector WidgetVector; + + ManageWidgetCommandHelper(); + void init(const QDesignerFormWindowInterface *fw, QWidget *widget); + void init(QWidget *widget, const WidgetVector &managedChildren); + + void manage(QDesignerFormWindowInterface *fw); + void unmanage(QDesignerFormWindowInterface *fw); + + const WidgetVector &managedChildren() const { return m_managedChildren; } +private: + QWidget *m_widget; + WidgetVector m_managedChildren; +}; + +class QDESIGNER_SHARED_EXPORT DeleteWidgetCommand: public QDesignerFormWindowCommand +{ + +public: + explicit DeleteWidgetCommand(QDesignerFormWindowInterface *formWindow); + ~DeleteWidgetCommand(); + + enum DeleteFlags { DoNotUnmanage = 0x1, DoNotSimplifyLayout = 0x2 }; + + void init(QWidget *widget, unsigned flags = 0); + + virtual void redo(); + virtual void undo(); + +private: + QPointer m_widget; + QPointer m_parentWidget; + QRect m_geometry; + LayoutInfo::Type m_layoutType; + LayoutHelper* m_layoutHelper; + unsigned m_flags; + QRect m_layoutPosition; + int m_splitterIndex; + bool m_layoutSimplified; + QDesignerMetaDataBaseItemInterface *m_formItem; + int m_tabOrderIndex; + int m_widgetOrderIndex; + int m_zOrderIndex; + ManageWidgetCommandHelper m_manageHelper; +}; + +class QDESIGNER_SHARED_EXPORT ReparentWidgetCommand: public QDesignerFormWindowCommand +{ + +public: + explicit ReparentWidgetCommand(QDesignerFormWindowInterface *formWindow); + + void init(QWidget *widget, QWidget *parentWidget); + + virtual void redo(); + virtual void undo(); + +private: + QPointer m_widget; + QPoint m_oldPos; + QPoint m_newPos; + QPointer m_oldParentWidget; + QPointer m_newParentWidget; + QList m_oldParentList; + QList m_oldParentZOrder; +}; + +class QDESIGNER_SHARED_EXPORT ChangeFormLayoutItemRoleCommand : public QDesignerFormWindowCommand +{ +public: + enum Operation { SpanningToLabel = 0x1, SpanningToField = 0x2, LabelToSpanning = 0x4, FieldToSpanning =0x8 }; + + explicit ChangeFormLayoutItemRoleCommand(QDesignerFormWindowInterface *formWindow); + + void init(QWidget *widget, Operation op); + + virtual void redo(); + virtual void undo(); + + // Return a mask of possible operations of that item + static unsigned possibleOperations(QDesignerFormEditorInterface *core, QWidget *w); + +private: + static QFormLayout *managedFormLayoutOf(QDesignerFormEditorInterface *core, QWidget *w); + static Operation reverseOperation(Operation op); + void doOperation(Operation op); + + QPointer m_widget; + Operation m_operation; +}; + +class QDESIGNER_SHARED_EXPORT ChangeLayoutItemGeometry: public QDesignerFormWindowCommand +{ + +public: + explicit ChangeLayoutItemGeometry(QDesignerFormWindowInterface *formWindow); + + void init(QWidget *widget, int row, int column, int rowspan, int colspan); + + virtual void redo(); + virtual void undo(); + +protected: + void changeItemPosition(const QRect &g); + +private: + QPointer m_widget; + QRect m_oldInfo; + QRect m_newInfo; +}; + +class QDESIGNER_SHARED_EXPORT TabOrderCommand: public QDesignerFormWindowCommand +{ + +public: + explicit TabOrderCommand(QDesignerFormWindowInterface *formWindow); + + void init(const QList &newTabOrder); + + inline QList oldTabOrder() const + { return m_oldTabOrder; } + + inline QList newTabOrder() const + { return m_newTabOrder; } + + virtual void redo(); + virtual void undo(); + +private: + QDesignerMetaDataBaseItemInterface *m_widgetItem; + QList m_oldTabOrder; + QList m_newTabOrder; +}; + +class QDESIGNER_SHARED_EXPORT PromoteToCustomWidgetCommand : public QDesignerFormWindowCommand +{ +public: + typedef QList > WidgetList; + + explicit PromoteToCustomWidgetCommand(QDesignerFormWindowInterface *formWindow); + + void init(const WidgetList &widgets, const QString &customClassName); + virtual void redo(); + virtual void undo(); + +private: + void updateSelection(); + WidgetList m_widgets; + QString m_customClassName; +}; + +class QDESIGNER_SHARED_EXPORT DemoteFromCustomWidgetCommand : public QDesignerFormWindowCommand +{ +public: + typedef PromoteToCustomWidgetCommand::WidgetList WidgetList; + + explicit DemoteFromCustomWidgetCommand(QDesignerFormWindowInterface *formWindow); + + void init(const WidgetList &promoted); + virtual void redo(); + virtual void undo(); +private: + PromoteToCustomWidgetCommand m_promote_cmd; +}; + +// Mixin class for storing the selection state +class QDESIGNER_SHARED_EXPORT CursorSelectionState { + Q_DISABLE_COPY(CursorSelectionState) +public: + CursorSelectionState(); + + void save(const QDesignerFormWindowInterface *formWindow); + void restore(QDesignerFormWindowInterface *formWindow) const; + +private: + typedef QList > WidgetPointerList; + WidgetPointerList m_selection; + QPointer m_current; +}; + +class QDESIGNER_SHARED_EXPORT LayoutCommand: public QDesignerFormWindowCommand +{ + +public: + explicit LayoutCommand(QDesignerFormWindowInterface *formWindow); + virtual ~LayoutCommand(); + + inline QWidgetList widgets() const { return m_widgets; } + + void init(QWidget *parentWidget, const QWidgetList &widgets, LayoutInfo::Type layoutType, + QWidget *layoutBase = 0, + // Reparent/Hide instances of QLayoutWidget. + bool reparentLayoutWidget = true); + + virtual void redo(); + virtual void undo(); + +private: + QPointer m_parentWidget; + QWidgetList m_widgets; + QPointer m_layoutBase; + QPointer m_layout; + CursorSelectionState m_cursorSelectionState; + bool m_setup; +}; + +class QDESIGNER_SHARED_EXPORT BreakLayoutCommand: public QDesignerFormWindowCommand +{ + +public: + explicit BreakLayoutCommand(QDesignerFormWindowInterface *formWindow); + virtual ~BreakLayoutCommand(); + + inline QWidgetList widgets() const { return m_widgets; } + + void init(const QWidgetList &widgets, QWidget *layoutBase, + // Reparent/Hide instances of QLayoutWidget. + bool reparentLayoutWidget = true); + + virtual void redo(); + virtual void undo(); + + // Access the properties of the layout, 0 in case of splitters. + const LayoutProperties *layoutProperties() const; + int propertyMask() const; + +private: + QWidgetList m_widgets; + QPointer m_layoutBase; + QPointer m_layout; + LayoutHelper* m_layoutHelper; + LayoutProperties *m_properties; + int m_propertyMask; + CursorSelectionState m_cursorSelectionState; +}; + +class QDESIGNER_SHARED_EXPORT SimplifyLayoutCommand: public QDesignerFormWindowCommand +{ +public: + explicit SimplifyLayoutCommand(QDesignerFormWindowInterface *formWindow); + virtual ~SimplifyLayoutCommand(); + + bool init(QWidget *layoutBase); + + // Quick check + static bool canSimplify(QDesignerFormEditorInterface *core, const QWidget *w, int *layoutType = 0); + + virtual void redo(); + virtual void undo(); + +private: + const QRect m_area; + QWidget *m_layoutBase; + LayoutHelper* m_layoutHelper; + bool m_layoutSimplified; +}; + +class QDESIGNER_SHARED_EXPORT ToolBoxCommand: public QDesignerFormWindowCommand +{ + +public: + explicit ToolBoxCommand(QDesignerFormWindowInterface *formWindow); + virtual ~ToolBoxCommand(); + + void init(QToolBox *toolBox); + + virtual void removePage(); + virtual void addPage(); + +protected: + QPointer m_toolBox; + QPointer m_widget; + int m_index; + QString m_itemText; + QIcon m_itemIcon; +}; + +class QDESIGNER_SHARED_EXPORT MoveToolBoxPageCommand: public ToolBoxCommand +{ + +public: + explicit MoveToolBoxPageCommand(QDesignerFormWindowInterface *formWindow); + virtual ~MoveToolBoxPageCommand(); + + void init(QToolBox *toolBox, QWidget *page, int newIndex); + + virtual void redo(); + virtual void undo(); + +private: + int m_newIndex; + int m_oldIndex; +}; + +class QDESIGNER_SHARED_EXPORT DeleteToolBoxPageCommand: public ToolBoxCommand +{ + +public: + explicit DeleteToolBoxPageCommand(QDesignerFormWindowInterface *formWindow); + virtual ~DeleteToolBoxPageCommand(); + + void init(QToolBox *toolBox); + + virtual void redo(); + virtual void undo(); +}; + +class QDESIGNER_SHARED_EXPORT AddToolBoxPageCommand: public ToolBoxCommand +{ + +public: + enum InsertionMode { + InsertBefore, + InsertAfter + }; + explicit AddToolBoxPageCommand(QDesignerFormWindowInterface *formWindow); + virtual ~AddToolBoxPageCommand(); + + void init(QToolBox *toolBox); + void init(QToolBox *toolBox, InsertionMode mode); + + virtual void redo(); + virtual void undo(); +}; + +class QDESIGNER_SHARED_EXPORT TabWidgetCommand: public QDesignerFormWindowCommand +{ + +public: + explicit TabWidgetCommand(QDesignerFormWindowInterface *formWindow); + virtual ~TabWidgetCommand(); + + void init(QTabWidget *tabWidget); + + virtual void removePage(); + virtual void addPage(); + +protected: + QPointer m_tabWidget; + QPointer m_widget; + int m_index; + QString m_itemText; + QIcon m_itemIcon; +}; + +class QDESIGNER_SHARED_EXPORT DeleteTabPageCommand: public TabWidgetCommand +{ + +public: + explicit DeleteTabPageCommand(QDesignerFormWindowInterface *formWindow); + virtual ~DeleteTabPageCommand(); + + void init(QTabWidget *tabWidget); + + virtual void redo(); + virtual void undo(); +}; + +class QDESIGNER_SHARED_EXPORT AddTabPageCommand: public TabWidgetCommand +{ + +public: + enum InsertionMode { + InsertBefore, + InsertAfter + }; + explicit AddTabPageCommand(QDesignerFormWindowInterface *formWindow); + virtual ~AddTabPageCommand(); + + void init(QTabWidget *tabWidget); + void init(QTabWidget *tabWidget, InsertionMode mode); + + virtual void redo(); + virtual void undo(); +}; + +class QDESIGNER_SHARED_EXPORT MoveTabPageCommand: public TabWidgetCommand +{ + +public: + explicit MoveTabPageCommand(QDesignerFormWindowInterface *formWindow); + virtual ~MoveTabPageCommand(); + + void init(QTabWidget *tabWidget, QWidget *page, + const QIcon &icon, const QString &label, + int index, int newIndex); + + virtual void redo(); + virtual void undo(); + +private: + int m_newIndex; + int m_oldIndex; + QPointer m_page; + QString m_label; + QIcon m_icon; +}; + +class QDESIGNER_SHARED_EXPORT StackedWidgetCommand: public QDesignerFormWindowCommand +{ + +public: + explicit StackedWidgetCommand(QDesignerFormWindowInterface *formWindow); + virtual ~StackedWidgetCommand(); + + void init(QStackedWidget *stackedWidget); + + virtual void removePage(); + virtual void addPage(); + +protected: + QPointer m_stackedWidget; + QPointer m_widget; + int m_index; +}; + +class QDESIGNER_SHARED_EXPORT MoveStackedWidgetCommand: public StackedWidgetCommand +{ + +public: + explicit MoveStackedWidgetCommand(QDesignerFormWindowInterface *formWindow); + virtual ~MoveStackedWidgetCommand(); + + void init(QStackedWidget *stackedWidget, QWidget *page, int newIndex); + + virtual void redo(); + virtual void undo(); + +private: + int m_newIndex; + int m_oldIndex; +}; + +class QDESIGNER_SHARED_EXPORT DeleteStackedWidgetPageCommand: public StackedWidgetCommand +{ + +public: + explicit DeleteStackedWidgetPageCommand(QDesignerFormWindowInterface *formWindow); + virtual ~DeleteStackedWidgetPageCommand(); + + void init(QStackedWidget *stackedWidget); + + virtual void redo(); + virtual void undo(); +}; + +class QDESIGNER_SHARED_EXPORT AddStackedWidgetPageCommand: public StackedWidgetCommand +{ + +public: + enum InsertionMode { + InsertBefore, + InsertAfter + }; + explicit AddStackedWidgetPageCommand(QDesignerFormWindowInterface *formWindow); + virtual ~AddStackedWidgetPageCommand(); + + void init(QStackedWidget *stackedWidget); + void init(QStackedWidget *stackedWidget, InsertionMode mode); + + virtual void redo(); + virtual void undo(); +}; + +class QDESIGNER_SHARED_EXPORT CreateMenuBarCommand: public QDesignerFormWindowCommand +{ + +public: + explicit CreateMenuBarCommand(QDesignerFormWindowInterface *formWindow); + + void init(QMainWindow *mainWindow); + + virtual void undo(); + virtual void redo(); + +private: + QPointer m_mainWindow; + QPointer m_menuBar; +}; + +class QDESIGNER_SHARED_EXPORT DeleteMenuBarCommand: public QDesignerFormWindowCommand +{ + +public: + explicit DeleteMenuBarCommand(QDesignerFormWindowInterface *formWindow); + + void init(QMenuBar *menuBar); + + virtual void undo(); + virtual void redo(); + +private: + QPointer m_mainWindow; + QPointer m_menuBar; +}; + +class QDESIGNER_SHARED_EXPORT CreateStatusBarCommand: public QDesignerFormWindowCommand +{ + +public: + explicit CreateStatusBarCommand(QDesignerFormWindowInterface *formWindow); + + void init(QMainWindow *mainWindow); + + virtual void undo(); + virtual void redo(); + +private: + QPointer m_mainWindow; + QPointer m_statusBar; +}; + +class QDESIGNER_SHARED_EXPORT DeleteStatusBarCommand: public QDesignerFormWindowCommand +{ + +public: + explicit DeleteStatusBarCommand(QDesignerFormWindowInterface *formWindow); + + void init(QStatusBar *statusBar); + + virtual void undo(); + virtual void redo(); + +private: + QPointer m_mainWindow; + QPointer m_statusBar; +}; + +class QDESIGNER_SHARED_EXPORT AddToolBarCommand: public QDesignerFormWindowCommand +{ + +public: + explicit AddToolBarCommand(QDesignerFormWindowInterface *formWindow); + + void init(QMainWindow *mainWindow); + + virtual void undo(); + virtual void redo(); + +private: + QPointer m_mainWindow; + QPointer m_toolBar; +}; + +class QDESIGNER_SHARED_EXPORT DeleteToolBarCommand: public QDesignerFormWindowCommand +{ + +public: + explicit DeleteToolBarCommand(QDesignerFormWindowInterface *formWindow); + + void init(QToolBar *toolBar); + + virtual void undo(); + virtual void redo(); + +private: + QPointer m_mainWindow; + QPointer m_toolBar; +}; + +class QDESIGNER_SHARED_EXPORT DockWidgetCommand: public QDesignerFormWindowCommand +{ + +public: + explicit DockWidgetCommand(const QString &description, QDesignerFormWindowInterface *formWindow); + virtual ~DockWidgetCommand(); + + void init(QDockWidget *dockWidget); + +protected: + QPointer m_dockWidget; +}; + +class QDESIGNER_SHARED_EXPORT AddDockWidgetCommand: public QDesignerFormWindowCommand +{ + +public: + explicit AddDockWidgetCommand(QDesignerFormWindowInterface *formWindow); + + void init(QMainWindow *mainWindow, QDockWidget *dockWidget); + void init(QMainWindow *mainWindow); + + virtual void undo(); + virtual void redo(); + +private: + QPointer m_mainWindow; + QPointer m_dockWidget; +}; + +class QDESIGNER_SHARED_EXPORT ContainerWidgetCommand: public QDesignerFormWindowCommand +{ + +public: + explicit ContainerWidgetCommand(QDesignerFormWindowInterface *formWindow); + virtual ~ContainerWidgetCommand(); + + QDesignerContainerExtension *containerExtension() const; + + void init(QWidget *containerWidget); + + virtual void removePage(); + virtual void addPage(); + +protected: + QPointer m_containerWidget; + QPointer m_widget; + int m_index; +}; + +class QDESIGNER_SHARED_EXPORT DeleteContainerWidgetPageCommand: public ContainerWidgetCommand +{ + +public: + explicit DeleteContainerWidgetPageCommand(QDesignerFormWindowInterface *formWindow); + virtual ~DeleteContainerWidgetPageCommand(); + + void init(QWidget *containerWidget, ContainerType ct); + + virtual void redo(); + virtual void undo(); +}; + +class QDESIGNER_SHARED_EXPORT AddContainerWidgetPageCommand: public ContainerWidgetCommand +{ + +public: + enum InsertionMode { + InsertBefore, + InsertAfter + }; + explicit AddContainerWidgetPageCommand(QDesignerFormWindowInterface *formWindow); + virtual ~AddContainerWidgetPageCommand(); + + void init(QWidget *containerWidget, ContainerType ct, InsertionMode mode); + + virtual void redo(); + virtual void undo(); +}; + +class QDESIGNER_SHARED_EXPORT ChangeCurrentPageCommand: public QDesignerFormWindowCommand +{ + +public: + explicit ChangeCurrentPageCommand(QDesignerFormWindowInterface *formWindow); + virtual ~ChangeCurrentPageCommand(); + + QDesignerContainerExtension *containerExtension() const; + + void init(QWidget *containerWidget, int newIndex); + + virtual void redo(); + virtual void undo(); + +protected: + QPointer m_containerWidget; + QPointer m_widget; + int m_oldIndex; + int m_newIndex; +}; + +struct QDESIGNER_SHARED_EXPORT ItemData { + ItemData() {} + + ItemData(const QListWidgetItem *item, bool editor); + ItemData(const QTableWidgetItem *item, bool editor); + ItemData(const QTreeWidgetItem *item, int column); + QListWidgetItem *createListItem(DesignerIconCache *iconCache, bool editor) const; + QTableWidgetItem *createTableItem(DesignerIconCache *iconCache, bool editor) const; + void fillTreeItemColumn(QTreeWidgetItem *item, int column, DesignerIconCache *iconCache) const; + + bool isValid() const { return !m_properties.isEmpty(); } + bool operator==(const ItemData &rhs) const { return m_properties == rhs.m_properties; } + bool operator!=(const ItemData &rhs) const { return m_properties != rhs.m_properties; } + + QHash m_properties; +}; + +struct QDESIGNER_SHARED_EXPORT ListContents { + ListContents() {} + + ListContents(const QTreeWidgetItem *item); + QTreeWidgetItem *createTreeItem(DesignerIconCache *iconCache) const; + + void createFromListWidget(const QListWidget *listWidget, bool editor); + void applyToListWidget(QListWidget *listWidget, DesignerIconCache *iconCache, bool editor) const; + void createFromComboBox(const QComboBox *listWidget); + void applyToComboBox(QComboBox *listWidget, DesignerIconCache *iconCache) const; + + bool operator==(const ListContents &rhs) const { return m_items == rhs.m_items; } + bool operator!=(const ListContents &rhs) const { return m_items != rhs.m_items; } + + QList m_items; +}; + +// Data structure representing the contents of a QTableWidget with +// methods to retrieve and apply for ChangeTableContentsCommand +struct QDESIGNER_SHARED_EXPORT TableWidgetContents { + + typedef QPair CellRowColumnAddress; + typedef QMap TableItemMap; + + TableWidgetContents(); + void clear(); + + void fromTableWidget(const QTableWidget *tableWidget, bool editor); + void applyToTableWidget(QTableWidget *tableWidget, DesignerIconCache *iconCache, bool editor) const; + + bool operator==(const TableWidgetContents &rhs) const; + bool operator!=(const TableWidgetContents &rhs) const { return !(*this == rhs); } + + static bool nonEmpty(const QTableWidgetItem *item, int headerColumn); + static QString defaultHeaderText(int i); + static void insertHeaderItem(const QTableWidgetItem *item, int i, ListContents *header, bool editor); + + int m_columnCount; + int m_rowCount; + ListContents m_horizontalHeader; + ListContents m_verticalHeader; + TableItemMap m_items; +}; + +class QDESIGNER_SHARED_EXPORT ChangeTableContentsCommand: public QDesignerFormWindowCommand +{ +public: + explicit ChangeTableContentsCommand(QDesignerFormWindowInterface *formWindow); + + void init(QTableWidget *tableWidget, const TableWidgetContents &oldCont, const TableWidgetContents &newCont); + virtual void redo(); + virtual void undo(); + +private: + QPointer m_tableWidget; + TableWidgetContents m_oldContents; + TableWidgetContents m_newContents; + DesignerIconCache *m_iconCache; +}; + +// Data structure representing the contents of a QTreeWidget with +// methods to retrieve and apply for ChangeTreeContentsCommand +struct QDESIGNER_SHARED_EXPORT TreeWidgetContents { + + struct ItemContents : public ListContents { + ItemContents() : m_itemFlags(-1) {} + ItemContents(const QTreeWidgetItem *item, bool editor); + QTreeWidgetItem *createTreeItem(DesignerIconCache *iconCache, bool editor) const; + + bool operator==(const ItemContents &rhs) const; + bool operator!=(const ItemContents &rhs) const { return !(*this == rhs); } + + int m_itemFlags; + //bool m_firstColumnSpanned:1; + //bool m_hidden:1; + //bool m_expanded:1; + QList m_children; + }; + + void clear(); + + void fromTreeWidget(const QTreeWidget *treeWidget, bool editor); + void applyToTreeWidget(QTreeWidget *treeWidget, DesignerIconCache *iconCache, bool editor) const; + + bool operator==(const TreeWidgetContents &rhs) const; + bool operator!=(const TreeWidgetContents &rhs) const { return !(*this == rhs); } + + ListContents m_headerItem; + QList m_rootItems; +}; + +class QDESIGNER_SHARED_EXPORT ChangeTreeContentsCommand: public QDesignerFormWindowCommand +{ + +public: + explicit ChangeTreeContentsCommand(QDesignerFormWindowInterface *formWindow); + + void init(QTreeWidget *treeWidget, const TreeWidgetContents &oldState, const TreeWidgetContents &newState); + virtual void redo(); + virtual void undo(); + enum ApplyIconStrategy { + SetIconStrategy, + ResetIconStrategy + }; +private: + QPointer m_treeWidget; + TreeWidgetContents m_oldState; + TreeWidgetContents m_newState; + DesignerIconCache *m_iconCache; +}; + +class QDESIGNER_SHARED_EXPORT ChangeListContentsCommand: public QDesignerFormWindowCommand +{ + +public: + explicit ChangeListContentsCommand(QDesignerFormWindowInterface *formWindow); + + void init(QListWidget *listWidget, const ListContents &oldItems, const ListContents &items); + void init(QComboBox *comboBox, const ListContents &oldItems, const ListContents &items); + virtual void redo(); + virtual void undo(); +private: + QPointer m_listWidget; + QPointer m_comboBox; + ListContents m_oldItemsState; + ListContents m_newItemsState; + DesignerIconCache *m_iconCache; +}; + +class QDESIGNER_SHARED_EXPORT AddActionCommand : public QDesignerFormWindowCommand +{ + +public: + explicit AddActionCommand(QDesignerFormWindowInterface *formWindow); + void init(QAction *action); + virtual void redo(); + virtual void undo(); +private: + QAction *m_action; +}; + +// Note: This command must be executed within a macro since it +// makes the form emit objectRemoved() which might cause other components +// to add commands (for example, removal of signals and slots +class QDESIGNER_SHARED_EXPORT RemoveActionCommand : public QDesignerFormWindowCommand +{ + +public: + explicit RemoveActionCommand(QDesignerFormWindowInterface *formWindow); + void init(QAction *action); + virtual void redo(); + virtual void undo(); + + struct ActionDataItem { + ActionDataItem(QAction *_before = 0, QWidget *_widget = 0) + : before(_before), widget(_widget) {} + QAction *before; + QWidget *widget; + }; + typedef QList ActionData; + +private: + QAction *m_action; + + ActionData m_actionData; +}; + +class QDESIGNER_SHARED_EXPORT ActionInsertionCommand : public QDesignerFormWindowCommand +{ + +protected: + ActionInsertionCommand(const QString &text, QDesignerFormWindowInterface *formWindow); + +public: + void init(QWidget *parentWidget, QAction *action, QAction *beforeAction = 0, bool update = true); + +protected: + void insertAction(); + void removeAction(); + +private: + QWidget *m_parentWidget; + QAction *m_action; + QAction *m_beforeAction; + bool m_update; +}; + +class QDESIGNER_SHARED_EXPORT InsertActionIntoCommand : public ActionInsertionCommand +{ + +public: + explicit InsertActionIntoCommand(QDesignerFormWindowInterface *formWindow); + + virtual void redo() { insertAction(); } + virtual void undo() { removeAction(); } +}; + +class QDESIGNER_SHARED_EXPORT RemoveActionFromCommand : public ActionInsertionCommand +{ + +public: + explicit RemoveActionFromCommand(QDesignerFormWindowInterface *formWindow); + + virtual void redo() { removeAction(); } + virtual void undo() { insertAction(); } +}; + +class QDESIGNER_SHARED_EXPORT MenuActionCommand : public QDesignerFormWindowCommand +{ +public: + void init(QAction *action, QAction *actionBefore, QWidget *associatedWidget, QWidget *objectToSelect); + +protected: + MenuActionCommand(const QString &text, QDesignerFormWindowInterface *formWindow); + void insertMenu(); + void removeMenu(); + +private: + QAction *m_action; + QAction *m_actionBefore; + QWidget *m_menuParent; + QWidget *m_associatedWidget; + QWidget *m_objectToSelect; +}; + +class QDESIGNER_SHARED_EXPORT AddMenuActionCommand : public MenuActionCommand +{ + +public: + explicit AddMenuActionCommand(QDesignerFormWindowInterface *formWindow); + + virtual void redo() { insertMenu(); } + virtual void undo() { removeMenu(); } +}; + +class QDESIGNER_SHARED_EXPORT RemoveMenuActionCommand : public MenuActionCommand +{ + +public: + explicit RemoveMenuActionCommand(QDesignerFormWindowInterface *formWindow); + + virtual void redo() { removeMenu(); } + virtual void undo() { insertMenu(); } +}; + +class QDESIGNER_SHARED_EXPORT CreateSubmenuCommand : public QDesignerFormWindowCommand +{ + +public: + explicit CreateSubmenuCommand(QDesignerFormWindowInterface *formWindow); + void init(QDesignerMenu *menu, QAction *action, QObject *m_objectToSelect = 0); + virtual void redo(); + virtual void undo(); +private: + QAction *m_action; + QDesignerMenu *m_menu; + QObject *m_objectToSelect; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QDESIGNER_COMMAND_H diff --git a/src/designer/src/lib/shared/qdesigner_dnditem.cpp b/src/designer/src/lib/shared/qdesigner_dnditem.cpp new file mode 100644 index 000000000..83218026a --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_dnditem.cpp @@ -0,0 +1,300 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_dnditem_p.h" +#include "formwindowbase_p.h" +#include "ui4_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +QDesignerDnDItem::QDesignerDnDItem(DropType type, QWidget *source) : + m_source(source), + m_type(type), + m_dom_ui(0), + m_widget(0), + m_decoration(0) +{ +} + +void QDesignerDnDItem::init(DomUI *ui, QWidget *widget, QWidget *decoration, + const QPoint &global_mouse_pos) +{ + Q_ASSERT(widget != 0 || ui != 0); + Q_ASSERT(decoration != 0); + + m_dom_ui = ui; + m_widget = widget; + m_decoration = decoration; + + const QRect geometry = m_decoration->geometry(); + m_hot_spot = global_mouse_pos - m_decoration->geometry().topLeft(); +} + +QDesignerDnDItem::~QDesignerDnDItem() +{ + if (m_decoration != 0) + m_decoration->deleteLater(); + delete m_dom_ui; +} + +DomUI *QDesignerDnDItem::domUi() const +{ + return m_dom_ui; +} + +QWidget *QDesignerDnDItem::decoration() const +{ + return m_decoration; +} + +QPoint QDesignerDnDItem::hotSpot() const +{ + return m_hot_spot; +} + +QWidget *QDesignerDnDItem::widget() const +{ + return m_widget; +} + +QDesignerDnDItem::DropType QDesignerDnDItem::type() const +{ + return m_type; +} + +QWidget *QDesignerDnDItem::source() const +{ + return m_source; +} + +void QDesignerDnDItem::setDomUi(DomUI *dom_ui) +{ + delete m_dom_ui; + m_dom_ui = dom_ui; +} + +// ---------- QDesignerMimeData + +// Make pixmap transparent on Windows only. Mac is transparent by default, Unix usually does not work. +#ifdef Q_WS_WIN +# define TRANSPARENT_DRAG_PIXMAP +#endif + +QDesignerMimeData::QDesignerMimeData(const QDesignerDnDItems &items, QDrag *drag) : + m_items(items) +{ + enum { Alpha = 200 }; + QPoint decorationTopLeft; + switch (m_items.size()) { + case 0: + break; + case 1: { + QWidget *deco = m_items.first()->decoration(); + decorationTopLeft = deco->pos(); + const QPixmap widgetPixmap = QPixmap::grabWidget(deco); +#ifdef TRANSPARENT_DRAG_PIXMAP + QImage image(widgetPixmap.size(), QImage::Format_ARGB32); + image.fill(QColor(Qt::transparent).rgba()); + QPainter painter(&image); + painter.drawPixmap(QPoint(0, 0), widgetPixmap); + painter.end(); + setImageTransparency(image, Alpha); + drag->setPixmap(QPixmap::fromImage(image)); +#else + drag->setPixmap(widgetPixmap); +#endif + } + break; + default: { + // determine size of drag decoration by uniting all geometries + const QDesignerDnDItems::const_iterator cend = m_items.constEnd(); + QDesignerDnDItems::const_iterator it =m_items.constBegin(); + QRect unitedGeometry = (*it)->decoration()->geometry(); + for (++it; it != cend; ++it ) + unitedGeometry = unitedGeometry .united((*it)->decoration()->geometry()); + + // paint with offset. At the same time, create a mask bitmap, containing widget rectangles. + QImage image(unitedGeometry.size(), QImage::Format_ARGB32); + image.fill(QColor(Qt::transparent).rgba()); + QBitmap mask(unitedGeometry.size()); + mask.clear(); + // paint with offset, determine action + QPainter painter(&image); + QPainter maskPainter(&mask); + decorationTopLeft = unitedGeometry.topLeft(); + for (it = m_items.constBegin() ; it != cend; ++it ) { + QWidget *w = (*it)->decoration(); + const QPixmap wp = QPixmap::grabWidget(w); + const QPoint pos = w->pos() - decorationTopLeft; + painter.drawPixmap(pos, wp); + maskPainter.fillRect(QRect(pos, wp.size()), Qt::color1); + } + painter.end(); + maskPainter.end(); +#ifdef TRANSPARENT_DRAG_PIXMAP + setImageTransparency(image, Alpha); +#endif + QPixmap pixmap = QPixmap::fromImage(image); + pixmap.setMask(mask); + drag->setPixmap(pixmap); + } + break; + } + // determine hot spot and reconstruct the exact starting position as form window + // introduces some offset when detecting DnD + m_globalStartPos = m_items.first()->decoration()->pos() + m_items.first()->hotSpot(); + m_hotSpot = m_globalStartPos - decorationTopLeft; + drag->setHotSpot(m_hotSpot); + + drag->setMimeData(this); +} + +QDesignerMimeData::~QDesignerMimeData() +{ + const QDesignerDnDItems::const_iterator cend = m_items.constEnd(); + for (QDesignerDnDItems::const_iterator it = m_items.constBegin(); it != cend; ++it ) + delete *it; +} + +Qt::DropAction QDesignerMimeData::proposedDropAction() const +{ + return m_items.first()->type() == QDesignerDnDItemInterface::CopyDrop ? Qt::CopyAction : Qt::MoveAction; +} + +Qt::DropAction QDesignerMimeData::execDrag(const QDesignerDnDItems &items, QWidget * dragSource) +{ + if (items.empty()) + return Qt::IgnoreAction; + + QDrag *drag = new QDrag(dragSource); + QDesignerMimeData *mimeData = new QDesignerMimeData(items, drag); + + // Store pointers to widgets that are to be re-shown if a move operation is canceled + QWidgetList reshowWidgets; + const QDesignerDnDItems::const_iterator cend = items.constEnd(); + for (QDesignerDnDItems::const_iterator it = items.constBegin(); it != cend; ++it ) + if (QWidget *w = (*it)->widget()) + if ((*it)->type() == QDesignerDnDItemInterface::MoveDrop) + reshowWidgets.push_back(w); + + const Qt::DropAction executedAction = drag->exec(Qt::CopyAction|Qt::MoveAction, mimeData->proposedDropAction()); + + if (executedAction == Qt::IgnoreAction && !reshowWidgets.empty()) + foreach (QWidget *w, reshowWidgets) + w->show(); + + return executedAction; +} + + +void QDesignerMimeData::moveDecoration(const QPoint &globalPos) const +{ + const QPoint relativeDistance = globalPos - m_globalStartPos; + const QDesignerDnDItems::const_iterator cend = m_items.constEnd(); + for (QDesignerDnDItems::const_iterator it =m_items.constBegin(); it != cend; ++it ) { + QWidget *w = (*it)->decoration(); + w->move(w->pos() + relativeDistance); + } +} + +void QDesignerMimeData::removeMovedWidgetsFromSourceForm(const QDesignerDnDItems &items) +{ + typedef QMultiMap FormWidgetMap; + FormWidgetMap formWidgetMap; + // Find moved widgets per form + const QDesignerDnDItems::const_iterator cend = items.constEnd(); + for (QDesignerDnDItems::const_iterator it = items.constBegin(); it != cend; ++it ) + if ((*it)->type() == QDesignerDnDItemInterface::MoveDrop) + if (QWidget *w = (*it)->widget()) + if (FormWindowBase *fb = qobject_cast((*it)->source())) + formWidgetMap.insert(fb, w); + if (formWidgetMap.empty()) + return; + + foreach (FormWindowBase * fb, formWidgetMap.keys()) + fb->deleteWidgetList(formWidgetMap.values(fb)); +} + +void QDesignerMimeData::acceptEventWithAction(Qt::DropAction desiredAction, QDropEvent *e) +{ + if (e->proposedAction() == desiredAction) { + e->acceptProposedAction(); + } else { + e->setDropAction(desiredAction); + e->accept(); + } +} + +void QDesignerMimeData::acceptEvent(QDropEvent *e) const +{ + acceptEventWithAction(proposedDropAction(), e); +} + +void QDesignerMimeData::setImageTransparency(QImage &image, int alpha) +{ + const int height = image.height(); + for (int l = 0; l < height; l++) { + QRgb *line = reinterpret_cast(image.scanLine(l)); + QRgb *lineEnd = line + image.width(); + for ( ; line < lineEnd; line++) { + const QRgb rgba = *line; + *line = qRgba(qRed(rgba), qGreen(rgba), qBlue(rgba), alpha); + } + } +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_dnditem_p.h b/src/designer/src/lib/shared/qdesigner_dnditem_p.h new file mode 100644 index 000000000..8c9d2e672 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_dnditem_p.h @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_DNDITEM_H +#define QDESIGNER_DNDITEM_H + +#include "shared_global_p.h" +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDrag; +class QImage; +class QDropEvent; + +namespace qdesigner_internal { + +class QDESIGNER_SHARED_EXPORT QDesignerDnDItem: public QDesignerDnDItemInterface +{ +public: + explicit QDesignerDnDItem(DropType type, QWidget *source = 0); + virtual ~QDesignerDnDItem(); + + virtual DomUI *domUi() const; + virtual QWidget *decoration() const; + virtual QWidget *widget() const; + virtual QPoint hotSpot() const; + virtual QWidget *source() const; + + virtual DropType type() const; + +protected: + void setDomUi(DomUI *dom_ui); + void init(DomUI *ui, QWidget *widget, QWidget *decoration, const QPoint &global_mouse_pos); + +private: + QWidget *m_source; + const DropType m_type; + const QPoint m_globalStartPos; + DomUI *m_dom_ui; + QWidget *m_widget; + QWidget *m_decoration; + QPoint m_hot_spot; + + Q_DISABLE_COPY(QDesignerDnDItem) +}; + +// Mime data for use with designer drag and drop operations. + +class QDESIGNER_SHARED_EXPORT QDesignerMimeData : public QMimeData { + Q_OBJECT + +public: + typedef QList QDesignerDnDItems; + + virtual ~QDesignerMimeData(); + + const QDesignerDnDItems &items() const { return m_items; } + + // Execute a drag and drop operation. + static Qt::DropAction execDrag(const QDesignerDnDItems &items, QWidget * dragSource); + + QPoint hotSpot() const { return m_hotSpot; } + + // Move the decoration. Required for drops over form windows as the position + // is derived from the decoration position. + void moveDecoration(const QPoint &globalPos) const; + + // For a move operation, create the undo command sequence to remove + // the widgets from the source form. + static void removeMovedWidgetsFromSourceForm(const QDesignerDnDItems &items); + + // Accept an event with the proper action. + void acceptEvent(QDropEvent *e) const; + + // Helper to accept an event with the desired action. + static void acceptEventWithAction(Qt::DropAction desiredAction, QDropEvent *e); + +private: + QDesignerMimeData(const QDesignerDnDItems &items, QDrag *drag); + Qt::DropAction proposedDropAction() const; + + static void setImageTransparency(QImage &image, int alpha); + + const QDesignerDnDItems m_items; + QPoint m_globalStartPos; + QPoint m_hotSpot; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QDESIGNER_DNDITEM_H diff --git a/src/designer/src/lib/shared/qdesigner_dockwidget.cpp b/src/designer/src/lib/shared/qdesigner_dockwidget.cpp new file mode 100644 index 000000000..8aad4579c --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_dockwidget.cpp @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_dockwidget_p.h" +#include "layoutinfo_p.h" + +#include +#include +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +QDesignerDockWidget::QDesignerDockWidget(QWidget *parent) + : QDockWidget(parent) +{ +} + +QDesignerDockWidget::~QDesignerDockWidget() +{ +} + +bool QDesignerDockWidget::docked() const +{ + return qobject_cast(parentWidget()) != 0; +} + +void QDesignerDockWidget::setDocked(bool b) +{ + if (QMainWindow *mainWindow = findMainWindow()) { + QDesignerFormEditorInterface *core = formWindow()->core(); + QDesignerContainerExtension *c; + c = qt_extension(core->extensionManager(), mainWindow); + if (b && !docked()) { + // Dock it + // ### undo/redo stack + setParent(0); + c->addWidget(this); + formWindow()->selectWidget(this, formWindow()->cursor()->isWidgetSelected(this)); + } else if (!b && docked()) { + // Undock it + for (int i = 0; i < c->count(); ++i) { + if (c->widget(i) == this) { + c->remove(i); + break; + } + } + // #### restore the position + setParent(mainWindow->centralWidget()); + show(); + formWindow()->selectWidget(this, formWindow()->cursor()->isWidgetSelected(this)); + } + } +} + +Qt::DockWidgetArea QDesignerDockWidget::dockWidgetArea() const +{ + if (QMainWindow *mainWindow = qobject_cast(parentWidget())) + return mainWindow->dockWidgetArea(const_cast(this)); + + return Qt::LeftDockWidgetArea; +} + +void QDesignerDockWidget::setDockWidgetArea(Qt::DockWidgetArea dockWidgetArea) +{ + if (QMainWindow *mainWindow = qobject_cast(parentWidget())) { + if ((dockWidgetArea != Qt::NoDockWidgetArea) + && isAreaAllowed(dockWidgetArea)) { + mainWindow->addDockWidget(dockWidgetArea, this); + } + } +} + +bool QDesignerDockWidget::inMainWindow() const +{ + QMainWindow *mw = findMainWindow(); + if (mw && !mw->centralWidget()->layout()) { + if (mw == parentWidget()) + return true; + if (mw->centralWidget() == parentWidget()) + return true; + } + return false; +} + +QDesignerFormWindowInterface *QDesignerDockWidget::formWindow() const +{ + return QDesignerFormWindowInterface::findFormWindow(const_cast(this)); +} + +QMainWindow *QDesignerDockWidget::findMainWindow() const +{ + if (QDesignerFormWindowInterface *fw = formWindow()) + return qobject_cast(fw->mainContainer()); + return 0; +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_dockwidget_p.h b/src/designer/src/lib/shared/qdesigner_dockwidget_p.h new file mode 100644 index 000000000..106ed1fb6 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_dockwidget_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_DOCKWIDGET_H +#define QDESIGNER_DOCKWIDGET_H + +#include "shared_global_p.h" +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +class QDESIGNER_SHARED_EXPORT QDesignerDockWidget: public QDockWidget +{ + Q_OBJECT + Q_PROPERTY(Qt::DockWidgetArea dockWidgetArea READ dockWidgetArea WRITE setDockWidgetArea DESIGNABLE docked STORED false) + Q_PROPERTY(bool docked READ docked WRITE setDocked DESIGNABLE inMainWindow STORED false) +public: + QDesignerDockWidget(QWidget *parent = 0); + virtual ~QDesignerDockWidget(); + + bool docked() const; + void setDocked(bool b); + + Qt::DockWidgetArea dockWidgetArea() const; + void setDockWidgetArea(Qt::DockWidgetArea dockWidgetArea); + + bool inMainWindow() const; + +private: + QDesignerFormWindowInterface *formWindow() const; + QMainWindow *findMainWindow() const; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_DOCKWIDGET_H diff --git a/src/designer/src/lib/shared/qdesigner_formbuilder.cpp b/src/designer/src/lib/shared/qdesigner_formbuilder.cpp new file mode 100644 index 000000000..a8054748b --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_formbuilder.cpp @@ -0,0 +1,498 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_formbuilder_p.h" +#include "dynamicpropertysheet.h" +#include "qsimpleresource_p.h" +#include "widgetfactory_p.h" +#include "qdesigner_introspection_p.h" + +#include +#include +// sdk +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// shared +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +#ifndef QT_FORMBUILDER_NO_SCRIPT +static QString summarizeScriptErrors(const QFormScriptRunner::Errors &errors) +{ + QString rc = QCoreApplication::translate("QDesignerFormBuilder", "Script errors occurred:"); + foreach (QFormScriptRunner::Error error, errors) { + rc += QLatin1Char('\n'); + rc += error.errorMessage; + } + return rc; +} +#endif + +namespace qdesigner_internal { + +QDesignerFormBuilder::QDesignerFormBuilder(QDesignerFormEditorInterface *core, + Mode mode, + const DeviceProfile &deviceProfile) : + m_core(core), + m_mode(mode), + m_deviceProfile(deviceProfile), + m_pixmapCache(0), + m_iconCache(0), + m_ignoreCreateResources(false), + m_tempResourceSet(0), + m_mainWidget(true) +{ + Q_ASSERT(m_core); +#ifndef QT_FORMBUILDER_NO_SCRIPT + // Disable scripting in the editors. + QFormScriptRunner::Options options = formScriptRunner()->options(); + switch (m_mode) { + case DisableScripts: + options |= QFormScriptRunner::DisableScripts; + break; + case EnableScripts: + options |= QFormScriptRunner::DisableWarnings; + options &= ~QFormScriptRunner::DisableScripts; + break; + } + formScriptRunner()-> setOptions(options); +#endif +} + +QString QDesignerFormBuilder::systemStyle() const +{ + return m_deviceProfile.isEmpty() ? + QString::fromUtf8(QApplication::style()->metaObject()->className()) : + m_deviceProfile.style(); +} + +QWidget *QDesignerFormBuilder::createWidgetFromContents(const QString &contents, QWidget *parentWidget) +{ + QByteArray data = contents.toUtf8(); + QBuffer buffer(&data); + buffer.open(QIODevice::ReadOnly); + return load(&buffer, parentWidget); +} + +QWidget *QDesignerFormBuilder::create(DomUI *ui, QWidget *parentWidget) +{ + m_mainWidget = true; + QtResourceSet *resourceSet = core()->resourceModel()->currentResourceSet(); + + // reload resource properties; + createResources(ui->elementResources()); + core()->resourceModel()->setCurrentResourceSet(m_tempResourceSet); + + m_ignoreCreateResources = true; + DesignerPixmapCache pixmapCache; + DesignerIconCache iconCache(&pixmapCache); + m_pixmapCache = &pixmapCache; + m_iconCache = &iconCache; + + QWidget *widget = QFormBuilder::create(ui, parentWidget); + + core()->resourceModel()->setCurrentResourceSet(resourceSet); + core()->resourceModel()->removeResourceSet(m_tempResourceSet); + m_tempResourceSet = 0; + m_ignoreCreateResources = false; + m_pixmapCache = 0; + m_iconCache = 0; + + m_customWidgetsWithScript.clear(); + return widget; +} + +QWidget *QDesignerFormBuilder::createWidget(const QString &widgetName, QWidget *parentWidget, const QString &name) +{ + QWidget *widget = 0; + + if (widgetName == QLatin1String("QToolBar")) { + widget = new QToolBar(parentWidget); + } else if (widgetName == QLatin1String("QMenu")) { + widget = new QMenu(parentWidget); + } else if (widgetName == QLatin1String("QMenuBar")) { + widget = new QMenuBar(parentWidget); + } else { + widget = core()->widgetFactory()->createWidget(widgetName, parentWidget); + } + + if (widget) { + widget->setObjectName(name); + if (QSimpleResource::hasCustomWidgetScript(m_core, widget)) + m_customWidgetsWithScript.insert(widget); + } + + if (m_mainWidget) { // We need to apply the DPI here to take effect on size hints, etc. + m_deviceProfile.apply(m_core, widget, DeviceProfile::ApplyPreview); + m_mainWidget = false; + } + return widget; +} + +bool QDesignerFormBuilder::addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) +{ + // Use container extension or rely on scripts unless main window. + if (QFormBuilder::addItem(ui_widget, widget, parentWidget)) + return true; + + if (QDesignerContainerExtension *container = qt_extension(m_core->extensionManager(), parentWidget)) { + container->addWidget(widget); + return true; + } + return false; +} + +bool QDesignerFormBuilder::addItem(DomLayoutItem *ui_item, QLayoutItem *item, QLayout *layout) +{ + return QFormBuilder::addItem(ui_item, item, layout); +} + +QIcon QDesignerFormBuilder::nameToIcon(const QString &filePath, const QString &qrcPath) +{ + Q_UNUSED(filePath) + Q_UNUSED(qrcPath) + qWarning() << "QDesignerFormBuilder::nameToIcon() is obsoleted"; + return QIcon(); +} + +QPixmap QDesignerFormBuilder::nameToPixmap(const QString &filePath, const QString &qrcPath) +{ + Q_UNUSED(filePath) + Q_UNUSED(qrcPath) + qWarning() << "QDesignerFormBuilder::nameToPixmap() is obsoleted"; + return QPixmap(); +} + +/* If the property is a enum or flag value, retrieve + * the existing enum/flag type via property sheet and use it to convert */ + +static bool readDomEnumerationValue(const DomProperty *p, + const QDesignerPropertySheetExtension* sheet, + QVariant &v) +{ + switch (p->kind()) { + case DomProperty::Set: { + const int index = sheet->indexOf(p->attributeName()); + if (index == -1) + return false; + const QVariant sheetValue = sheet->property(index); + if (sheetValue.canConvert()) { + const PropertySheetFlagValue f = qvariant_cast(sheetValue); + bool ok = false; + v = f.metaFlags.parseFlags(p->elementSet(), &ok); + if (!ok) + designerWarning(f.metaFlags.messageParseFailed(p->elementSet())); + return true; + } + } + break; + case DomProperty::Enum: { + const int index = sheet->indexOf(p->attributeName()); + if (index == -1) + return false; + const QVariant sheetValue = sheet->property(index); + if (sheetValue.canConvert()) { + const PropertySheetEnumValue e = qvariant_cast(sheetValue); + bool ok = false; + v = e.metaEnum.parseEnum(p->elementEnum(), &ok); + if (!ok) + designerWarning(e.metaEnum.messageParseFailed(p->elementEnum())); + return true; + } + } + break; + default: + break; + } + return false; +} + +void QDesignerFormBuilder::applyProperties(QObject *o, const QList &properties) +{ + typedef QList DomPropertyList; + + if (properties.empty()) + return; + + QFormBuilderExtra *formBuilderExtra = QFormBuilderExtra::instance(this); + const QDesignerPropertySheetExtension *sheet = qt_extension(core()->extensionManager(), o); + const QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension(core()->extensionManager(), o); + const bool changingMetaObject = WidgetFactory::classNameOf(core(), o) == QLatin1String("QAxWidget"); + const QDesignerMetaObjectInterface *meta = core()->introspection()->metaObject(o); + const bool dynamicPropertiesAllowed = dynamicSheet && dynamicSheet->dynamicPropertiesAllowed(); + + QDesignerPropertySheet *designerPropertySheet = qobject_cast( + core()->extensionManager()->extension(o, Q_TYPEID(QDesignerPropertySheetExtension))); + + if (designerPropertySheet) { + if (designerPropertySheet->pixmapCache()) + designerPropertySheet->setPixmapCache(m_pixmapCache); + if (designerPropertySheet->iconCache()) + designerPropertySheet->setIconCache(m_iconCache); + } + + const DomPropertyList::const_iterator cend = properties.constEnd(); + for (DomPropertyList::const_iterator it = properties.constBegin(); it != cend; ++it) { + DomProperty *p = *it; + QVariant v; + if (!readDomEnumerationValue(p, sheet, v)) + v = toVariant(o->metaObject(), p); + + if (v.isNull()) + continue; + + const QString attributeName = p->attributeName(); + if (formBuilderExtra->applyPropertyInternally(o, attributeName, v)) + continue; + + // refuse fake properties like current tab name (weak test) + if (!dynamicPropertiesAllowed) { + if (changingMetaObject) // Changes after setting control of QAxWidget + meta = core()->introspection()->metaObject(o); + if (meta->indexOfProperty(attributeName) == -1) + continue; + } + + QObject *obj = o; + QAbstractScrollArea *scroll = qobject_cast(o); + if (scroll && attributeName == QLatin1String("cursor") && scroll->viewport()) + obj = scroll->viewport(); + + // a real property + obj->setProperty(attributeName.toUtf8(), v); + } +} + +DomWidget *QDesignerFormBuilder::createDom(QWidget *widget, DomWidget *ui_parentWidget, bool recursive) +{ + DomWidget *ui_widget = QFormBuilder::createDom(widget, ui_parentWidget, recursive); + QSimpleResource::addExtensionDataToDOM(this, m_core, ui_widget, widget); + return ui_widget; +} + +QWidget *QDesignerFormBuilder::create(DomWidget *ui_widget, QWidget *parentWidget) +{ + QWidget *widget = QFormBuilder::create(ui_widget, parentWidget); + // Do not apply state if scripts are to be run in preview mode + QSimpleResource::applyExtensionDataFromDOM(this, m_core, ui_widget, widget, m_mode == DisableScripts); + return widget; +} + +void QDesignerFormBuilder::createResources(DomResources *resources) +{ + if (m_ignoreCreateResources) + return; + QStringList paths; + if (resources != 0) { + const QList dom_include = resources->elementInclude(); + foreach (DomResource *res, dom_include) { + QString path = QDir::cleanPath(workingDirectory().absoluteFilePath(res->attributeLocation())); + paths << path; + } + } + + m_tempResourceSet = core()->resourceModel()->addResourceSet(paths); +} + +QLayout *QDesignerFormBuilder::create(DomLayout *ui_layout, QLayout *layout, QWidget *parentWidget) +{ + return QFormBuilder::create(ui_layout, layout, parentWidget); +} + +void QDesignerFormBuilder::loadExtraInfo(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget) +{ + QFormBuilder::loadExtraInfo(ui_widget, widget, parentWidget); +} + +QWidget *QDesignerFormBuilder::createPreview(const QDesignerFormWindowInterface *fw, + const QString &styleName, + const QString &appStyleSheet, + const DeviceProfile &deviceProfile, + ScriptErrors *scriptErrors, + QString *errorMessage) +{ + scriptErrors->clear(); + + // load + QDesignerFormBuilder builder(fw->core(), EnableScripts, deviceProfile); + builder.setWorkingDirectory(fw->absoluteDir()); + + const bool warningsEnabled = QSimpleResource::setWarningsEnabled(false); + QByteArray bytes = fw->contents().toUtf8(); + QSimpleResource::setWarningsEnabled(warningsEnabled); + + QBuffer buffer(&bytes); + buffer.open(QIODevice::ReadOnly); + + QWidget *widget = builder.load(&buffer, 0); + if (!widget) { // Shouldn't happen + *errorMessage = QCoreApplication::translate("QDesignerFormBuilder", "The preview failed to build."); + return 0; + } + // Make sure palette is applied + const QString styleToUse = styleName.isEmpty() ? builder.deviceProfile().style() : styleName; + if (!styleToUse.isEmpty()) { + if (WidgetFactory *wf = qobject_cast(fw->core()->widgetFactory())) { + if (styleToUse != wf->styleName()) + WidgetFactory::applyStyleToTopLevel(wf->getStyle(styleToUse), widget); + } + } +#ifndef QT_FORMBUILDER_NO_SCRIPT + // Check for script errors + *scriptErrors = builder.formScriptRunner()->errors(); + if (!scriptErrors->empty()) { + *errorMessage = summarizeScriptErrors(*scriptErrors); + delete widget; + return 0; + } +#endif + // Fake application style sheet by prepending. (If this doesn't work, fake by nesting + // into parent widget). + if (!appStyleSheet.isEmpty()) { + QString styleSheet = appStyleSheet; + styleSheet += QLatin1Char('\n'); + styleSheet += widget->styleSheet(); + widget->setStyleSheet(styleSheet); + } + return widget; +} + +QWidget *QDesignerFormBuilder::createPreview(const QDesignerFormWindowInterface *fw, const QString &styleName) +{ + return createPreview(fw, styleName, QString()); +} + +QWidget *QDesignerFormBuilder::createPreview(const QDesignerFormWindowInterface *fw, + const QString &styleName, + const QString &appStyleSheet, + const DeviceProfile &deviceProfile, + QString *errorMessage) +{ + ScriptErrors scriptErrors; + return createPreview(fw, styleName, appStyleSheet, deviceProfile, &scriptErrors, errorMessage); +} + +QWidget *QDesignerFormBuilder::createPreview(const QDesignerFormWindowInterface *fw, + const QString &styleName, + const QString &appStyleSheet, + QString *errorMessage) +{ + ScriptErrors scriptErrors; + return createPreview(fw, styleName, appStyleSheet, DeviceProfile(), &scriptErrors, errorMessage); +} + +QWidget *QDesignerFormBuilder::createPreview(const QDesignerFormWindowInterface *fw, const QString &styleName, const QString &appStyleSheet) +{ + ScriptErrors scriptErrors; + QString errorMessage; + QWidget *widget = createPreview(fw, styleName, appStyleSheet, DeviceProfile(), &scriptErrors, &errorMessage); + if (!widget) { + // Display Script errors or message box + QWidget *dialogParent = fw->core()->topLevel(); + if (scriptErrors.empty()) { + fw->core()->dialogGui()->message(dialogParent, QDesignerDialogGuiInterface::PreviewFailureMessage, + QMessageBox::Warning, QCoreApplication::translate("QDesignerFormBuilder", "Designer"), errorMessage, QMessageBox::Ok); + } else { + ScriptErrorDialog scriptErrorDialog(scriptErrors, dialogParent); + scriptErrorDialog.exec(); + } + return 0; + } + return widget; +} + +QPixmap QDesignerFormBuilder::createPreviewPixmap(const QDesignerFormWindowInterface *fw, const QString &styleName, const QString &appStyleSheet) +{ + QWidget *widget = createPreview(fw, styleName, appStyleSheet); + if (!widget) + return QPixmap(); + + const QPixmap rc = QPixmap::grabWidget (widget); + widget->deleteLater(); + return rc; +} + +// ---------- NewFormWidgetFormBuilder + +NewFormWidgetFormBuilder::NewFormWidgetFormBuilder(QDesignerFormEditorInterface *core, + Mode mode, + const DeviceProfile &deviceProfile) : + QDesignerFormBuilder(core, mode, deviceProfile) +{ +} + +void NewFormWidgetFormBuilder::createCustomWidgets(DomCustomWidgets *dc) +{ + QSimpleResource::handleDomCustomWidgets(core(), dc); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_formbuilder_p.h b/src/designer/src/lib/shared/qdesigner_formbuilder_p.h new file mode 100644 index 000000000..2f902e394 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_formbuilder_p.h @@ -0,0 +1,181 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_FORMBUILDER_H +#define QDESIGNER_FORMBUILDER_H + +#include "shared_global_p.h" +#include "deviceprofile_p.h" + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; + +class QPixmap; +class QtResourceSet; + +namespace qdesigner_internal { + +class DesignerPixmapCache; +class DesignerIconCache; + +/* Form builder used for previewing forms and widget box. + * It applies the system settings to its toplevel window. */ + +class QDESIGNER_SHARED_EXPORT QDesignerFormBuilder: public QFormBuilder +{ +public: + enum Mode { + DisableScripts, + EnableScripts + }; + + QDesignerFormBuilder(QDesignerFormEditorInterface *core, + Mode mode, + const DeviceProfile &deviceProfile = DeviceProfile()); + + QWidget *createWidgetFromContents(const QString &contents, QWidget *parentWidget = 0); + + virtual QWidget *createWidget(DomWidget *ui_widget, QWidget *parentWidget = 0) + { return QFormBuilder::create(ui_widget, parentWidget); } + + inline QDesignerFormEditorInterface *core() const + { return m_core; } + + QString systemStyle() const; + + typedef QFormScriptRunner::Errors ScriptErrors; + // Create a preview widget (for integrations) or return 0. The widget has to be embedded into a main window. + // Experimental, depending on script support. + static QWidget *createPreview(const QDesignerFormWindowInterface *fw, const QString &styleName /* ="" */, + const QString &appStyleSheet /* ="" */, + const DeviceProfile &deviceProfile, + ScriptErrors *scriptErrors, QString *errorMessage); + // Convenience that pops up message boxes in case of failures. + static QWidget *createPreview(const QDesignerFormWindowInterface *fw, const QString &styleName = QString()); + // Create a preview widget (for integrations) or return 0. The widget has to be embedded into a main window. + static QWidget *createPreview(const QDesignerFormWindowInterface *fw, const QString &styleName, const QString &appStyleSheet, QString *errorMessage); + static QWidget *createPreview(const QDesignerFormWindowInterface *fw, const QString &styleName, const QString &appStyleSheet, const DeviceProfile &deviceProfile, QString *errorMessage); + // Convenience that pops up message boxes in case of failures. + static QWidget *createPreview(const QDesignerFormWindowInterface *fw, const QString &styleName, const QString &appStyleSheet); + + // Create a preview image + static QPixmap createPreviewPixmap(const QDesignerFormWindowInterface *fw, const QString &styleName = QString(), const QString &appStyleSheet = QString()); + +protected: + using QFormBuilder::createDom; + using QFormBuilder::create; + + virtual QWidget *create(DomUI *ui, QWidget *parentWidget); + virtual DomWidget *createDom(QWidget *widget, DomWidget *ui_parentWidget, bool recursive = true); + virtual QWidget *create(DomWidget *ui_widget, QWidget *parentWidget); + virtual QLayout *create(DomLayout *ui_layout, QLayout *layout, QWidget *parentWidget); + virtual void createResources(DomResources *resources); + + virtual QWidget *createWidget(const QString &widgetName, QWidget *parentWidget, const QString &name); + virtual bool addItem(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget); + virtual bool addItem(DomLayoutItem *ui_item, QLayoutItem *item, QLayout *layout); + + virtual QIcon nameToIcon(const QString &filePath, const QString &qrcPath); + virtual QPixmap nameToPixmap(const QString &filePath, const QString &qrcPath); + + virtual void applyProperties(QObject *o, const QList &properties); + + virtual void loadExtraInfo(DomWidget *ui_widget, QWidget *widget, QWidget *parentWidget); + + QtResourceSet *internalResourceSet() const { return m_tempResourceSet; } + + DeviceProfile deviceProfile() const { return m_deviceProfile; } + +private: + QDesignerFormEditorInterface *m_core; + const Mode m_mode; + + typedef QSet WidgetSet; + WidgetSet m_customWidgetsWithScript; + + const DeviceProfile m_deviceProfile; + + DesignerPixmapCache *m_pixmapCache; + DesignerIconCache *m_iconCache; + bool m_ignoreCreateResources; + QtResourceSet *m_tempResourceSet; + bool m_mainWidget; +}; + +// Form builder for a new form widget (preview). To allow for promoted +// widgets in the template, it implements the handling of custom widgets +// (adding of them to the widget database). + +class QDESIGNER_SHARED_EXPORT NewFormWidgetFormBuilder: public QDesignerFormBuilder { +public: + NewFormWidgetFormBuilder(QDesignerFormEditorInterface *core, + Mode mode, + const DeviceProfile &deviceProfile = DeviceProfile()); + +protected: + virtual void createCustomWidgets(DomCustomWidgets *); +}; + + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QDESIGNER_FORMBUILDER_H diff --git a/src/designer/src/lib/shared/qdesigner_formeditorcommand.cpp b/src/designer/src/lib/shared/qdesigner_formeditorcommand.cpp new file mode 100644 index 000000000..bff14ac5b --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_formeditorcommand.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qdesigner_formeditorcommand_p.h" +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// ---- QDesignerFormEditorCommand ---- +QDesignerFormEditorCommand::QDesignerFormEditorCommand(const QString &description, QDesignerFormEditorInterface *core) + : QUndoCommand(description), + m_core(core) +{ +} + +QDesignerFormEditorInterface *QDesignerFormEditorCommand::core() const +{ + return m_core; +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_formeditorcommand_p.h b/src/designer/src/lib/shared/qdesigner_formeditorcommand_p.h new file mode 100644 index 000000000..7b88be9e6 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_formeditorcommand_p.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_FORMEDITORCOMMAND_H +#define QDESIGNER_FORMEDITORCOMMAND_H + +#include "shared_global_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +class QDESIGNER_SHARED_EXPORT QDesignerFormEditorCommand: public QUndoCommand +{ + +public: + QDesignerFormEditorCommand(const QString &description, QDesignerFormEditorInterface *core); + +protected: + QDesignerFormEditorInterface *core() const; + +private: + QPointer m_core; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QDESIGNER_FORMEDITORCOMMAND_H diff --git a/src/designer/src/lib/shared/qdesigner_formwindowcommand.cpp b/src/designer/src/lib/shared/qdesigner_formwindowcommand.cpp new file mode 100644 index 000000000..3efc82994 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_formwindowcommand.cpp @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include "qdesigner_formwindowcommand_p.h" +#include "qdesigner_objectinspector_p.h" +#include "layout_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// ---- QDesignerFormWindowCommand ---- +QDesignerFormWindowCommand::QDesignerFormWindowCommand(const QString &description, + QDesignerFormWindowInterface *formWindow, + QUndoCommand *parent) + : QUndoCommand(description, parent), + m_formWindow(formWindow) +{ +} + +QDesignerFormWindowInterface *QDesignerFormWindowCommand::formWindow() const +{ + return m_formWindow; +} + +QDesignerFormEditorInterface *QDesignerFormWindowCommand::core() const +{ + if (QDesignerFormWindowInterface *fw = formWindow()) + return fw->core(); + + return 0; +} + +void QDesignerFormWindowCommand::undo() +{ + cheapUpdate(); +} + +void QDesignerFormWindowCommand::redo() +{ + cheapUpdate(); +} + +void QDesignerFormWindowCommand::cheapUpdate() +{ + if (core()->objectInspector()) + core()->objectInspector()->setFormWindow(formWindow()); + + if (core()->actionEditor()) + core()->actionEditor()->setFormWindow(formWindow()); +} + +QDesignerPropertySheetExtension* QDesignerFormWindowCommand::propertySheet(QObject *object) const +{ + return qt_extension(formWindow()->core()->extensionManager(), object); +} + +void QDesignerFormWindowCommand::updateBuddies(QDesignerFormWindowInterface *form, + const QString &old_name, + const QString &new_name) +{ + QExtensionManager* extensionManager = form->core()->extensionManager(); + + typedef QList LabelList; + + const LabelList label_list = form->findChildren(); + if (label_list.empty()) + return; + + const QString buddyProperty = QLatin1String("buddy"); + const QByteArray oldNameU8 = old_name.toUtf8(); + const QByteArray newNameU8 = new_name.toUtf8(); + + const LabelList::const_iterator cend = label_list.constEnd(); + for (LabelList::const_iterator it = label_list.constBegin(); it != cend; ++it ) { + if (QDesignerPropertySheetExtension* sheet = qt_extension(extensionManager, *it)) { + const int idx = sheet->indexOf(buddyProperty); + if (idx != -1) { + const QByteArray oldBuddy = sheet->property(idx).toByteArray(); + if (oldBuddy == oldNameU8) + sheet->setProperty(idx, newNameU8); + } + } + } +} + +void QDesignerFormWindowCommand::selectUnmanagedObject(QObject *unmanagedObject) +{ + // Keep selection in sync + if (QDesignerObjectInspector *oi = qobject_cast(core()->objectInspector())) { + oi->clearSelection(); + oi->selectObject(unmanagedObject); + } + core()->propertyEditor()->setObject(unmanagedObject); +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_formwindowcommand_p.h b/src/designer/src/lib/shared/qdesigner_formwindowcommand_p.h new file mode 100644 index 000000000..7c98559e3 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_formwindowcommand_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_FORMWINDOWCOMMAND_H +#define QDESIGNER_FORMWINDOWCOMMAND_H + +#include "shared_global_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; +class QDesignerPropertySheetExtension; + +namespace qdesigner_internal { + +class QDESIGNER_SHARED_EXPORT QDesignerFormWindowCommand: public QUndoCommand +{ + +public: + QDesignerFormWindowCommand(const QString &description, + QDesignerFormWindowInterface *formWindow, + QUndoCommand *parent = 0); + + virtual void undo(); + virtual void redo(); + + static void updateBuddies(QDesignerFormWindowInterface *form, + const QString &old_name, const QString &new_name); +protected: + QDesignerFormWindowInterface *formWindow() const; + QDesignerFormEditorInterface *core() const; + QDesignerPropertySheetExtension* propertySheet(QObject *object) const; + + void cheapUpdate(); + + void selectUnmanagedObject(QObject *unmanagedObject); +private: + QPointer m_formWindow; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QDESIGNER_COMMAND_H diff --git a/src/designer/src/lib/shared/qdesigner_formwindowmanager.cpp b/src/designer/src/lib/shared/qdesigner_formwindowmanager.cpp new file mode 100644 index 000000000..1521e146e --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_formwindowmanager.cpp @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_formwindowmanager_p.h" +#include "plugindialog_p.h" + +#include + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +/*! + \class QDesignerFormWindowManager + + Extends QDesignerFormWindowManagerInterface with methods to control + the preview and printing of forms. It provides a facade that simplifies + the complexity of the more general PreviewConfiguration & PreviewManager + interfaces. + + \since 4.5 + */ + + +QDesignerFormWindowManager::QDesignerFormWindowManager(QObject *parent) + : QDesignerFormWindowManagerInterface(parent), m_unused(0) +{ +} + +QDesignerFormWindowManager::~QDesignerFormWindowManager() +{ +} + +/*! + Allows you to intervene and control \QD's form "Preview" action. The + function returns the original action. + + \since 4.5 + */ +QAction *QDesignerFormWindowManager::actionDefaultPreview() const +{ + return 0; +} + +/*! + Allows you to intervene and control \QD's form "Preview in" style action. The + function returns the original list of actions. + + The method calls PreviewManager::createStyleActionGroup() internally. + + \since 4.5 + */ +QActionGroup *QDesignerFormWindowManager::actionGroupPreviewInStyle() const +{ + return 0; +} + +/*! + \fn QPixmap QDesignerFormWindowManager::createPreviewPixmap(QString *errorMessage) + + Creates a pixmap representing the preview of the currently active form. + + The method calls PreviewManager::createPreviewPixmap() internally. + + \since 4.5 + */ + + +/*! + \fn QPixmap QDesignerFormWindowManager::closeAllPreviews() + + Closes all preview windows generated by actionDefaultPreview, actionGroupPreviewInStyle + and the corresponding methods in PreviewManager. + + \since 4.5 + */ + +/*! + \fn PreviewManager *QDesignerFormWindowManager::previewManager() + + Accesses the previewmanager implementation. + + \since 4.5 + \internal + */ + +/*! + \fn QAction *QDesignerFormWindowManager::actionShowFormWindowSettingsDialog() const; + + Allows you to intervene and control \QD's form "Form Settings" action. The + function returns the original action. + + \since 4.5 + \internal + */ + +QAction *QDesignerFormWindowManager::actionShowFormWindowSettingsDialog() const +{ + return 0; +} + +/*! + \fn void QDesignerFormWindowManager::aboutPlugins() + + Pops up an "About plugins" dialog. + + \since 4.5 + \internal + */ + +void QDesignerFormWindowManager::aboutPlugins() +{ + PluginDialog dlg(core(), core()->topLevel()); + dlg.exec(); +} + +/*! + \fn + void QDesignerFormWindowManager::formWindowSettingsChanged(QDesignerFormWindowInterface *fw); + + This signal is emitted when the form settings dialog was shown + and changes have been made to the form. + + \since 4.5 + \internal + */ + + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_formwindowmanager_p.h b/src/designer/src/lib/shared/qdesigner_formwindowmanager_p.h new file mode 100644 index 000000000..43c9149fc --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_formwindowmanager_p.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_FORMWINDOMANAGER_H +#define QDESIGNER_FORMWINDOMANAGER_H + +#include "shared_global_p.h" +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class PreviewManager; + +// +// Convenience methods to manage form previews (ultimately forwarded to PreviewManager). +// +class QDESIGNER_SHARED_EXPORT QDesignerFormWindowManager + : public QDesignerFormWindowManagerInterface +{ + Q_OBJECT +public: + explicit QDesignerFormWindowManager(QObject *parent = 0); + virtual ~QDesignerFormWindowManager(); + + virtual QAction *actionDefaultPreview() const; + virtual QActionGroup *actionGroupPreviewInStyle() const; + virtual QAction *actionShowFormWindowSettingsDialog() const; + + virtual QPixmap createPreviewPixmap(QString *errorMessage) = 0; + + virtual PreviewManager *previewManager() const = 0; + +Q_SIGNALS: + void formWindowSettingsChanged(QDesignerFormWindowInterface *fw); + +public Q_SLOTS: + virtual void closeAllPreviews() = 0; + void aboutPlugins(); + +private: + void *m_unused; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QDESIGNER_FORMWINDOMANAGER_H diff --git a/src/designer/src/lib/shared/qdesigner_integration.cpp b/src/designer/src/lib/shared/qdesigner_integration.cpp new file mode 100644 index 000000000..7470bbf80 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_integration.cpp @@ -0,0 +1,496 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_integration_p.h" +#include "qdesigner_propertycommand_p.h" +#include "qdesigner_propertyeditor_p.h" +#include "qdesigner_objectinspector_p.h" +#include "widgetdatabase_p.h" +#include "pluginmanager_p.h" +#include "widgetfactory_p.h" +#include "qdesigner_widgetbox_p.h" +#include "qtgradientmanager.h" +#include "qtgradientutils.h" +#include "qtresourcemodel_p.h" + +// sdk +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// ---------------- DesignerIntegrationPrivate +class QDesignerIntegrationPrivate { +public: + QDesignerIntegrationPrivate() + : m_gradientManager(0), + m_fileWatcherBehaviour(QDesignerIntegration::PromptAndReload), + m_resourceEditingEnabled(true), + m_slotNavigationEnabled(false) + {} + + QString m_gradientsPath; + QtGradientManager *m_gradientManager; + QDesignerIntegration::ResourceFileWatcherBehaviour m_fileWatcherBehaviour; + bool m_resourceEditingEnabled; + bool m_slotNavigationEnabled; +}; + +// -------------- QDesignerIntegration +// As of 4.4, the header will be distributed with the Eclipse plugin. + +QDesignerIntegration::QDesignerIntegration(QDesignerFormEditorInterface *core, QObject *parent) : + QDesignerIntegrationInterface(core, parent), + m_d(new QDesignerIntegrationPrivate) +{ + initialize(); +} + +QDesignerIntegration::~QDesignerIntegration() +{ + QFile f(m_d->m_gradientsPath); + if (f.open(QIODevice::WriteOnly)) { + f.write(QtGradientUtils::saveState(m_d->m_gradientManager).toUtf8()); + f.close(); + } + delete m_d; +} + +void QDesignerIntegration::initialize() +{ + // + // integrate the `Form Editor component' + // + + // Extensions + if (QDesignerPropertyEditor *designerPropertyEditor= qobject_cast(core()->propertyEditor())) { + connect(designerPropertyEditor, SIGNAL(propertyValueChanged(QString,QVariant,bool)), this, SLOT(updateProperty(QString,QVariant,bool))); + connect(designerPropertyEditor, SIGNAL(resetProperty(QString)), this, SLOT(resetProperty(QString))); + connect(designerPropertyEditor, SIGNAL(addDynamicProperty(QString,QVariant)), + this, SLOT(addDynamicProperty(QString,QVariant))); + connect(designerPropertyEditor, SIGNAL(removeDynamicProperty(QString)), + this, SLOT(removeDynamicProperty(QString))); + } else { + connect(core()->propertyEditor(), SIGNAL(propertyChanged(QString,QVariant)), + this, SLOT(updatePropertyPrivate(QString,QVariant))); + } + + connect(core()->formWindowManager(), SIGNAL(formWindowAdded(QDesignerFormWindowInterface*)), + this, SLOT(setupFormWindow(QDesignerFormWindowInterface*))); + + connect(core()->formWindowManager(), SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)), + this, SLOT(updateActiveFormWindow(QDesignerFormWindowInterface*))); + + m_d->m_gradientManager = new QtGradientManager(this); + core()->setGradientManager(m_d->m_gradientManager); + + QString designerFolder = QDir::homePath(); + designerFolder += QDir::separator(); + designerFolder += QLatin1String(".designer"); + m_d->m_gradientsPath = designerFolder; + m_d->m_gradientsPath += QDir::separator(); + m_d->m_gradientsPath += QLatin1String("gradients.xml"); + + QFile f(m_d->m_gradientsPath); + if (f.open(QIODevice::ReadOnly)) { + QtGradientUtils::restoreState(m_d->m_gradientManager, QString::fromAscii(f.readAll())); + f.close(); + } else { + QFile defaultGradients(QLatin1String(":/trolltech/designer/defaultgradients.xml")); + if (defaultGradients.open(QIODevice::ReadOnly)) { + QtGradientUtils::restoreState(m_d->m_gradientManager, QString::fromAscii(defaultGradients.readAll())); + defaultGradients.close(); + } + } + + if (WidgetDataBase *widgetDataBase = qobject_cast(core()->widgetDataBase())) + widgetDataBase->grabStandardWidgetBoxIcons(); +} + +void QDesignerIntegration::updateProperty(const QString &name, const QVariant &value, bool enableSubPropertyHandling) +{ + QDesignerFormWindowInterface *formWindow = core()->formWindowManager()->activeFormWindow(); + if (!formWindow) + return; + + Selection selection; + getSelection(selection); + if (selection.empty()) + return; + + SetPropertyCommand *cmd = new SetPropertyCommand(formWindow); + // find a reference object to compare to and to find the right group + if (cmd->init(selection.selection(), name, value, propertyEditorObject(), enableSubPropertyHandling)) { + formWindow->commandHistory()->push(cmd); + } else { + delete cmd; + qDebug() << "Unable to set property " << name << '.'; + } + + emit propertyChanged(formWindow, name, value); +} + +void QDesignerIntegration::updatePropertyPrivate(const QString &name, const QVariant &value) +{ + updateProperty(name, value, true); +} + +void QDesignerIntegration::resetProperty(const QString &name) +{ + QDesignerFormWindowInterface *formWindow = core()->formWindowManager()->activeFormWindow(); + if (!formWindow) + return; + + Selection selection; + getSelection(selection); + if (selection.empty()) + return; + + + ResetPropertyCommand *cmd = new ResetPropertyCommand(formWindow); + // find a reference object to find the right group + if (cmd->init(selection.selection(), name, propertyEditorObject())) { + formWindow->commandHistory()->push(cmd); + } else { + delete cmd; + qDebug() << "** WARNING Unable to reset property " << name << '.'; + } +} + +void QDesignerIntegration::addDynamicProperty(const QString &name, const QVariant &value) +{ + QDesignerFormWindowInterface *formWindow = core()->formWindowManager()->activeFormWindow(); + if (!formWindow) + return; + + Selection selection; + getSelection(selection); + if (selection.empty()) + return; + + AddDynamicPropertyCommand *cmd = new AddDynamicPropertyCommand(formWindow); + if (cmd->init(selection.selection(), propertyEditorObject(), name, value)) { + formWindow->commandHistory()->push(cmd); + } else { + delete cmd; + qDebug() << "** WARNING Unable to add dynamic property " << name << '.'; + } +} + +void QDesignerIntegration::removeDynamicProperty(const QString &name) +{ + QDesignerFormWindowInterface *formWindow = core()->formWindowManager()->activeFormWindow(); + if (!formWindow) + return; + + Selection selection; + getSelection(selection); + if (selection.empty()) + return; + + RemoveDynamicPropertyCommand *cmd = new RemoveDynamicPropertyCommand(formWindow); + if (cmd->init(selection.selection(), propertyEditorObject(), name)) { + formWindow->commandHistory()->push(cmd); + } else { + delete cmd; + qDebug() << "** WARNING Unable to remove dynamic property " << name << '.'; + } + +} + + +void QDesignerIntegration::updateActiveFormWindow(QDesignerFormWindowInterface *formWindow) +{ + Q_UNUSED(formWindow); + updateSelection(); +} + +void QDesignerIntegration::setupFormWindow(QDesignerFormWindowInterface *formWindow) +{ + connect(formWindow, SIGNAL(selectionChanged()), this, SLOT(updateSelection())); + connect(formWindow, SIGNAL(activated(QWidget*)), this, SLOT(activateWidget(QWidget*))); +} + +void QDesignerIntegration::updateGeometry() +{ +} + +void QDesignerIntegration::updateSelection() +{ + QDesignerFormWindowInterface *formWindow = core()->formWindowManager()->activeFormWindow(); + QWidget *selection = 0; + + if (formWindow) { + selection = formWindow->cursor()->current(); + } + + if (QDesignerActionEditorInterface *actionEditor = core()->actionEditor()) + actionEditor->setFormWindow(formWindow); + + if (QDesignerPropertyEditorInterface *propertyEditor = core()->propertyEditor()) + propertyEditor->setObject(selection); + + if (QDesignerObjectInspectorInterface *objectInspector = core()->objectInspector()) + objectInspector->setFormWindow(formWindow); + +} + +void QDesignerIntegration::activateWidget(QWidget *widget) +{ + Q_UNUSED(widget); +} + +QWidget *QDesignerIntegration::containerWindow(QWidget *widget) const +{ + // Find the parent window to apply a geometry to. + while (widget) { + if (widget->isWindow()) + break; + if (!qstrcmp(widget->metaObject()->className(), "QMdiSubWindow")) + break; + + widget = widget->parentWidget(); + } + + return widget; +} + +void QDesignerIntegration::getSelection(Selection &s) +{ + // Get multiselection from object inspector + if (QDesignerObjectInspector *designerObjectInspector = qobject_cast(core()->objectInspector())) { + designerObjectInspector->getSelection(s); + // Action editor puts actions that are not on the form yet + // into the property editor only. + if (s.empty()) + if (QObject *object = core()->propertyEditor()->object()) + s.objects.push_back(object); + + } else { + // Just in case someone plugs in an old-style object inspector: Emulate selection + s.clear(); + QDesignerFormWindowInterface *formWindow = core()->formWindowManager()->activeFormWindow(); + if (!formWindow) + return; + + QObject *object = core()->propertyEditor()->object(); + if (object->isWidgetType()) { + QWidget *widget = static_cast(object); + QDesignerFormWindowCursorInterface *cursor = formWindow->cursor(); + if (cursor->isWidgetSelected(widget)) { + s.managed.push_back(widget); + } else { + s.unmanaged.push_back(widget); + } + } else { + s.objects.push_back(object); + } + } +} + +QObject *QDesignerIntegration::propertyEditorObject() +{ + QDesignerPropertyEditorInterface *propertyEditor = core()->propertyEditor(); + if (!propertyEditor) + return 0; + return propertyEditor->object(); +} + +// Load plugins into widget database and factory. +void QDesignerIntegration::initializePlugins(QDesignerFormEditorInterface *formEditor) +{ + // load the plugins + WidgetDataBase *widgetDataBase = qobject_cast(formEditor->widgetDataBase()); + if (widgetDataBase) { + widgetDataBase->loadPlugins(); + } + + if (WidgetFactory *widgetFactory = qobject_cast(formEditor->widgetFactory())) { + widgetFactory->loadPlugins(); + } + + if (widgetDataBase) { + widgetDataBase->grabDefaultPropertyValues(); + } +} + +void QDesignerIntegration::updateCustomWidgetPlugins() +{ + QDesignerFormEditorInterface *formEditor = core(); + if (QDesignerPluginManager *pm = formEditor->pluginManager()) + pm->registerNewPlugins(); + + initializePlugins(formEditor); + + // Do not just reload the last file as the WidgetBox merges the compiled-in resources + // and $HOME/.designer/widgetbox.xml. This would also double the scratchpad. + if (QDesignerWidgetBox *wb = qobject_cast(formEditor->widgetBox())) { + const QDesignerWidgetBox::LoadMode oldLoadMode = wb->loadMode(); + wb->setLoadMode(QDesignerWidgetBox::LoadCustomWidgetsOnly); + wb->load(); + wb->setLoadMode(oldLoadMode); + } +} + +void QDesignerIntegration::emitObjectNameChanged(QDesignerFormWindowInterface *formWindow, QObject *object, const QString &newName, const QString &oldName) +{ + emit objectNameChanged(formWindow, object, newName, oldName); +} + +void QDesignerIntegration::emitNavigateToSlot(const QString &objectName, + const QString &signalSignature, + const QStringList ¶meterNames) +{ + emit navigateToSlot(objectName, signalSignature, parameterNames); +} + +void QDesignerIntegration::emitNavigateToSlot(const QString &slotSignature) +{ + emit navigateToSlot(slotSignature); +} + +void QDesignerIntegration::requestHelp(const QDesignerFormEditorInterface *core, const QString &manual, const QString &document) +{ + if (QDesignerIntegration *di = qobject_cast(core->integration())) + emit di->helpRequested(manual, document); +} + +QDesignerResourceBrowserInterface *QDesignerIntegration::createResourceBrowser(QWidget *) +{ + return 0; +} + +void QDesignerIntegration::setResourceFileWatcherBehaviour(ResourceFileWatcherBehaviour behaviour) +{ + m_d->m_fileWatcherBehaviour = behaviour; + core()->resourceModel()->setWatcherEnabled(behaviour != QDesignerIntegration::NoWatcher); +} + +QDesignerIntegration::ResourceFileWatcherBehaviour QDesignerIntegration::resourceFileWatcherBehaviour() const +{ + return m_d->m_fileWatcherBehaviour; +} + +void QDesignerIntegration::setResourceEditingEnabled(bool enable) +{ + m_d->m_resourceEditingEnabled = enable; +} + +bool QDesignerIntegration::isResourceEditingEnabled() const +{ + return m_d->m_resourceEditingEnabled; +} + +void QDesignerIntegration::setSlotNavigationEnabled(bool enable) +{ + m_d->m_slotNavigationEnabled = enable; +} + +bool QDesignerIntegration::isSlotNavigationEnabled() const +{ + return m_d->m_slotNavigationEnabled; +} + +static QString fixHelpClassName(const QString &className) +{ + // ### generalize using the Widget Data Base + if (className == QLatin1String("Line")) + return QLatin1String("QFrame"); + if (className == QLatin1String("Spacer")) + return QLatin1String("QSpacerItem"); + if (className == QLatin1String("QLayoutWidget")) + return QLatin1String("QLayout"); + return className; +} + +// Return class in which the property is defined +static QString classForProperty(QDesignerFormEditorInterface *core, + QObject *object, + const QString &property) +{ + if (const QDesignerPropertySheetExtension *ps = qt_extension(core->extensionManager(), object)) { + const int index = ps->indexOf(property); + if (index >= 0) + return ps->propertyGroup(index); + } + return QString(); +} + +QString QDesignerIntegration::contextHelpId() const +{ + QObject *currentObject = core()->propertyEditor()->object(); + if (!currentObject) + return QString(); + // Return a help index id consisting of "class::property" + QString className; + QString currentPropertyName = core()->propertyEditor()->currentPropertyName(); + if (!currentPropertyName.isEmpty()) + className = classForProperty(core(), currentObject, currentPropertyName); + if (className.isEmpty()) { + currentPropertyName.clear(); // We hit on some fake property. + className = WidgetFactory::classNameOf(core(), currentObject); + } + QString helpId = fixHelpClassName(className); + if (!currentPropertyName.isEmpty()) { + helpId += QLatin1String("::"); + helpId += currentPropertyName; + } + return helpId; +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_integration_p.h b/src/designer/src/lib/shared/qdesigner_integration_p.h new file mode 100644 index 000000000..f4fdff7db --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_integration_p.h @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_INTEGRATION_H +#define QDESIGNER_INTEGRATION_H + +#include "shared_global_p.h" +#include + +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; +class QDesignerResourceBrowserInterface; + +class QVariant; +class QWidget; + +namespace qdesigner_internal { + +struct Selection; +class QDesignerIntegrationPrivate; + +class QDESIGNER_SHARED_EXPORT QDesignerIntegration: public QDesignerIntegrationInterface +{ + Q_OBJECT +public: + explicit QDesignerIntegration(QDesignerFormEditorInterface *core, QObject *parent = 0); + virtual ~QDesignerIntegration(); + + static void requestHelp(const QDesignerFormEditorInterface *core, const QString &manual, const QString &document); + + virtual QWidget *containerWindow(QWidget *widget) const; + + // Load plugins into widget database and factory. + static void initializePlugins(QDesignerFormEditorInterface *formEditor); + void emitObjectNameChanged(QDesignerFormWindowInterface *formWindow, QObject *object, + const QString &newName, const QString &oldName); + void emitNavigateToSlot(const QString &objectName, const QString &signalSignature, const QStringList ¶meterNames); + void emitNavigateToSlot(const QString &slotSignature); + + // Create a resource browser specific to integration. Language integration takes precedence + virtual QDesignerResourceBrowserInterface *createResourceBrowser(QWidget *parent = 0); + + enum ResourceFileWatcherBehaviour { + NoWatcher, + ReloadSilently, + PromptAndReload + }; + + ResourceFileWatcherBehaviour resourceFileWatcherBehaviour() const; + bool isResourceEditingEnabled() const; + bool isSlotNavigationEnabled() const; + + QString contextHelpId() const; + +protected: + + void setResourceFileWatcherBehaviour(ResourceFileWatcherBehaviour behaviour); // PromptAndReload by default + void setResourceEditingEnabled(bool enable); // true by default + void setSlotNavigationEnabled(bool enable); // false by default + +signals: + void propertyChanged(QDesignerFormWindowInterface *formWindow, const QString &name, const QVariant &value); + void objectNameChanged(QDesignerFormWindowInterface *formWindow, QObject *object, const QString &newName, const QString &oldName); + void helpRequested(const QString &manual, const QString &document); + + void navigateToSlot(const QString &objectName, const QString &signalSignature, const QStringList ¶meterNames); + void navigateToSlot(const QString &slotSignature); + +public slots: + virtual void updateProperty(const QString &name, const QVariant &value, bool enableSubPropertyHandling); + // Additional signals of designer property editor + virtual void resetProperty(const QString &name); + virtual void addDynamicProperty(const QString &name, const QVariant &value); + virtual void removeDynamicProperty(const QString &name); + + virtual void updateActiveFormWindow(QDesignerFormWindowInterface *formWindow); + virtual void setupFormWindow(QDesignerFormWindowInterface *formWindow); + virtual void updateSelection(); + virtual void updateGeometry(); + virtual void activateWidget(QWidget *widget); + + void updateCustomWidgetPlugins(); + +private slots: + void updatePropertyPrivate(const QString &name, const QVariant &value); + +private: + void initialize(); + void getSelection(Selection &s); + QObject *propertyEditorObject(); + + QDesignerIntegrationPrivate *m_d; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QDESIGNER_INTEGRATION_H diff --git a/src/designer/src/lib/shared/qdesigner_introspection.cpp b/src/designer/src/lib/shared/qdesigner_introspection.cpp new file mode 100644 index 000000000..9d45acca6 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_introspection.cpp @@ -0,0 +1,372 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_introspection_p.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +// Qt Implementation +static QStringList byteArrayListToStringList(const QList &l) +{ + if (l.empty()) + return QStringList(); + QStringList rc; + const QList::const_iterator cend = l.constEnd(); + for (QList::const_iterator it = l.constBegin(); it != cend; ++it) + rc += QString::fromUtf8(*it); + return rc; +} + +static inline QString charToQString(const char *c) +{ + if (!c) + return QString(); + return QString::fromUtf8(c); +} + +namespace { + // ------- QDesignerMetaEnum + class QDesignerMetaEnum : public QDesignerMetaEnumInterface { + public: + QDesignerMetaEnum(const QMetaEnum &qEnum); + virtual bool isFlag() const { return m_enum.isFlag(); } + virtual QString key(int index) const { return charToQString(m_enum.key(index)); } + virtual int keyCount() const { return m_enum.keyCount(); } + virtual int keyToValue(const QString &key) const { return m_enum.keyToValue(key.toUtf8()); } + virtual int keysToValue(const QString &keys) const { return m_enum.keysToValue(keys.toUtf8()); } + virtual QString name() const { return m_name; } + virtual QString scope() const { return m_scope; } + virtual QString separator() const; + virtual int value(int index) const { return m_enum.value(index); } + virtual QString valueToKey(int value) const { return charToQString(m_enum.valueToKey(value)); } + virtual QString valueToKeys(int value) const { return charToQString(m_enum.valueToKeys(value)); } + + private: + const QMetaEnum m_enum; + const QString m_name; + const QString m_scope; + }; + + QDesignerMetaEnum::QDesignerMetaEnum(const QMetaEnum &qEnum) : + m_enum(qEnum), + m_name(charToQString(m_enum.name())), + m_scope(charToQString(m_enum.scope())) + { + } + + QString QDesignerMetaEnum::separator() const + { + static const QString rc = QLatin1String("::"); + return rc; + } + + // ------- QDesignerMetaProperty + class QDesignerMetaProperty : public QDesignerMetaPropertyInterface { + public: + QDesignerMetaProperty(const QMetaProperty &property); + virtual ~QDesignerMetaProperty(); + + virtual const QDesignerMetaEnumInterface *enumerator() const { return m_enumerator; } + + virtual Kind kind() const { return m_kind; } + + virtual AccessFlags accessFlags() const { return m_access; } + virtual Attributes attributes(const QObject *object = 0) const; + + virtual QVariant::Type type() const { return m_property.type(); } + virtual QString name() const { return m_name; } + virtual QString typeName() const { return m_typeName; } + virtual int userType() const { return m_property.userType(); } + virtual bool hasSetter() const { return m_property.hasStdCppSet(); } + + virtual QVariant read(const QObject *object) const { return m_property.read(object); } + virtual bool reset(QObject *object) const { return m_property.reset(object); } + virtual bool write(QObject *object, const QVariant &value) const { return m_property.write(object, value); } + + private: + const QMetaProperty m_property; + const QString m_name; + const QString m_typeName; + Kind m_kind; + AccessFlags m_access; + Attributes m_defaultAttributes; + QDesignerMetaEnumInterface *m_enumerator; + }; + + QDesignerMetaProperty::QDesignerMetaProperty(const QMetaProperty &property) : + m_property(property), + m_name(charToQString(m_property.name())), + m_typeName(charToQString(m_property.typeName())), + m_kind(OtherKind), + m_enumerator(0) + { + if (m_property.isFlagType() || m_property.isEnumType()) { + const QMetaEnum metaEnum = m_property.enumerator(); + Q_ASSERT(metaEnum.isValid()); + m_enumerator = new QDesignerMetaEnum(metaEnum); + } + // kind + if (m_property.isFlagType()) + m_kind = FlagKind; + else + if (m_property.isEnumType()) + m_kind = EnumKind; + // flags and attributes + if (m_property.isReadable()) + m_access |= ReadAccess; + if (m_property.isWritable()) + m_access |= WriteAccess; + if (m_property.isResettable()) + m_access |= ResetAccess; + + if (m_property.isDesignable()) + m_defaultAttributes |= DesignableAttribute; + if (m_property.isScriptable()) + m_defaultAttributes |= ScriptableAttribute; + if (m_property.isStored()) + m_defaultAttributes |= StoredAttribute; + if (m_property.isUser()) + m_defaultAttributes |= UserAttribute; + } + + QDesignerMetaProperty::~QDesignerMetaProperty() + { + delete m_enumerator; + } + + QDesignerMetaProperty::Attributes QDesignerMetaProperty::attributes(const QObject *object) const + { + if (!object) + return m_defaultAttributes; + Attributes rc; + if (m_property.isDesignable(object)) + rc |= DesignableAttribute; + if (m_property.isScriptable(object)) + rc |= ScriptableAttribute; + if (m_property.isStored(object)) + rc |= StoredAttribute; + if (m_property.isUser(object)) + rc |= UserAttribute; + return rc; + } + + // -------------- QDesignerMetaMethod + + class QDesignerMetaMethod : public QDesignerMetaMethodInterface { + public: + QDesignerMetaMethod(const QMetaMethod &method); + + virtual Access access() const { return m_access; } + virtual MethodType methodType() const { return m_methodType; } + virtual QStringList parameterNames() const { return m_parameterNames; } + virtual QStringList parameterTypes() const { return m_parameterTypes; } + virtual QString signature() const { return m_signature; } + virtual QString normalizedSignature() const { return m_normalizedSignature; } + virtual QString tag() const { return m_tag; } + virtual QString typeName() const { return m_typeName; } + + private: + Access m_access; + MethodType m_methodType; + const QStringList m_parameterNames; + const QStringList m_parameterTypes; + const QString m_signature; + const QString m_normalizedSignature; + const QString m_tag; + const QString m_typeName; + }; + + QDesignerMetaMethod::QDesignerMetaMethod(const QMetaMethod &method) : + m_parameterNames(byteArrayListToStringList(method.parameterNames())), + m_parameterTypes(byteArrayListToStringList(method.parameterTypes())), + m_signature(charToQString(method.signature())), + m_normalizedSignature(charToQString(QMetaObject::normalizedSignature(method.signature()))), + m_tag(charToQString(method.tag())), + m_typeName(charToQString(method.typeName())) + { + switch (method.access()) { + case QMetaMethod::Public: + m_access = Public; + break; + case QMetaMethod::Protected: + m_access = Protected; + break; + case QMetaMethod::Private: + m_access = Private; + break; + + } + switch (method.methodType()) { + case QMetaMethod::Constructor: + m_methodType = Constructor; + break; + case QMetaMethod::Method: + m_methodType = Method; + break; + case QMetaMethod::Signal: + m_methodType = Signal; + break; + + case QMetaMethod::Slot: + m_methodType = Slot; + break; + } + } + + // ------------- QDesignerMetaObject + class QDesignerMetaObject : public QDesignerMetaObjectInterface { + public: + QDesignerMetaObject(const qdesigner_internal::QDesignerIntrospection *introspection, const QMetaObject *metaObject); + virtual ~QDesignerMetaObject(); + + virtual QString className() const { return m_className; } + virtual const QDesignerMetaEnumInterface *enumerator(int index) const { return m_enumerators[index]; } + virtual int enumeratorCount() const { return m_enumerators.size(); } + virtual int enumeratorOffset() const { return m_metaObject->enumeratorOffset(); } + + virtual int indexOfEnumerator(const QString &name) const { return m_metaObject->indexOfEnumerator(name.toUtf8()); } + virtual int indexOfMethod(const QString &method) const { return m_metaObject->indexOfMethod(method.toUtf8()); } + virtual int indexOfProperty(const QString &name) const { return m_metaObject->indexOfProperty(name.toUtf8()); } + virtual int indexOfSignal(const QString &signal) const { return m_metaObject->indexOfSignal(signal.toUtf8()); } + virtual int indexOfSlot(const QString &slot) const { return m_metaObject->indexOfSlot(slot.toUtf8()); } + + virtual const QDesignerMetaMethodInterface *method(int index) const { return m_methods[index]; } + virtual int methodCount() const { return m_methods.size(); } + virtual int methodOffset() const { return m_metaObject->methodOffset(); } + + virtual const QDesignerMetaPropertyInterface *property(int index) const { return m_properties[index]; } + virtual int propertyCount() const { return m_properties.size(); } + virtual int propertyOffset() const { return m_metaObject->propertyOffset(); } + + const QDesignerMetaObjectInterface *superClass() const; + virtual const QDesignerMetaPropertyInterface *userProperty() const { return m_userProperty; } + + private: + const QString m_className; + const qdesigner_internal::QDesignerIntrospection *m_introspection; + const QMetaObject *m_metaObject; + + typedef QVector Enumerators; + Enumerators m_enumerators; + + typedef QVector Methods; + Methods m_methods; + + typedef QVector Properties; + Properties m_properties; + + QDesignerMetaPropertyInterface *m_userProperty; + }; + + QDesignerMetaObject::QDesignerMetaObject(const qdesigner_internal::QDesignerIntrospection *introspection, const QMetaObject *metaObject) : + m_className(charToQString(metaObject->className())), + m_introspection(introspection), + m_metaObject(metaObject), + m_userProperty(0) + { + const int numEnumerators = metaObject->enumeratorCount(); + m_enumerators.reserve(numEnumerators); + for (int i = 0; i < numEnumerators; i++) + m_enumerators.push_back(new QDesignerMetaEnum(metaObject->enumerator(i))); + const int numMethods = metaObject->methodCount(); + m_methods.reserve(numMethods); + for (int i = 0; i < numMethods; i++) + m_methods.push_back(new QDesignerMetaMethod(metaObject->method(i))); + + const int numProperties = metaObject->propertyCount(); + m_properties.reserve(numProperties); + for (int i = 0; i < numProperties; i++) + m_properties.push_back(new QDesignerMetaProperty(metaObject->property(i))); + + const QMetaProperty userProperty = metaObject->userProperty(); + if (userProperty.isValid()) + m_userProperty = new QDesignerMetaProperty(userProperty); + } + + QDesignerMetaObject::~QDesignerMetaObject() + { + qDeleteAll(m_enumerators); + qDeleteAll(m_methods); + qDeleteAll(m_properties); + delete m_userProperty; + } + + const QDesignerMetaObjectInterface *QDesignerMetaObject::superClass() const + { + const QMetaObject *qSuperClass = m_metaObject->superClass(); + if (!qSuperClass) + return 0; + return m_introspection->metaObjectForQMetaObject(qSuperClass); + } + +} + +namespace qdesigner_internal { + + QDesignerIntrospection::QDesignerIntrospection() + { + } + + QDesignerIntrospection::~QDesignerIntrospection() + { + qDeleteAll(m_metaObjectMap.values()); + } + + const QDesignerMetaObjectInterface* QDesignerIntrospection::metaObject(const QObject *object) const + { + return metaObjectForQMetaObject(object->metaObject()); + } + + const QDesignerMetaObjectInterface* QDesignerIntrospection::metaObjectForQMetaObject(const QMetaObject *metaObject) const + { + MetaObjectMap::iterator it = m_metaObjectMap.find(metaObject); + if (it == m_metaObjectMap.end()) + it = m_metaObjectMap.insert(metaObject, new QDesignerMetaObject(this, metaObject)); + return it.value(); + } +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_introspection_p.h b/src/designer/src/lib/shared/qdesigner_introspection_p.h new file mode 100644 index 000000000..ed4785f87 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_introspection_p.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef DESIGNERINTROSPECTION +#define DESIGNERINTROSPECTION + +#include "shared_global_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +struct QMetaObject; +class QWidget; + +namespace qdesigner_internal { + // Qt C++ introspection with helpers to find core and meta object for an object + class QDESIGNER_SHARED_EXPORT QDesignerIntrospection : public QDesignerIntrospectionInterface { + public: + QDesignerIntrospection(); + virtual ~QDesignerIntrospection(); + + virtual const QDesignerMetaObjectInterface* metaObject(const QObject *object) const; + + const QDesignerMetaObjectInterface* metaObjectForQMetaObject(const QMetaObject *metaObject) const; + private: + typedef QMap MetaObjectMap; + mutable MetaObjectMap m_metaObjectMap; + + }; +} + +QT_END_NAMESPACE + +#endif // DESIGNERINTROSPECTION diff --git a/src/designer/src/lib/shared/qdesigner_membersheet.cpp b/src/designer/src/lib/shared/qdesigner_membersheet.cpp new file mode 100644 index 000000000..f70fc389b --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_membersheet.cpp @@ -0,0 +1,371 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_membersheet_p.h" + +#include +#include + +#include + +namespace { + +class Qt3Members + { + public: + static Qt3Members *instance(); + QMap getSignals() const { return m_classNameToSignals; } + QMap getSlots() const { return m_classNameToSlots; } + private: + Qt3Members(); + static Qt3Members *m_instance; + QMap m_classNameToSignals; + QMap m_classNameToSlots; + }; + +Qt3Members *Qt3Members::m_instance = 0; + +Qt3Members::Qt3Members() +{ + m_classNameToSignals[QLatin1String("QTextEdit")].append(QLatin1String("currentFontChanged(QFont)")); + m_classNameToSignals[QLatin1String("QTextEdit")].append(QLatin1String("currentColorChanged(QColor)")); + m_classNameToSignals[QLatin1String("QTabWidget")].append(QLatin1String("currentChanged(QWidget*)")); + m_classNameToSignals[QLatin1String("QTabWidget")].append(QLatin1String("selected(QString)")); + m_classNameToSignals[QLatin1String("QTabBar")].append(QLatin1String("selected(int)")); + m_classNameToSignals[QLatin1String("QMenuBar")].append(QLatin1String("activated(int)")); + m_classNameToSignals[QLatin1String("QMenuBar")].append(QLatin1String("highlighted(int)")); + m_classNameToSignals[QLatin1String("QMenu")].append(QLatin1String("activated(int)")); + m_classNameToSignals[QLatin1String("QMenu")].append(QLatin1String("highlighted(int)")); + m_classNameToSignals[QLatin1String("QLineEdit")].append(QLatin1String("lostFocus()")); + m_classNameToSignals[QLatin1String("QDial")].append(QLatin1String("dialPressed()")); + m_classNameToSignals[QLatin1String("QDial")].append(QLatin1String("dialMoved(int)")); + m_classNameToSignals[QLatin1String("QDial")].append(QLatin1String("dialReleased()")); + m_classNameToSignals[QLatin1String("QComboBox")].append(QLatin1String("textChanged(QString)")); + m_classNameToSignals[QLatin1String("QActionGroup")].append(QLatin1String("selected(QAction*)")); + m_classNameToSignals[QLatin1String("QAction")].append(QLatin1String("activated(int)")); + m_classNameToSignals[QLatin1String("QAbstractSocket")].append(QLatin1String("connectionClosed()")); + m_classNameToSignals[QLatin1String("QAbstractSocket")].append(QLatin1String("delayedCloseFinished()")); + + m_classNameToSlots[QLatin1String("QWidget")].append(QLatin1String("setShown(bool)")); + m_classNameToSlots[QLatin1String("QToolButton")].append(QLatin1String("setTextPosition(QToolButton::TextPosition)")); + m_classNameToSlots[QLatin1String("QToolButton")].append(QLatin1String("setUsesBigPixmap(bool)")); + m_classNameToSlots[QLatin1String("QToolButton")].append(QLatin1String("setUsesTextLabel(bool)")); + m_classNameToSlots[QLatin1String("QTextEdit")].append(QLatin1String("setModified(bool)")); + m_classNameToSlots[QLatin1String("QTextEdit")].append(QLatin1String("setColor(QColor)")); + m_classNameToSlots[QLatin1String("QTabWidget")].append(QLatin1String("setCurrentPage(int)")); + m_classNameToSlots[QLatin1String("QTabWidget")].append(QLatin1String("showPage(QWidget*)")); + m_classNameToSlots[QLatin1String("QTabWidget")].append(QLatin1String("removePage(QWidget*)")); + m_classNameToSlots[QLatin1String("QTabBar")].append(QLatin1String("setCurrentTab(int)")); + m_classNameToSlots[QLatin1String("QStatusBar")].append(QLatin1String("message(QString,int)")); + m_classNameToSlots[QLatin1String("QStatusBar")].append(QLatin1String("clear()")); + m_classNameToSlots[QLatin1String("QSplashScreen")].append(QLatin1String("message(QString,int)")); + m_classNameToSlots[QLatin1String("QSplashScreen")].append(QLatin1String("clear()")); + m_classNameToSlots[QLatin1String("QSlider")].append(QLatin1String("addStep()")); + m_classNameToSlots[QLatin1String("QSlider")].append(QLatin1String("subtractStep()")); + m_classNameToSlots[QLatin1String("QAbstractButton")].append(QLatin1String("setOn(bool)")); + m_classNameToSlots[QLatin1String("QAction")].append(QLatin1String("setOn(bool)")); + m_classNameToSlots[QLatin1String("QErrorMessage")].append(QLatin1String("message(QString)")); + m_classNameToSlots[QLatin1String("QTimer")].append(QLatin1String("changeInterval(int)")); + m_classNameToSlots[QLatin1String("QTimer")].append(QLatin1String("start(int,bool)")); +} + +Qt3Members *Qt3Members::instance() +{ + if (!m_instance) + m_instance = new Qt3Members(); + return m_instance; +} +} + +QT_BEGIN_NAMESPACE + +static QList stringListToByteArray(const QStringList &l) +{ + if (l.empty()) + return QList(); + QList rc; + const QStringList::const_iterator cend = l.constEnd(); + for (QStringList::const_iterator it = l.constBegin(); it != cend; ++it) + rc += it->toUtf8(); + return rc; +} + +// Find the form editor in the hierarchy. +// We know that the parent of the sheet is the extension manager +// whose parent is the core. + +static QDesignerFormEditorInterface *formEditorForObject(QObject *o) { + do { + if (QDesignerFormEditorInterface* core = qobject_cast(o)) + return core; + o = o->parent(); + } while(o); + Q_ASSERT(o); + return 0; +} + +// ------------ QDesignerMemberSheetPrivate +class QDesignerMemberSheetPrivate { +public: + explicit QDesignerMemberSheetPrivate(QObject *object, QObject *sheetParent); + + QDesignerFormEditorInterface *m_core; + const QDesignerMetaObjectInterface *m_meta; + + class Info { + public: + inline Info() : visible(true) {} + + QString group; + bool visible; + }; + + typedef QHash InfoHash; + + Info &ensureInfo(int index); + + InfoHash m_info; +}; + +QDesignerMemberSheetPrivate::QDesignerMemberSheetPrivate(QObject *object, QObject *sheetParent) : + m_core(formEditorForObject(sheetParent)), + m_meta(m_core->introspection()->metaObject(object)) +{ +} + +QDesignerMemberSheetPrivate::Info &QDesignerMemberSheetPrivate::ensureInfo(int index) +{ + InfoHash::iterator it = m_info.find(index); + if (it == m_info.end()) { + it = m_info.insert(index, Info()); + } + return it.value(); +} + +// --------- QDesignerMemberSheet + +QDesignerMemberSheet::QDesignerMemberSheet(QObject *object, QObject *parent) : + QObject(parent), + d(new QDesignerMemberSheetPrivate(object, parent)) +{ +} + +QDesignerMemberSheet::~QDesignerMemberSheet() +{ + delete d; +} + +int QDesignerMemberSheet::count() const +{ + return d->m_meta->methodCount(); +} + +int QDesignerMemberSheet::indexOf(const QString &name) const +{ + return d->m_meta->indexOfMethod(name); +} + +QString QDesignerMemberSheet::memberName(int index) const +{ + return d->m_meta->method(index)->tag(); +} + +QString QDesignerMemberSheet::declaredInClass(int index) const +{ + const QString member = d->m_meta->method(index)->signature(); + + // Find class whose superclass does not contain the method. + const QDesignerMetaObjectInterface *meta_obj = d->m_meta; + + for (;;) { + const QDesignerMetaObjectInterface *tmp = meta_obj->superClass(); + if (tmp == 0) + break; + if (tmp->indexOfMethod(member) == -1) + break; + meta_obj = tmp; + } + return meta_obj->className(); +} + +QString QDesignerMemberSheet::memberGroup(int index) const +{ + return d->m_info.value(index).group; +} + +void QDesignerMemberSheet::setMemberGroup(int index, const QString &group) +{ + d->ensureInfo(index).group = group; +} + +QString QDesignerMemberSheet::signature(int index) const +{ + return d->m_meta->method(index)->normalizedSignature(); +} + +bool QDesignerMemberSheet::isVisible(int index) const +{ + typedef QDesignerMemberSheetPrivate::InfoHash InfoHash; + const InfoHash::const_iterator it = d->m_info.constFind(index); + if (it != d->m_info.constEnd()) + return it.value().visible; + + return d->m_meta->method(index)->methodType() == QDesignerMetaMethodInterface::Signal + || d->m_meta->method(index)->access() == QDesignerMetaMethodInterface::Public; +} + +void QDesignerMemberSheet::setVisible(int index, bool visible) +{ + d->ensureInfo(index).visible = visible; +} + +bool QDesignerMemberSheet::isSignal(int index) const +{ + return d->m_meta->method(index)->methodType() == QDesignerMetaMethodInterface::Signal; +} + +bool QDesignerMemberSheet::isSlot(int index) const +{ + return d->m_meta->method(index)->methodType() == QDesignerMetaMethodInterface::Slot; +} + +bool QDesignerMemberSheet::inheritedFromWidget(int index) const +{ + const QString name = d->m_meta->method(index)->signature(); + return declaredInClass(index) == QLatin1String("QWidget") || declaredInClass(index) == QLatin1String("QObject"); +} + + +QList QDesignerMemberSheet::parameterTypes(int index) const +{ + return stringListToByteArray(d->m_meta->method(index)->parameterTypes()); +} + +QList QDesignerMemberSheet::parameterNames(int index) const +{ + return stringListToByteArray(d->m_meta->method(index)->parameterNames()); +} + +bool QDesignerMemberSheet::signalMatchesSlot(const QString &signal, const QString &slot) +{ + bool result = true; + + do { + int signal_idx = signal.indexOf(QLatin1Char('(')); + int slot_idx = slot.indexOf(QLatin1Char('(')); + if (signal_idx == -1 || slot_idx == -1) + break; + + ++signal_idx; ++slot_idx; + + if (slot.at(slot_idx) == QLatin1Char(')')) + break; + + while (signal_idx < signal.size() && slot_idx < slot.size()) { + const QChar signal_c = signal.at(signal_idx); + const QChar slot_c = slot.at(slot_idx); + + if (signal_c == QLatin1Char(',') && slot_c == QLatin1Char(')')) + break; + + if (signal_c == QLatin1Char(')') && slot_c == QLatin1Char(')')) + break; + + if (signal_c != slot_c) { + result = false; + break; + } + + ++signal_idx; ++slot_idx; + } + } while (false); + + return result; +} + +bool QDesignerMemberSheet::isQt3Signal(int index) const +{ + if (!isSignal(index)) + return false; + + const QString className = declaredInClass(index); + const QString signalSignature = signature(index); + + QMap qt3signals = Qt3Members::instance()->getSignals(); + QMap::const_iterator it = qt3signals.constFind(className); + if (it != qt3signals.constEnd() && (*it).contains(signalSignature)) + return true; + + return false; +} + +bool QDesignerMemberSheet::isQt3Slot(int index) const +{ + if (!isSlot(index)) + return false; + + const QString className = declaredInClass(index); + const QString slotSignature = signature(index); + + QMap qt3slots = Qt3Members::instance()->getSlots(); + QMap::const_iterator it = qt3slots.constFind(className); + if (it != qt3slots.constEnd() && (*it).contains(slotSignature)) + return true; + return false; +} + +// ------------ QDesignerMemberSheetFactory + +QDesignerMemberSheetFactory::QDesignerMemberSheetFactory(QExtensionManager *parent) + : QExtensionFactory(parent) +{ +} + +QObject *QDesignerMemberSheetFactory::createExtension(QObject *object, const QString &iid, QObject *parent) const +{ + if (iid == Q_TYPEID(QDesignerMemberSheetExtension)) { + return new QDesignerMemberSheet(object, parent); + } + + return 0; +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_membersheet_p.h b/src/designer/src/lib/shared/qdesigner_membersheet_p.h new file mode 100644 index 000000000..0f0f5736c --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_membersheet_p.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_MEMBERSHEET_H +#define QDESIGNER_MEMBERSHEET_H + +#include "shared_global_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerMemberSheetPrivate; + +class QDESIGNER_SHARED_EXPORT QDesignerMemberSheet: public QObject, public QDesignerMemberSheetExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerMemberSheetExtension) + +public: + explicit QDesignerMemberSheet(QObject *object, QObject *parent = 0); + virtual ~QDesignerMemberSheet(); + + virtual int indexOf(const QString &name) const; + + virtual int count() const; + virtual QString memberName(int index) const; + + virtual QString memberGroup(int index) const; + virtual void setMemberGroup(int index, const QString &group); + + virtual bool isVisible(int index) const; + virtual void setVisible(int index, bool b); + + virtual bool isSignal(int index) const; + virtual bool isSlot(int index) const; + + virtual bool isQt3Signal(int index) const; + virtual bool isQt3Slot(int index) const; + + virtual bool inheritedFromWidget(int index) const; + + static bool signalMatchesSlot(const QString &signal, const QString &slot); + + virtual QString declaredInClass(int index) const; + + virtual QString signature(int index) const; + virtual QList parameterTypes(int index) const; + virtual QList parameterNames(int index) const; + +private: + QDesignerMemberSheetPrivate *d; +}; + +class QDESIGNER_SHARED_EXPORT QDesignerMemberSheetFactory: public QExtensionFactory +{ + Q_OBJECT + Q_INTERFACES(QAbstractExtensionFactory) + +public: + QDesignerMemberSheetFactory(QExtensionManager *parent = 0); + +protected: + virtual QObject *createExtension(QObject *object, const QString &iid, QObject *parent) const; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_MEMBERSHEET_H diff --git a/src/designer/src/lib/shared/qdesigner_menu.cpp b/src/designer/src/lib/shared/qdesigner_menu.cpp new file mode 100644 index 000000000..e9abf30cd --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_menu.cpp @@ -0,0 +1,1390 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_menu_p.h" +#include "qdesigner_menubar_p.h" +#include "qdesigner_toolbar_p.h" +#include "qdesigner_command_p.h" +#include "qdesigner_propertycommand_p.h" +#include "actionrepository_p.h" +#include "actionprovider_p.h" +#include "actioneditor_p.h" +#include "qdesigner_utils_p.h" +#include "qdesigner_objectinspector_p.h" + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +Q_DECLARE_METATYPE(QAction*) + +QT_BEGIN_NAMESPACE + +using namespace qdesigner_internal; + +// give the user a little more space to click on the sub menu rectangle +static inline void extendClickableArea(QRect *subMenuRect, Qt::LayoutDirection dir) +{ + switch (dir) { + case Qt::LayoutDirectionAuto: // Should never happen + case Qt::LeftToRight: + subMenuRect->setLeft(subMenuRect->left() - 20); + break; + case Qt::RightToLeft: + subMenuRect->setRight(subMenuRect->right() + 20); + break; + } +} + +QDesignerMenu::QDesignerMenu(QWidget *parent) : + QMenu(parent), + m_subMenuPixmap(QPixmap(QLatin1String(":/trolltech/formeditor/images/submenu.png"))), + m_currentIndex(0), + m_addItem(new SpecialMenuAction(this)), + m_addSeparator(new SpecialMenuAction(this)), + m_showSubMenuTimer(new QTimer(this)), + m_deactivateWindowTimer(new QTimer(this)), + m_adjustSizeTimer(new QTimer(this)), + m_editor(new QLineEdit(this)), + m_dragging(false), + m_lastSubMenuIndex(-1) +{ + setContextMenuPolicy(Qt::DefaultContextMenu); + setAcceptDrops(true); // ### fake + setSeparatorsCollapsible(false); + + connect(m_adjustSizeTimer, SIGNAL(timeout()), this, SLOT(slotAdjustSizeNow())); + m_addItem->setText(tr("Type Here")); + addAction(m_addItem); + + m_addSeparator->setText(tr("Add Separator")); + addAction(m_addSeparator); + + connect(m_showSubMenuTimer, SIGNAL(timeout()), this, SLOT(slotShowSubMenuNow())); + + connect(m_deactivateWindowTimer, SIGNAL(timeout()), this, SLOT(slotDeactivateNow())); + + m_editor->setObjectName(QLatin1String("__qt__passive_editor")); + m_editor->hide(); + + m_editor->installEventFilter(this); + installEventFilter(this); +} + +QDesignerMenu::~QDesignerMenu() +{ +} + +void QDesignerMenu::slotAdjustSizeNow() +{ + // Not using a single-shot, since we want to compress the timers if many items are being + // adjusted + m_adjustSizeTimer->stop(); + adjustSize(); +} + +bool QDesignerMenu::handleEvent(QWidget *widget, QEvent *event) +{ + if (event->type() == QEvent::FocusIn || event->type() == QEvent::FocusOut) { + update(); + + if (widget == m_editor) + return false; + } + + switch (event->type()) { + default: break; + + case QEvent::MouseButtonPress: + return handleMousePressEvent(widget, static_cast(event)); + case QEvent::MouseButtonRelease: + return handleMouseReleaseEvent(widget, static_cast(event)); + case QEvent::MouseButtonDblClick: + return handleMouseDoubleClickEvent(widget, static_cast(event)); + case QEvent::MouseMove: + return handleMouseMoveEvent(widget, static_cast(event)); + case QEvent::ContextMenu: + return handleContextMenuEvent(widget, static_cast(event)); + case QEvent::KeyPress: + return handleKeyPressEvent(widget, static_cast(event)); + } + + return true; +} + +void QDesignerMenu::startDrag(const QPoint &pos, Qt::KeyboardModifiers modifiers) +{ + const int index = findAction(pos); + if (index >= realActionCount()) + return; + + QAction *action = safeActionAt(index); + + QDesignerFormWindowInterface *fw = formWindow(); + const Qt::DropAction dropAction = (modifiers & Qt::ControlModifier) ? Qt::CopyAction : Qt::MoveAction; + if (dropAction == Qt::MoveAction) { + RemoveActionFromCommand *cmd = new RemoveActionFromCommand(fw); + cmd->init(this, action, actions().at(index + 1)); + fw->commandHistory()->push(cmd); + } + + QDrag *drag = new QDrag(this); + drag->setPixmap(ActionRepositoryMimeData::actionDragPixmap(action)); + drag->setMimeData(new ActionRepositoryMimeData(action, dropAction)); + + const int old_index = m_currentIndex; + m_currentIndex = -1; + + if (drag->start(dropAction) == Qt::IgnoreAction) { + if (dropAction == Qt::MoveAction) { + QAction *previous = safeActionAt(index); + InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw); + cmd->init(this, action, previous); + fw->commandHistory()->push(cmd); + } + + m_currentIndex = old_index; + } +} + +bool QDesignerMenu::handleKeyPressEvent(QWidget * /*widget*/, QKeyEvent *e) +{ + m_showSubMenuTimer->stop(); + + if (m_editor->isHidden() && hasFocus()) { // In navigation mode + switch (e->key()) { + + case Qt::Key_Delete: + if (m_currentIndex == -1 || m_currentIndex >= realActionCount()) + break; + hideSubMenu(); + deleteAction(); + break; + + case Qt::Key_Left: + e->accept(); + moveLeft(); + return true; + + case Qt::Key_Right: + e->accept(); + moveRight(); + return true; // no update + + case Qt::Key_Up: + e->accept(); + moveUp(e->modifiers() & Qt::ControlModifier); + return true; + + case Qt::Key_Down: + e->accept(); + moveDown(e->modifiers() & Qt::ControlModifier); + return true; + + case Qt::Key_PageUp: + m_currentIndex = 0; + break; + + case Qt::Key_PageDown: + m_currentIndex = actions().count() - 1; + break; + + case Qt::Key_Enter: + case Qt::Key_Return: + case Qt::Key_F2: + e->accept(); + enterEditMode(); + return true; // no update + + case Qt::Key_Escape: + e->ignore(); + setFocus(); + hide(); + closeMenuChain(); + return true; + + case Qt::Key_Alt: + case Qt::Key_Shift: + case Qt::Key_Control: + e->ignore(); + setFocus(); // FIXME: this is because some other widget get the focus when CTRL is pressed + return true; // no update + + default: { + QAction *action = currentAction(); + if (!action || action->isSeparator() || action == m_addSeparator) { + e->ignore(); + return true; + } else if (!e->text().isEmpty() && e->text().at(0).toLatin1() >= 32) { + showLineEdit(); + QApplication::sendEvent(m_editor, e); + e->accept(); + } else { + e->ignore(); + } + } + return true; + } + } else if (m_editor->hasFocus()) { // In edit mode + switch (e->key()) { + default: + e->ignore(); + return false; + + case Qt::Key_Enter: + case Qt::Key_Return: + if (!m_editor->text().isEmpty()) { + leaveEditMode(ForceAccept); + m_editor->hide(); + setFocus(); + moveDown(false); + break; + } + // fall through + + case Qt::Key_Escape: + m_editor->hide(); + setFocus(); + break; + } + } + + e->accept(); + update(); + + return true; +} + +static void sendMouseEventTo(QWidget *target, const QPoint &targetPoint, const QMouseEvent *event) +{ + QMouseEvent e(event->type(), targetPoint, event->globalPos(), event->button(), event->buttons(), event->modifiers()); + QApplication::sendEvent(target, &e); +} + +bool QDesignerMenu::handleMouseDoubleClickEvent(QWidget *, QMouseEvent *event) +{ + event->accept(); + m_startPosition = QPoint(); + + if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton) + return true; + + if (!rect().contains(event->pos())) { + // special case for menubar + QWidget *target = QApplication::widgetAt(event->globalPos()); + QMenuBar *mb = qobject_cast(target); + QDesignerMenu *menu = qobject_cast(target); + if (mb != 0 || menu != 0) { + const QPoint pt = target->mapFromGlobal(event->globalPos()); + QAction *action = mb == 0 ? menu->actionAt(pt) : mb->actionAt(pt); + if (action) + sendMouseEventTo(target, pt, event); + } + return true; + } + + m_currentIndex = findAction(event->pos()); + QAction *action = safeActionAt(m_currentIndex); + + QRect pm_rect; + if (action->menu() || hasSubMenuPixmap(action)) { + pm_rect = subMenuPixmapRect(action); + extendClickableArea(&pm_rect, layoutDirection()); + } + + if (!pm_rect.contains(event->pos()) && m_currentIndex != -1) + enterEditMode(); + + return true; +} + +bool QDesignerMenu::handleMousePressEvent(QWidget * /*widget*/, QMouseEvent *event) +{ + if (!rect().contains(event->pos())) { + QWidget *clickedWidget = QApplication::widgetAt(event->globalPos()); + if (QMenuBar *mb = qobject_cast(clickedWidget)) { + const QPoint pt = mb->mapFromGlobal(event->globalPos()); + if (QAction *action = mb->actionAt(pt)) { + QMenu * menu = action->menu(); + if (menu == findRootMenu()) { + // propagate the mouse press event (but don't close the popup) + sendMouseEventTo(mb, pt, event); + return true; + } + } + } + + if (QDesignerMenu *m = qobject_cast(clickedWidget)) { + m->hideSubMenu(); + sendMouseEventTo(m, m->mapFromGlobal(event->globalPos()), event); + } else { + QDesignerMenu *root = findRootMenu(); + root->hide(); + root->hideSubMenu(); + } + if (clickedWidget) { + if (QWidget *focusProxy = clickedWidget->focusProxy()) + clickedWidget = focusProxy; + if (clickedWidget->focusPolicy() != Qt::NoFocus) + clickedWidget->setFocus(Qt::OtherFocusReason); + } + return true; + } + + m_showSubMenuTimer->stop(); + m_startPosition = QPoint(); + event->accept(); + + if (event->button() != Qt::LeftButton) + return true; + + m_startPosition = mapFromGlobal(event->globalPos()); + + const int index = findAction(m_startPosition); + + QAction *action = safeActionAt(index); + QRect pm_rect = subMenuPixmapRect(action); + extendClickableArea(&pm_rect, layoutDirection()); + + const int old_index = m_currentIndex; + m_currentIndex = index; + if ((hasSubMenuPixmap(action) || action->menu() != 0) + && pm_rect.contains(m_startPosition)) { + if (m_currentIndex == m_lastSubMenuIndex) { + hideSubMenu(); + } else + slotShowSubMenuNow(); + } else { + if (index == old_index) { + if (m_currentIndex == m_lastSubMenuIndex) + hideSubMenu(); + } else { + hideSubMenu(); + } + } + + update(); + if (index != old_index) + selectCurrentAction(); + + return true; +} + +bool QDesignerMenu::handleMouseReleaseEvent(QWidget *, QMouseEvent *event) +{ + event->accept(); + m_startPosition = QPoint(); + + return true; +} + +bool QDesignerMenu::handleMouseMoveEvent(QWidget *, QMouseEvent *event) +{ + if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton) + return true; + + if (!rect().contains(event->pos())) { + + if (QMenuBar *mb = qobject_cast(QApplication::widgetAt(event->globalPos()))) { + const QPoint pt = mb->mapFromGlobal(event->globalPos()); + QAction *action = mb->actionAt(pt); + if (action && action->menu() == findRootMenu()) { + // propagate the mouse press event (but don't close the popup) + sendMouseEventTo(mb, pt, event); + return true; + } + // hide the popup Qt will replay the event + slotDeactivateNow(); + } + return true; + } + + if (m_startPosition.isNull()) + return true; + + event->accept(); + + const QPoint pos = mapFromGlobal(event->globalPos()); + + if ((pos - m_startPosition).manhattanLength() < qApp->startDragDistance()) + return true; + + startDrag(m_startPosition, event->modifiers()); + m_startPosition = QPoint(); + + return true; +} + +bool QDesignerMenu::handleContextMenuEvent(QWidget *, QContextMenuEvent *event) +{ + event->accept(); + + const int index = findAction(mapFromGlobal(event->globalPos())); + QAction *action = safeActionAt(index); + if (qobject_cast(action)) + return true; + + QMenu menu; + QVariant itemData; + itemData.setValue(action); + + QAction *addSeparatorAction = menu.addAction(tr("Insert separator")); + addSeparatorAction->setData(itemData); + + QAction *removeAction = 0; + if (action->isSeparator()) + removeAction = menu.addAction(tr("Remove separator")); + else + removeAction = menu.addAction(tr("Remove action '%1'").arg(action->objectName())); + removeAction->setData(itemData); + + connect(addSeparatorAction, SIGNAL(triggered(bool)), this, SLOT(slotAddSeparator())); + connect(removeAction, SIGNAL(triggered(bool)), this, SLOT(slotRemoveSelectedAction())); + menu.exec(event->globalPos()); + + return true; +} + +void QDesignerMenu::slotAddSeparator() +{ + QAction *action = qobject_cast(sender()); + if (!action) + return; + + QAction *a = qvariant_cast(action->data()); + Q_ASSERT(a != 0); + + const int pos = actions().indexOf(a); + QAction *action_before = 0; + if (pos != -1) + action_before = safeActionAt(pos); + + QDesignerFormWindowInterface *fw = formWindow(); + fw->beginCommand(tr("Add separator")); + QAction *sep = createAction(QString(), true); + + InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw); + cmd->init(this, sep, action_before); + fw->commandHistory()->push(cmd); + + if (parentMenu()) { + QAction *parent_action = parentMenu()->currentAction(); + if (parent_action->menu() == 0) { + CreateSubmenuCommand *cmd = new CreateSubmenuCommand(fw); + cmd->init(parentMenu(), parentMenu()->currentAction()); + fw->commandHistory()->push(cmd); + } + } + + fw->endCommand(); +} + +void QDesignerMenu::slotRemoveSelectedAction() +{ + if (QAction *action = qobject_cast(sender())) + if (QAction *a = qvariant_cast(action->data())) + deleteAction(a); +} + +void QDesignerMenu::deleteAction(QAction *a) +{ + const int pos = actions().indexOf(a); + QAction *action_before = 0; + if (pos != -1) + action_before = safeActionAt(pos + 1); + + QDesignerFormWindowInterface *fw = formWindow(); + RemoveActionFromCommand *cmd = new RemoveActionFromCommand(fw); + cmd->init(this, a, action_before); + fw->commandHistory()->push(cmd); +} + +QRect QDesignerMenu::subMenuPixmapRect(QAction *action) const +{ + const QRect g = actionGeometry(action); + const int x = layoutDirection() == Qt::LeftToRight ? (g.right() - m_subMenuPixmap.width() - 2) : 2; + const int y = g.top() + (g.height() - m_subMenuPixmap.height())/2 + 1; + return QRect(x, y, m_subMenuPixmap.width(), m_subMenuPixmap.height()); +} + +bool QDesignerMenu::hasSubMenuPixmap(QAction *action) const +{ + return action != 0 + && qobject_cast(action) == 0 + && !action->isSeparator() + && !action->menu() + && canCreateSubMenu(action); +} + +void QDesignerMenu::showEvent ( QShowEvent * event ) +{ + selectCurrentAction(); + QMenu::showEvent (event); +} + +void QDesignerMenu::paintEvent(QPaintEvent *event) +{ + QMenu::paintEvent(event); + + QPainter p(this); + + QAction *current = currentAction(); + + foreach (QAction *a, actions()) { + const QRect g = actionGeometry(a); + + if (qobject_cast(a)) { + QLinearGradient lg(g.left(), g.top(), g.left(), g.bottom()); + lg.setColorAt(0.0, Qt::transparent); + lg.setColorAt(0.7, QColor(0, 0, 0, 32)); + lg.setColorAt(1.0, Qt::transparent); + + p.fillRect(g, lg); + } else if (hasSubMenuPixmap(a)) { + p.drawPixmap(subMenuPixmapRect(a).topLeft(), m_subMenuPixmap); + } + } + + if (!hasFocus() || !current || m_dragging) + return; + + if (QDesignerMenu *menu = parentMenu()) { + if (menu->dragging()) + return; + } + + if (QDesignerMenuBar *menubar = qobject_cast(parentWidget())) { + if (menubar->dragging()) + return; + } + + const QRect g = actionGeometry(current); + drawSelection(&p, g.adjusted(1, 1, -3, -3)); +} + +bool QDesignerMenu::dragging() const +{ + return m_dragging; +} + +QDesignerMenu *QDesignerMenu::findRootMenu() const +{ + if (parentMenu()) + return parentMenu()->findRootMenu(); + + return const_cast(this); +} + +QDesignerMenu *QDesignerMenu::findActivatedMenu() const +{ + QList candidates; + candidates.append(const_cast(this)); + candidates += findChildren(); + + foreach (QDesignerMenu *m, candidates) { + if (m == qApp->activeWindow()) + return m; + } + + return 0; +} + +bool QDesignerMenu::eventFilter(QObject *object, QEvent *event) +{ + if (object != this && object != m_editor) { + return false; + } + + if (!m_editor->isHidden() && object == m_editor && event->type() == QEvent::FocusOut) { + leaveEditMode(Default); + m_editor->hide(); + update(); + return false; + } + + bool dispatch = true; + + switch (event->type()) { + default: break; + + case QEvent::WindowDeactivate: + deactivateMenu(); + break; + case QEvent::ContextMenu: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + + while (QApplication::activePopupWidget() && !qobject_cast(QApplication::activePopupWidget())) { + QApplication::activePopupWidget()->close(); + } + + // fall through + case QEvent::KeyPress: + case QEvent::KeyRelease: + case QEvent::MouseMove: + dispatch = (object != m_editor); + // no break + + case QEvent::Enter: + case QEvent::Leave: + case QEvent::FocusIn: + case QEvent::FocusOut: + if (dispatch) + if (QWidget *widget = qobject_cast(object)) + if (widget == this || isAncestorOf(widget)) + return handleEvent(widget, event); + break; + } + + return false; +}; + +int QDesignerMenu::findAction(const QPoint &pos) const +{ + const int index = actionIndexAt(this, pos, Qt::Vertical); + if (index == -1) + return realActionCount(); + + return index; +} + +void QDesignerMenu::adjustIndicator(const QPoint &pos) +{ + if (QDesignerActionProviderExtension *a = actionProvider()) { + a->adjustIndicator(pos); + } +} + +QDesignerMenu::ActionDragCheck QDesignerMenu::checkAction(QAction *action) const +{ + if (!action || (action->menu() && action->menu()->parentWidget() != const_cast(this))) + return NoActionDrag; // menu action!! nothing to do + + if (!Utils::isObjectAncestorOf(formWindow()->mainContainer(), action)) + return NoActionDrag; // the action belongs to another form window + + if (actions().contains(action)) + return ActionDragOnSubMenu; // we already have the action in the menu + + return AcceptActionDrag; +} + +void QDesignerMenu::dragEnterEvent(QDragEnterEvent *event) +{ + const ActionRepositoryMimeData *d = qobject_cast(event->mimeData()); + if (!d || d->actionList().empty()) { + event->ignore(); + return; + } + + QAction *action = d->actionList().first(); + + switch (checkAction(action)) { + case NoActionDrag: + event->ignore(); + break; + case ActionDragOnSubMenu: + d->accept(event); + m_dragging = true; + break; + case AcceptActionDrag: + d->accept(event); + m_dragging = true; + adjustIndicator(event->pos()); + break; + } +} + +void QDesignerMenu::dragMoveEvent(QDragMoveEvent *event) +{ + if (actionGeometry(m_addSeparator).contains(event->pos())) { + event->ignore(); + adjustIndicator(QPoint(-1, -1)); + return; + } + + const ActionRepositoryMimeData *d = qobject_cast(event->mimeData()); + if (!d || d->actionList().empty()) { + event->ignore(); + return; + } + + QAction *action = d->actionList().first(); + const ActionDragCheck dc = checkAction(action); + switch (dc) { + case NoActionDrag: + event->ignore(); + break; + case ActionDragOnSubMenu: + case AcceptActionDrag: { // Do not pop up submenu of action being dragged + const int newIndex = findAction(event->pos()); + if (safeActionAt(newIndex) != action) { + m_currentIndex = newIndex; + if (m_lastSubMenuIndex != m_currentIndex) + m_showSubMenuTimer->start(300); + } + if (dc == AcceptActionDrag) { + adjustIndicator(event->pos()); + d->accept(event); + } else { + event->ignore(); + } + } + break; + } +} + +void QDesignerMenu::dragLeaveEvent(QDragLeaveEvent *) +{ + m_dragging = false; + adjustIndicator(QPoint(-1, -1)); + m_showSubMenuTimer->stop(); +} + +void QDesignerMenu::dropEvent(QDropEvent *event) +{ + m_showSubMenuTimer->stop(); + hideSubMenu(); + m_dragging = false; + + QDesignerFormWindowInterface *fw = formWindow(); + const ActionRepositoryMimeData *d = qobject_cast(event->mimeData()); + if (!d || d->actionList().empty()) { + event->ignore(); + return; + } + QAction *action = d->actionList().first(); + if (action && checkAction(action) == AcceptActionDrag) { + event->acceptProposedAction(); + int index = findAction(event->pos()); + index = qMin(index, actions().count() - 1); + + fw->beginCommand(tr("Insert action")); + InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw); + cmd->init(this, action, safeActionAt(index)); + fw->commandHistory()->push(cmd); + + m_currentIndex = index; + + if (parentMenu()) { + QAction *parent_action = parentMenu()->currentAction(); + if (parent_action->menu() == 0) { + CreateSubmenuCommand *cmd = new CreateSubmenuCommand(fw); + cmd->init(parentMenu(), parentMenu()->currentAction(), action); + fw->commandHistory()->push(cmd); + } + } + update(); + fw->endCommand(); + } else { + event->ignore(); + } + adjustIndicator(QPoint(-1, -1)); +} + +void QDesignerMenu::actionEvent(QActionEvent *event) +{ + QMenu::actionEvent(event); + m_adjustSizeTimer->start(0); +} + +QDesignerFormWindowInterface *QDesignerMenu::formWindow() const +{ + if (parentMenu()) + return parentMenu()->formWindow(); + + return QDesignerFormWindowInterface::findFormWindow(parentWidget()); +} + +QDesignerActionProviderExtension *QDesignerMenu::actionProvider() +{ + if (QDesignerFormWindowInterface *fw = formWindow()) { + QDesignerFormEditorInterface *core = fw->core(); + return qt_extension(core->extensionManager(), this); + } + + return 0; +} + +void QDesignerMenu::closeMenuChain() +{ + m_showSubMenuTimer->stop(); + + QWidget *w = this; + while (w && qobject_cast(w)) + w = w->parentWidget(); + + if (w) { + foreach (QMenu *subMenu, w->findChildren()) { + subMenu->hide(); + } + } + + m_lastSubMenuIndex = -1; +} + +// Close submenu using the left/right keys according to layoutDirection(). +// Return false to indicate the event must be propagated to the menu bar. +bool QDesignerMenu::hideSubMenuOnCursorKey() +{ + if (parentMenu()) { + hide(); + return true; + } + closeMenuChain(); + update(); + if (parentMenuBar()) + return false; + return true; +} + +// Open a submenu using the left/right keys according to layoutDirection(). +// Return false to indicate the event must be propagated to the menu bar. +bool QDesignerMenu::showSubMenuOnCursorKey() +{ + const QAction *action = currentAction(); + + if (qobject_cast(action) || action->isSeparator()) { + closeMenuChain(); + if (parentMenuBar()) + return false; + return true; + } + m_lastSubMenuIndex = -1; // force a refresh + slotShowSubMenuNow(); + return true; +} + +void QDesignerMenu::moveLeft() +{ + const bool handled = layoutDirection() == Qt::LeftToRight ? + hideSubMenuOnCursorKey() : showSubMenuOnCursorKey(); + if (!handled) + parentMenuBar()->moveLeft(); +} + +void QDesignerMenu::moveRight() +{ + const bool handled = layoutDirection() == Qt::LeftToRight ? + showSubMenuOnCursorKey() : hideSubMenuOnCursorKey(); + if (!handled) + parentMenuBar()->moveRight(); +} + +void QDesignerMenu::moveUp(bool ctrl) +{ + if (m_currentIndex == 0) { + hide(); + return; + } + + if (ctrl) + (void) swap(m_currentIndex, m_currentIndex - 1); + --m_currentIndex; + m_currentIndex = qMax(0, m_currentIndex); + // Always re-select, swapping destroys order + update(); + selectCurrentAction(); +} + +void QDesignerMenu::moveDown(bool ctrl) +{ + if (m_currentIndex == actions().count() - 1) { + return; + } + + if (ctrl) + (void) swap(m_currentIndex + 1, m_currentIndex); + + ++m_currentIndex; + m_currentIndex = qMin(actions().count() - 1, m_currentIndex); + update(); + if (!ctrl) + selectCurrentAction(); +} + +QAction *QDesignerMenu::currentAction() const +{ + if (m_currentIndex < 0 || m_currentIndex >= actions().count()) + return 0; + + return safeActionAt(m_currentIndex); +} + +int QDesignerMenu::realActionCount() const +{ + return actions().count() - 2; // 2 fake actions +} + +void QDesignerMenu::selectCurrentAction() +{ + QAction *action = currentAction(); + if (!action || action == m_addSeparator || action == m_addItem) + return; + + QDesignerObjectInspector *oi = 0; + if (QDesignerFormWindowInterface *fw = formWindow()) + oi = qobject_cast(fw->core()->objectInspector()); + + if (!oi) + return; + + oi->clearSelection(); + if (QMenu *menu = action->menu()) + oi->selectObject(menu); + else + oi->selectObject(action); +} + +void QDesignerMenu::createRealMenuAction(QAction *action) +{ + if (action->menu()) + return; // nothing to do + + QDesignerFormWindowInterface *fw = formWindow(); + QDesignerFormEditorInterface *core = formWindow()->core(); + + QDesignerMenu *menu = findOrCreateSubMenu(action); + m_subMenus.remove(action); + + action->setMenu(menu); + menu->setTitle(action->text()); + + Q_ASSERT(fw); + + core->widgetFactory()->initialize(menu); + + const QString niceObjectName = ActionEditor::actionTextToName(menu->title(), QLatin1String("menu")); + menu->setObjectName(niceObjectName); + + core->metaDataBase()->add(menu); + fw->ensureUniqueObjectName(menu); + + QAction *menuAction = menu->menuAction(); + core->metaDataBase()->add(menuAction); +} + +void QDesignerMenu::removeRealMenu(QAction *action) +{ + QDesignerMenu *menu = qobject_cast(action->menu()); + if (menu == 0) + return; + action->setMenu(0); + m_subMenus.insert(action, menu); + QDesignerFormEditorInterface *core = formWindow()->core(); + core->metaDataBase()->remove(menu); +} + +QDesignerMenu *QDesignerMenu::findOrCreateSubMenu(QAction *action) +{ + if (action->menu()) + return qobject_cast(action->menu()); + + QDesignerMenu *menu = m_subMenus.value(action); + if (!menu) { + menu = new QDesignerMenu(this); + m_subMenus.insert(action, menu); + } + + return menu; +} + +bool QDesignerMenu::canCreateSubMenu(QAction *action) const // ### improve it's a bit too slow +{ + foreach (const QWidget *aw, action->associatedWidgets()) + if (aw != this) { + if (const QMenu *m = qobject_cast(aw)) { + if (m->actions().contains(action)) + return false; // sorry + } else { + if (const QToolBar *tb = qobject_cast(aw)) + if (tb->actions().contains(action)) + return false; // sorry + } + } + return true; +} + +void QDesignerMenu::slotShowSubMenuNow() +{ + m_showSubMenuTimer->stop(); + + if (m_lastSubMenuIndex == m_currentIndex) + return; + + if (m_lastSubMenuIndex != -1) + hideSubMenu(); + + if (m_currentIndex >= realActionCount()) + return; + + QAction *action = currentAction(); + + if (action->isSeparator() || !canCreateSubMenu(action)) + return; + + if (QMenu *menu = findOrCreateSubMenu(action)) { + if (!menu->isVisible()) { + if ((menu->windowFlags() & Qt::Popup) != Qt::Popup) + menu->setWindowFlags(Qt::Popup); + const QRect g = actionGeometry(action); + if (layoutDirection() == Qt::LeftToRight) { + menu->move(mapToGlobal(g.topRight())); + } else { + // The position is not initially correct due to the unknown width, + // causing it to overlap a bit the first time it is invoked. + const QSize menuSize = menu->size(); + QPoint point = g.topLeft() - QPoint(menu->width() + 10, 0); + menu->move(mapToGlobal(point)); + } + menu->show(); + menu->setFocus(); + } else { + menu->raise(); + } + menu->setFocus(); + + m_lastSubMenuIndex = m_currentIndex; + } +} + +void QDesignerMenu::showSubMenu(QAction *action) +{ + m_showSubMenuTimer->stop(); + + if (m_editor->isVisible() || !action || qobject_cast(action) + || action->isSeparator() || !isVisible()) + return; + + m_showSubMenuTimer->start(300); +} + +QDesignerMenu *QDesignerMenu::parentMenu() const +{ + return qobject_cast(parentWidget()); +} + +QDesignerMenuBar *QDesignerMenu::parentMenuBar() const +{ + if (QDesignerMenuBar *mb = qobject_cast(parentWidget())) { + return mb; + } else if (QDesignerMenu *m = parentMenu()) { + return m->parentMenuBar(); + } + + return 0; +} + +void QDesignerMenu::setVisible(bool visible) +{ + if (visible) + m_currentIndex = 0; + else + m_lastSubMenuIndex = -1; + + QMenu::setVisible(visible); + +} + +void QDesignerMenu::adjustSpecialActions() +{ + removeAction(m_addItem); + removeAction(m_addSeparator); + addAction(m_addItem); + addAction(m_addSeparator); +} + +bool QDesignerMenu::interactive(bool i) +{ + const bool old = m_interactive; + m_interactive = i; + return old; +} + +void QDesignerMenu::enterEditMode() +{ + if (m_currentIndex >= 0 && m_currentIndex <= realActionCount()) { + showLineEdit(); + } else { + hideSubMenu(); + QDesignerFormWindowInterface *fw = formWindow(); + fw->beginCommand(tr("Add separator")); + QAction *sep = createAction(QString(), true); + + InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw); + cmd->init(this, sep, safeActionAt(realActionCount())); + fw->commandHistory()->push(cmd); + + if (parentMenu()) { + QAction *parent_action = parentMenu()->currentAction(); + if (parent_action->menu() == 0) { + CreateSubmenuCommand *cmd = new CreateSubmenuCommand(fw); + cmd->init(parentMenu(), parentMenu()->currentAction()); + fw->commandHistory()->push(cmd); + } + } + + fw->endCommand(); + + m_currentIndex = actions().indexOf(m_addItem); + update(); + } +} + +void QDesignerMenu::leaveEditMode(LeaveEditMode mode) +{ + if (mode == Default) + return; + + QAction *action = 0; + + QDesignerFormWindowInterface *fw = formWindow(); + if (m_currentIndex < realActionCount()) { + action = safeActionAt(m_currentIndex); + fw->beginCommand(QApplication::translate("Command", "Set action text")); + } else { + Q_ASSERT(fw != 0); + fw->beginCommand(QApplication::translate("Command", "Insert action")); + action = createAction(ActionEditor::actionTextToName(m_editor->text())); + InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw); + cmd->init(this, action, currentAction()); + fw->commandHistory()->push(cmd); + } + + SetPropertyCommand *cmd = new SetPropertyCommand(fw); + cmd->init(action, QLatin1String("text"), m_editor->text()); + fw->commandHistory()->push(cmd); + + if (parentMenu()) { + QAction *parent_action = parentMenu()->currentAction(); + if (parent_action->menu() == 0) { + CreateSubmenuCommand *cmd = new CreateSubmenuCommand(fw); + cmd->init(parentMenu(), parentMenu()->currentAction(), action); + fw->commandHistory()->push(cmd); + } + } + + update(); + fw->endCommand(); +} + +QAction *QDesignerMenu::safeMenuAction(QDesignerMenu *menu) const +{ + QAction *action = menu->menuAction(); + + if (!action) + action = m_subMenus.key(menu); + + return action; +} + +void QDesignerMenu::showLineEdit() +{ + m_showSubMenuTimer->stop(); + + QAction *action = 0; + + if (m_currentIndex < realActionCount()) + action = safeActionAt(m_currentIndex); + else + action = m_addItem; + + if (action->isSeparator()) + return; + + hideSubMenu(); + + // open edit field for item name + setFocus(); + + const QString text = action != m_addItem ? action->text() : QString(); + m_editor->setText(text); + m_editor->selectAll(); + m_editor->setGeometry(actionGeometry(action).adjusted(1, 1, -2, -2)); + m_editor->show(); + m_editor->setFocus(); +} + +QAction *QDesignerMenu::createAction(const QString &objectName, bool separator) +{ + QDesignerFormWindowInterface *fw = formWindow(); + Q_ASSERT(fw); + return ToolBarEventFilter::createAction(fw, objectName, separator); +} + +// ### share with QDesignerMenu::swap +bool QDesignerMenu::swap(int a, int b) +{ + const int left = qMin(a, b); + int right = qMax(a, b); + + QAction *action_a = safeActionAt(left); + QAction *action_b = safeActionAt(right); + + if (action_a == action_b + || !action_a + || !action_b + || qobject_cast(action_a) + || qobject_cast(action_b)) + return false; // nothing to do + + right = qMin(right, realActionCount()); + if (right < 0) + return false; // nothing to do + + QDesignerFormWindowInterface *fw = formWindow(); + fw->beginCommand(QApplication::translate("Command", "Move action")); + + QAction *action_b_before = safeActionAt(right + 1); + + RemoveActionFromCommand *cmd1 = new RemoveActionFromCommand(fw); + cmd1->init(this, action_b, action_b_before, false); + fw->commandHistory()->push(cmd1); + + QAction *action_a_before = safeActionAt(left + 1); + + InsertActionIntoCommand *cmd2 = new InsertActionIntoCommand(fw); + cmd2->init(this, action_b, action_a_before, false); + fw->commandHistory()->push(cmd2); + + RemoveActionFromCommand *cmd3 = new RemoveActionFromCommand(fw); + cmd3->init(this, action_a, action_b, false); + fw->commandHistory()->push(cmd3); + + InsertActionIntoCommand *cmd4 = new InsertActionIntoCommand(fw); + cmd4->init(this, action_a, action_b_before, true); + fw->commandHistory()->push(cmd4); + + fw->endCommand(); + + return true; +} + +QAction *QDesignerMenu::safeActionAt(int index) const +{ + if (index < 0 || index >= actions().count()) + return 0; + + return actions().at(index); +} + +void QDesignerMenu::hideSubMenu() +{ + m_lastSubMenuIndex = -1; + foreach (QMenu *subMenu, findChildren()) { + subMenu->hide(); + } +} + +void QDesignerMenu::deleteAction() +{ + QAction *action = currentAction(); + const int pos = actions().indexOf(action); + QAction *action_before = 0; + if (pos != -1) + action_before = safeActionAt(pos + 1); + + QDesignerFormWindowInterface *fw = formWindow(); + RemoveActionFromCommand *cmd = new RemoveActionFromCommand(fw); + cmd->init(this, action, action_before); + fw->commandHistory()->push(cmd); + + update(); +} + +void QDesignerMenu::deactivateMenu() +{ + m_deactivateWindowTimer->start(10); +} + +void QDesignerMenu::slotDeactivateNow() +{ + m_deactivateWindowTimer->stop(); + + if (m_dragging) + return; + + QDesignerMenu *root = findRootMenu(); + + if (! root->findActivatedMenu()) { + root->hide(); + root->hideSubMenu(); + } +} + +void QDesignerMenu::drawSelection(QPainter *p, const QRect &r) +{ + p->save(); + + QColor c = Qt::blue; + p->setPen(QPen(c, 1)); + c.setAlpha(32); + p->setBrush(c); + p->drawRect(r); + + p->restore(); +} + +void QDesignerMenu::keyPressEvent(QKeyEvent *event) +{ + event->ignore(); +} + +void QDesignerMenu::keyReleaseEvent(QKeyEvent *event) +{ + event->ignore(); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_menu_p.h b/src/designer/src/lib/shared/qdesigner_menu_p.h new file mode 100644 index 000000000..b88af7aac --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_menu_p.h @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_MENU_H +#define QDESIGNER_MENU_H + +#include "shared_global_p.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QTimer; +class QLineEdit; + +class QDesignerFormWindowInterface; +class QDesignerActionProviderExtension; +class QDesignerMenu; +class QDesignerMenuBar; +class QPainter; +class QMimeData; + +namespace qdesigner_internal { + class CreateSubmenuCommand; + class ActionInsertionCommand; +} + +class QDESIGNER_SHARED_EXPORT QDesignerMenu: public QMenu +{ + Q_OBJECT +public: + QDesignerMenu(QWidget *parent = 0); + virtual ~QDesignerMenu(); + + bool eventFilter(QObject *object, QEvent *event); + + QDesignerFormWindowInterface *formWindow() const; + QDesignerActionProviderExtension *actionProvider(); + + QDesignerMenu *parentMenu() const; + QDesignerMenuBar *parentMenuBar() const; + + virtual void setVisible(bool visible); + + void adjustSpecialActions(); + + bool interactive(bool i); + void createRealMenuAction(QAction *action); + void removeRealMenu(QAction *action); + + static void drawSelection(QPainter *p, const QRect &r); + + bool dragging() const; + + void closeMenuChain(); + + void moveLeft(); + void moveRight(); + void moveUp(bool ctrl); + void moveDown(bool ctrl); + + // Helper for MenuTaskMenu extension + void deleteAction(QAction *a); + +private slots: + void slotAddSeparator(); + void slotRemoveSelectedAction(); + void slotShowSubMenuNow(); + void slotDeactivateNow(); + void slotAdjustSizeNow(); + +protected: + virtual void actionEvent(QActionEvent *event); + virtual void dragEnterEvent(QDragEnterEvent *event); + virtual void dragMoveEvent(QDragMoveEvent *event); + virtual void dragLeaveEvent(QDragLeaveEvent *event); + virtual void dropEvent(QDropEvent *event); + virtual void paintEvent(QPaintEvent *event); + virtual void keyPressEvent(QKeyEvent *event); + virtual void keyReleaseEvent(QKeyEvent *event); + virtual void showEvent(QShowEvent *event); + + bool handleEvent(QWidget *widget, QEvent *event); + bool handleMouseDoubleClickEvent(QWidget *widget, QMouseEvent *event); + bool handleMousePressEvent(QWidget *widget, QMouseEvent *event); + bool handleMouseReleaseEvent(QWidget *widget, QMouseEvent *event); + bool handleMouseMoveEvent(QWidget *widget, QMouseEvent *event); + bool handleContextMenuEvent(QWidget *widget, QContextMenuEvent *event); + bool handleKeyPressEvent(QWidget *widget, QKeyEvent *event); + + void startDrag(const QPoint &pos, Qt::KeyboardModifiers modifiers); + + void adjustIndicator(const QPoint &pos); + int findAction(const QPoint &pos) const; + + QAction *currentAction() const; + int realActionCount() const; + enum ActionDragCheck { NoActionDrag, ActionDragOnSubMenu, AcceptActionDrag }; + ActionDragCheck checkAction(QAction *action) const; + + void showSubMenu(QAction *action); + + enum LeaveEditMode { + Default = 0, + ForceAccept + }; + + void enterEditMode(); + void leaveEditMode(LeaveEditMode mode); + void showLineEdit(); + + QAction *createAction(const QString &text, bool separator = false); + QDesignerMenu *findOrCreateSubMenu(QAction *action); + + QAction *safeActionAt(int index) const; + QAction *safeMenuAction(QDesignerMenu *menu) const; + bool swap(int a, int b); + + void hideSubMenu(); + void deleteAction(); + void deactivateMenu(); + + bool canCreateSubMenu(QAction *action) const; + QDesignerMenu *findRootMenu() const; + QDesignerMenu *findActivatedMenu() const; + + QRect subMenuPixmapRect(QAction *action) const; + bool hasSubMenuPixmap(QAction *action) const; + + void selectCurrentAction(); + +private: + bool hideSubMenuOnCursorKey(); + bool showSubMenuOnCursorKey(); + const QPixmap m_subMenuPixmap; + + QPoint m_startPosition; + int m_currentIndex; + QAction *m_addItem; + QAction *m_addSeparator; + QHash m_subMenus; + QTimer *m_showSubMenuTimer; + QTimer *m_deactivateWindowTimer; + QTimer *m_adjustSizeTimer; + bool m_interactive; + QLineEdit *m_editor; + bool m_dragging; + int m_lastSubMenuIndex; + + friend class qdesigner_internal::CreateSubmenuCommand; + friend class qdesigner_internal::ActionInsertionCommand; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_MENU_H diff --git a/src/designer/src/lib/shared/qdesigner_menubar.cpp b/src/designer/src/lib/shared/qdesigner_menubar.cpp new file mode 100644 index 000000000..534cf0cda --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_menubar.cpp @@ -0,0 +1,979 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_menubar_p.h" +#include "qdesigner_menu_p.h" +#include "qdesigner_command_p.h" +#include "qdesigner_propertycommand_p.h" +#include "actionrepository_p.h" +#include "actionprovider_p.h" +#include "actioneditor_p.h" +#include "qdesigner_utils_p.h" +#include "promotiontaskmenu_p.h" +#include "qdesigner_objectinspector_p.h" + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include + +Q_DECLARE_METATYPE(QAction*) + +QT_BEGIN_NAMESPACE + +typedef QList ActionList; + +using namespace qdesigner_internal; + +namespace qdesigner_internal +{ + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +SpecialMenuAction::SpecialMenuAction(QObject *parent) + : QAction(parent) +{ +} + +SpecialMenuAction::~SpecialMenuAction() +{ +} + + +} // namespace qdesigner_internal + + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +QDesignerMenuBar::QDesignerMenuBar(QWidget *parent) : + QMenuBar(parent), + m_addMenu(new SpecialMenuAction(this)), + m_currentIndex(0), + m_interactive(true), + m_editor(new QLineEdit(this)), + m_dragging(false), + m_lastMenuActionIndex( -1), + m_promotionTaskMenu(new PromotionTaskMenu(this, PromotionTaskMenu::ModeSingleWidget, this)) +{ + setContextMenuPolicy(Qt::DefaultContextMenu); + + setAcceptDrops(true); // ### fake + // Fake property: Keep the menu bar editable in the form even if a native menu bar is used. + setNativeMenuBar(false); + + m_addMenu->setText(tr("Type Here")); + addAction(m_addMenu); + + QFont italic; + italic.setItalic(true); + m_addMenu->setFont(italic); + + m_editor->setObjectName(QLatin1String("__qt__passive_editor")); + m_editor->hide(); + m_editor->installEventFilter(this); + installEventFilter(this); +} + +QDesignerMenuBar::~QDesignerMenuBar() +{ +} + +void QDesignerMenuBar::paintEvent(QPaintEvent *event) +{ + QMenuBar::paintEvent(event); + + QPainter p(this); + + foreach (QAction *a, actions()) { + if (qobject_cast(a)) { + const QRect g = actionGeometry(a); + QLinearGradient lg(g.left(), g.top(), g.left(), g.bottom()); + lg.setColorAt(0.0, Qt::transparent); + lg.setColorAt(0.7, QColor(0, 0, 0, 32)); + lg.setColorAt(1.0, Qt::transparent); + + p.fillRect(g, lg); + } + } + + QAction *action = currentAction(); + + if (m_dragging || !action) + return; + + if (hasFocus()) { + const QRect g = actionGeometry(action); + QDesignerMenu::drawSelection(&p, g.adjusted(1, 1, -1, -1)); + } else if (action->menu() && action->menu()->isVisible()) { + const QRect g = actionGeometry(action); + p.drawRect(g.adjusted(1, 1, -1, -1)); + } +} + +bool QDesignerMenuBar::handleEvent(QWidget *widget, QEvent *event) +{ + if (!formWindow()) + return false; + + if (event->type() == QEvent::FocusIn || event->type() == QEvent::FocusOut) + update(); + + switch (event->type()) { + default: break; + + case QEvent::MouseButtonDblClick: + return handleMouseDoubleClickEvent(widget, static_cast(event)); + case QEvent::MouseButtonPress: + return handleMousePressEvent(widget, static_cast(event)); + case QEvent::MouseButtonRelease: + return handleMouseReleaseEvent(widget, static_cast(event)); + case QEvent::MouseMove: + return handleMouseMoveEvent(widget, static_cast(event)); + case QEvent::ContextMenu: + return handleContextMenuEvent(widget, static_cast(event)); + case QEvent::KeyPress: + return handleKeyPressEvent(widget, static_cast(event)); + case QEvent::FocusIn: + case QEvent::FocusOut: + return widget != m_editor; + } + + return true; +} + +bool QDesignerMenuBar::handleMouseDoubleClickEvent(QWidget *, QMouseEvent *event) +{ + if (!rect().contains(event->pos())) + return true; + + if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton) + return true; + + event->accept(); + + m_startPosition = QPoint(); + + m_currentIndex = actionIndexAt(this, event->pos(), Qt::Horizontal); + if (m_currentIndex != -1) { + showLineEdit(); + } + + return true; +} + +bool QDesignerMenuBar::handleKeyPressEvent(QWidget *, QKeyEvent *e) +{ + if (m_editor->isHidden()) { // In navigation mode + switch (e->key()) { + + case Qt::Key_Delete: + if (m_currentIndex == -1 || m_currentIndex >= realActionCount()) + break; + hideMenu(); + deleteMenu(); + break; + + case Qt::Key_Left: + e->accept(); + moveLeft(e->modifiers() & Qt::ControlModifier); + return true; + + case Qt::Key_Right: + e->accept(); + moveRight(e->modifiers() & Qt::ControlModifier); + return true; // no update + + case Qt::Key_Up: + e->accept(); + moveUp(); + return true; + + case Qt::Key_Down: + e->accept(); + moveDown(); + return true; + + case Qt::Key_PageUp: + m_currentIndex = 0; + break; + + case Qt::Key_PageDown: + m_currentIndex = actions().count() - 1; + break; + + case Qt::Key_Enter: + case Qt::Key_Return: + e->accept(); + enterEditMode(); + return true; // no update + + case Qt::Key_Alt: + case Qt::Key_Shift: + case Qt::Key_Control: + case Qt::Key_Escape: + e->ignore(); + setFocus(); // FIXME: this is because some other widget get the focus when CTRL is pressed + return true; // no update + + default: + if (!e->text().isEmpty() && e->text().at(0).toLatin1() >= 32) { + showLineEdit(); + QApplication::sendEvent(m_editor, e); + e->accept(); + } else { + e->ignore(); + } + return true; + } + } else { // In edit mode + switch (e->key()) { + default: + return false; + + case Qt::Key_Control: + e->ignore(); + return true; + + case Qt::Key_Enter: + case Qt::Key_Return: + if (!m_editor->text().isEmpty()) { + leaveEditMode(ForceAccept); + if (m_lastFocusWidget) + m_lastFocusWidget->setFocus(); + + m_editor->hide(); + showMenu(); + break; + } + // fall through + + case Qt::Key_Escape: + update(); + setFocus(); + break; + } + } + + e->accept(); + update(); + + return true; +} + +void QDesignerMenuBar::startDrag(const QPoint &pos) +{ + const int index = findAction(pos); + if (m_currentIndex == -1 || index >= realActionCount()) + return; + + QAction *action = safeActionAt(index); + + QDesignerFormWindowInterface *fw = formWindow(); + RemoveActionFromCommand *cmd = new RemoveActionFromCommand(fw); + cmd->init(this, action, actions().at(index + 1)); + fw->commandHistory()->push(cmd); + + adjustSize(); + + hideMenu(index); + + QDrag *drag = new QDrag(this); + drag->setPixmap(ActionRepositoryMimeData::actionDragPixmap(action)); + drag->setMimeData(new ActionRepositoryMimeData(action, Qt::MoveAction)); + + const int old_index = m_currentIndex; + m_currentIndex = -1; + + if (drag->start(Qt::MoveAction) == Qt::IgnoreAction) { + InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw); + cmd->init(this, action, safeActionAt(index)); + fw->commandHistory()->push(cmd); + + m_currentIndex = old_index; + adjustSize(); + } +} + +bool QDesignerMenuBar::handleMousePressEvent(QWidget *, QMouseEvent *event) +{ + m_startPosition = QPoint(); + event->accept(); + + if (event->button() != Qt::LeftButton) + return true; + + m_startPosition = event->pos(); + const int newIndex = actionIndexAt(this, m_startPosition, Qt::Horizontal); + const bool changed = newIndex != m_currentIndex; + m_currentIndex = newIndex; + updateCurrentAction(changed); + + return true; +} + +bool QDesignerMenuBar::handleMouseReleaseEvent(QWidget *, QMouseEvent *event) +{ + m_startPosition = QPoint(); + + if (event->button() != Qt::LeftButton) + return true; + + event->accept(); + m_currentIndex = actionIndexAt(this, event->pos(), Qt::Horizontal); + if (!m_editor->isVisible() && m_currentIndex != -1 && m_currentIndex < realActionCount()) + showMenu(); + + return true; +} + +bool QDesignerMenuBar::handleMouseMoveEvent(QWidget *, QMouseEvent *event) +{ + if ((event->buttons() & Qt::LeftButton) != Qt::LeftButton) + return true; + + if (m_startPosition.isNull()) + return true; + + const QPoint pos = mapFromGlobal(event->globalPos()); + + if ((pos - m_startPosition).manhattanLength() < qApp->startDragDistance()) + return true; + + const int index = actionIndexAt(this, m_startPosition, Qt::Horizontal); + if (index < actions().count()) { + hideMenu(index); + update(); + } + + startDrag(m_startPosition); + m_startPosition = QPoint(); + + return true; +} + +ActionList QDesignerMenuBar::contextMenuActions() +{ + ActionList rc; + if (QAction *action = safeActionAt(m_currentIndex)) { + if (!qobject_cast(action)) { + QVariant itemData; + itemData.setValue(action); + + QAction *remove_action = new QAction(tr("Remove Menu '%1'").arg(action->menu()->objectName()), 0); + remove_action->setData(itemData); + connect(remove_action, SIGNAL(triggered()), this, SLOT(deleteMenu())); + rc.push_back(remove_action); + QAction *sep = new QAction(0); + sep->setSeparator(true); + rc.push_back(sep); + } + } + + m_promotionTaskMenu->addActions(formWindow(), PromotionTaskMenu::TrailingSeparator, rc); + + QAction *remove_menubar = new QAction(tr("Remove Menu Bar"), 0); + connect(remove_menubar, SIGNAL(triggered()), this, SLOT(slotRemoveMenuBar())); + rc.push_back(remove_menubar); + return rc; +} + +bool QDesignerMenuBar::handleContextMenuEvent(QWidget *, QContextMenuEvent *event) +{ + event->accept(); + + m_currentIndex = actionIndexAt(this, mapFromGlobal(event->globalPos()), Qt::Horizontal); + + update(); + + QMenu menu; + const ActionList al = contextMenuActions(); + const ActionList::const_iterator acend = al.constEnd(); + for (ActionList::const_iterator it = al.constBegin(); it != acend; ++it) + menu.addAction(*it); + menu.exec(event->globalPos()); + return true; +} + +void QDesignerMenuBar::slotRemoveMenuBar() +{ + Q_ASSERT(formWindow() != 0); + + QDesignerFormWindowInterface *fw = formWindow(); + + DeleteMenuBarCommand *cmd = new DeleteMenuBarCommand(fw); + cmd->init(this); + fw->commandHistory()->push(cmd); +} + +void QDesignerMenuBar::focusOutEvent(QFocusEvent *event) +{ + QMenuBar::focusOutEvent(event); +} + +void QDesignerMenuBar::enterEditMode() +{ + if (m_currentIndex >= 0 && m_currentIndex <= realActionCount()) { + showLineEdit(); + } +} + +void QDesignerMenuBar::leaveEditMode(LeaveEditMode mode) +{ + m_editor->releaseKeyboard(); + + if (mode == Default) + return; + + if (m_editor->text().isEmpty()) + return; + + QAction *action = 0; + + QDesignerFormWindowInterface *fw = formWindow(); + Q_ASSERT(fw); + + if (m_currentIndex >= 0 && m_currentIndex < realActionCount()) { + action = safeActionAt(m_currentIndex); + fw->beginCommand(QApplication::translate("Command", "Change Title")); + } else { + fw->beginCommand(QApplication::translate("Command", "Insert Menu")); + const QString niceObjectName = ActionEditor::actionTextToName(m_editor->text(), QLatin1String("menu")); + QMenu *menu = qobject_cast(fw->core()->widgetFactory()->createWidget(QLatin1String("QMenu"), this)); + fw->core()->widgetFactory()->initialize(menu); + menu->setObjectName(niceObjectName); + menu->setTitle(tr("Menu")); + fw->ensureUniqueObjectName(menu); + action = menu->menuAction(); + AddMenuActionCommand *cmd = new AddMenuActionCommand(fw); + cmd->init(action, m_addMenu, this, this); + fw->commandHistory()->push(cmd); + } + + SetPropertyCommand *cmd = new SetPropertyCommand(fw); + cmd->init(action, QLatin1String("text"), m_editor->text()); + fw->commandHistory()->push(cmd); + fw->endCommand(); +} + +void QDesignerMenuBar::showLineEdit() +{ + QAction *action = 0; + + if (m_currentIndex >= 0 && m_currentIndex < realActionCount()) + action = safeActionAt(m_currentIndex); + else + action = m_addMenu; + + if (action->isSeparator()) + return; + + // hideMenu(); + + m_lastFocusWidget = qApp->focusWidget(); + + // open edit field for item name + const QString text = action != m_addMenu ? action->text() : QString(); + + m_editor->setText(text); + m_editor->selectAll(); + m_editor->setGeometry(actionGeometry(action)); + m_editor->show(); + qApp->setActiveWindow(m_editor); + m_editor->setFocus(); + m_editor->grabKeyboard(); +} + +bool QDesignerMenuBar::eventFilter(QObject *object, QEvent *event) +{ + if (object != this && object != m_editor) + return false; + + if (!m_editor->isHidden() && object == m_editor && event->type() == QEvent::FocusOut) { + leaveEditMode(Default); + m_editor->hide(); + update(); + return true; + } + + bool dispatch = true; + + switch (event->type()) { + default: break; + + case QEvent::KeyPress: + case QEvent::KeyRelease: + case QEvent::ContextMenu: + case QEvent::MouseMove: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + dispatch = (object != m_editor); + // no break + + case QEvent::Enter: + case QEvent::Leave: + case QEvent::FocusIn: + case QEvent::FocusOut: + { + QWidget *widget = qobject_cast(object); + + if (dispatch && widget && (widget == this || isAncestorOf(widget))) + return handleEvent(widget, event); + } break; + + case QEvent::Shortcut: + event->accept(); + return true; + } + + return false; +}; + +int QDesignerMenuBar::findAction(const QPoint &pos) const +{ + const int index = actionIndexAt(this, pos, Qt::Horizontal); + if (index == -1) + return realActionCount(); + + return index; +} + +void QDesignerMenuBar::adjustIndicator(const QPoint &pos) +{ + const int index = findAction(pos); + QAction *action = safeActionAt(index); + Q_ASSERT(action != 0); + + if (pos != QPoint(-1, -1)) { + QDesignerMenu *m = qobject_cast(action->menu()); + if (!m || m->parentMenu()) { + m_currentIndex = index; + showMenu(index); + } + } + + if (QDesignerActionProviderExtension *a = actionProvider()) { + a->adjustIndicator(pos); + } +} + +QDesignerMenuBar::ActionDragCheck QDesignerMenuBar::checkAction(QAction *action) const +{ + // action belongs to another form + if (!action || !Utils::isObjectAncestorOf(formWindow()->mainContainer(), action)) + return NoActionDrag; + + if (!action->menu()) + return ActionDragOnSubMenu; // simple action only on sub menus + + QDesignerMenu *m = qobject_cast(action->menu()); + if (m && m->parentMenu()) + return ActionDragOnSubMenu; // it looks like a submenu + + if (actions().contains(action)) + return ActionDragOnSubMenu; // we already have the action in the menubar + + return AcceptActionDrag; +} + +void QDesignerMenuBar::dragEnterEvent(QDragEnterEvent *event) +{ + const ActionRepositoryMimeData *d = qobject_cast(event->mimeData()); + if (!d || d->actionList().empty()) { + event->ignore(); + return; + } + + QAction *action = d->actionList().first(); + switch (checkAction(action)) { + case NoActionDrag: + event->ignore(); + break; + case ActionDragOnSubMenu: + m_dragging = true; + d->accept(event); + break; + case AcceptActionDrag: + m_dragging = true; + d->accept(event); + adjustIndicator(event->pos()); + break; + } +} + +void QDesignerMenuBar::dragMoveEvent(QDragMoveEvent *event) +{ + const ActionRepositoryMimeData *d = qobject_cast(event->mimeData()); + if (!d || d->actionList().empty()) { + event->ignore(); + return; + } + QAction *action = d->actionList().first(); + + switch (checkAction(action)) { + case NoActionDrag: + event->ignore(); + break; + case ActionDragOnSubMenu: + event->ignore(); + showMenu(findAction(event->pos())); + break; + case AcceptActionDrag: + d->accept(event); + adjustIndicator(event->pos()); + break; + } +} + +void QDesignerMenuBar::dragLeaveEvent(QDragLeaveEvent *) +{ + m_dragging = false; + + adjustIndicator(QPoint(-1, -1)); +} + +void QDesignerMenuBar::dropEvent(QDropEvent *event) +{ + m_dragging = false; + + if (const ActionRepositoryMimeData *d = qobject_cast(event->mimeData())) { + + QAction *action = d->actionList().first(); + if (checkAction(action) == AcceptActionDrag) { + event->acceptProposedAction(); + int index = findAction(event->pos()); + index = qMin(index, actions().count() - 1); + + QDesignerFormWindowInterface *fw = formWindow(); + InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw); + cmd->init(this, action, safeActionAt(index)); + fw->commandHistory()->push(cmd); + + m_currentIndex = index; + update(); + adjustIndicator(QPoint(-1, -1)); + return; + } + } + event->ignore(); +} + +void QDesignerMenuBar::actionEvent(QActionEvent *event) +{ + QMenuBar::actionEvent(event); +} + +QDesignerFormWindowInterface *QDesignerMenuBar::formWindow() const +{ + return QDesignerFormWindowInterface::findFormWindow(const_cast(this)); +} + +QDesignerActionProviderExtension *QDesignerMenuBar::actionProvider() +{ + if (QDesignerFormWindowInterface *fw = formWindow()) { + QDesignerFormEditorInterface *core = fw->core(); + return qt_extension(core->extensionManager(), this); + } + + return 0; +} + +QAction *QDesignerMenuBar::currentAction() const +{ + if (m_currentIndex < 0 || m_currentIndex >= actions().count()) + return 0; + + return safeActionAt(m_currentIndex); +} + +int QDesignerMenuBar::realActionCount() const +{ + return actions().count() - 1; // 1 fake actions +} + +bool QDesignerMenuBar::dragging() const +{ + return m_dragging; +} + +void QDesignerMenuBar::moveLeft(bool ctrl) +{ + if (layoutDirection() == Qt::LeftToRight) { + movePrevious(ctrl); + } else { + moveNext(ctrl); + } +} + +void QDesignerMenuBar::moveRight(bool ctrl) +{ + if (layoutDirection() == Qt::LeftToRight) { + moveNext(ctrl); + } else { + movePrevious(ctrl); + } +} + +void QDesignerMenuBar::movePrevious(bool ctrl) +{ + const bool swapped = ctrl && swapActions(m_currentIndex, m_currentIndex - 1); + const int newIndex = qMax(0, m_currentIndex - 1); + // Always re-select, swapping destroys order + if (swapped || newIndex != m_currentIndex) { + m_currentIndex = newIndex; + updateCurrentAction(true); + } +} + +void QDesignerMenuBar::moveNext(bool ctrl) +{ + const bool swapped = ctrl && swapActions(m_currentIndex + 1, m_currentIndex); + const int newIndex = qMin(actions().count() - 1, m_currentIndex + 1); + if (swapped || newIndex != m_currentIndex) { + m_currentIndex = newIndex; + updateCurrentAction(!ctrl); + } +} + +void QDesignerMenuBar::moveUp() +{ + update(); +} + +void QDesignerMenuBar::moveDown() +{ + showMenu(); +} + +void QDesignerMenuBar::adjustSpecialActions() +{ + removeAction(m_addMenu); + addAction(m_addMenu); +} + +bool QDesignerMenuBar::interactive(bool i) +{ + const bool old = m_interactive; + m_interactive = i; + return old; +} + +void QDesignerMenuBar::hideMenu(int index) +{ + if (index < 0 && m_currentIndex >= 0) + index = m_currentIndex; + + if (index < 0 || index >= realActionCount()) + return; + + QAction *action = safeActionAt(index); + + if (action && action->menu()) { + action->menu()->hide(); + + if (QDesignerMenu *menu = qobject_cast(action->menu())) { + menu->closeMenuChain(); + } + } +} + +void QDesignerMenuBar::deleteMenu() +{ + deleteMenuAction(currentAction()); +} + +void QDesignerMenuBar::deleteMenuAction(QAction *action) +{ + if (action && !qobject_cast(action)) { + const int pos = actions().indexOf(action); + QAction *action_before = 0; + if (pos != -1) + action_before = safeActionAt(pos + 1); + + QDesignerFormWindowInterface *fw = formWindow(); + RemoveMenuActionCommand *cmd = new RemoveMenuActionCommand(fw); + cmd->init(action, action_before, this, this); + fw->commandHistory()->push(cmd); + } +} + +void QDesignerMenuBar::showMenu(int index) +{ + if (index < 0 && m_currentIndex >= 0) + index = m_currentIndex; + + if (index < 0 || index >= realActionCount()) + return; + + m_currentIndex = index; + QAction *action = currentAction(); + + if (action && action->menu()) { + if (m_lastMenuActionIndex != -1 && m_lastMenuActionIndex != index) { + hideMenu(m_lastMenuActionIndex); + } + + m_lastMenuActionIndex = index; + QMenu *menu = action->menu(); + const QRect g = actionGeometry(action); + + if (!menu->isVisible()) { + if ((menu->windowFlags() & Qt::Popup) != Qt::Popup) + menu->setWindowFlags(Qt::Popup); + menu->adjustSize(); + if (layoutDirection() == Qt::LeftToRight) { + menu->move(mapToGlobal(g.bottomLeft())); + } else { + // The position is not initially correct due to the unknown width, + // causing it to overlap a bit the first time it is invoked. + const QSize menuSize = menu->size(); + QPoint point = g.bottomRight() - QPoint(menu->width(), 0); + menu->move(mapToGlobal(point)); + } + menu->setFocus(Qt::MouseFocusReason); + menu->raise(); + menu->show(); + } else { + menu->raise(); + } + } +} + +QAction *QDesignerMenuBar::safeActionAt(int index) const +{ + if (index < 0 || index >= actions().count()) + return 0; + + return actions().at(index); +} + +bool QDesignerMenuBar::swapActions(int a, int b) +{ + const int left = qMin(a, b); + int right = qMax(a, b); + + QAction *action_a = safeActionAt(left); + QAction *action_b = safeActionAt(right); + + if (action_a == action_b + || !action_a + || !action_b + || qobject_cast(action_a) + || qobject_cast(action_b)) + return false; // nothing to do + + right = qMin(right, realActionCount()); + if (right < 0) + return false; // nothing to do + + formWindow()->beginCommand(QApplication::translate("Command", "Move action")); + + QAction *action_b_before = safeActionAt(right + 1); + + QDesignerFormWindowInterface *fw = formWindow(); + RemoveActionFromCommand *cmd1 = new RemoveActionFromCommand(fw); + cmd1->init(this, action_b, action_b_before, false); + fw->commandHistory()->push(cmd1); + + QAction *action_a_before = safeActionAt(left + 1); + + InsertActionIntoCommand *cmd2 = new InsertActionIntoCommand(fw); + cmd2->init(this, action_b, action_a_before, false); + fw->commandHistory()->push(cmd2); + + RemoveActionFromCommand *cmd3 = new RemoveActionFromCommand(fw); + cmd3->init(this, action_a, action_b, false); + fw->commandHistory()->push(cmd3); + + InsertActionIntoCommand *cmd4 = new InsertActionIntoCommand(fw); + cmd4->init(this, action_a, action_b_before, true); + fw->commandHistory()->push(cmd4); + + fw->endCommand(); + + return true; +} + +void QDesignerMenuBar::keyPressEvent(QKeyEvent *event) +{ + event->ignore(); +} + +void QDesignerMenuBar::keyReleaseEvent(QKeyEvent *event) +{ + event->ignore(); +} + +void QDesignerMenuBar::updateCurrentAction(bool selectAction) +{ + update(); + + if (!selectAction) + return; + + QAction *action = currentAction(); + if (!action || action == m_addMenu) + return; + + QMenu *menu = action->menu(); + if (!menu) + return; + + QDesignerObjectInspector *oi = 0; + if (QDesignerFormWindowInterface *fw = formWindow()) + oi = qobject_cast(fw->core()->objectInspector()); + + if (!oi) + return; + + oi->clearSelection(); + oi->selectObject(menu); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_menubar_p.h b/src/designer/src/lib/shared/qdesigner_menubar_p.h new file mode 100644 index 000000000..8ca538559 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_menubar_p.h @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_MENUBAR_H +#define QDESIGNER_MENUBAR_H + +#include "shared_global_p.h" + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QDesignerActionProviderExtension; + +class QLineEdit; +class QMimeData; + +namespace qdesigner_internal { +class PromotionTaskMenu; + +class SpecialMenuAction: public QAction +{ + Q_OBJECT +public: + SpecialMenuAction(QObject *parent = 0); + virtual ~SpecialMenuAction(); +}; + +} // namespace qdesigner_internal + +class QDESIGNER_SHARED_EXPORT QDesignerMenuBar: public QMenuBar +{ + Q_OBJECT +public: + QDesignerMenuBar(QWidget *parent = 0); + virtual ~QDesignerMenuBar(); + + bool eventFilter(QObject *object, QEvent *event); + + QDesignerFormWindowInterface *formWindow() const; + QDesignerActionProviderExtension *actionProvider(); + + void adjustSpecialActions(); + bool interactive(bool i); + bool dragging() const; + + void moveLeft(bool ctrl = false); + void moveRight(bool ctrl = false); + void moveUp(); + void moveDown(); + + // Helpers for MenuTaskMenu/MenuBarTaskMenu extensions + QList contextMenuActions(); + void deleteMenuAction(QAction *action); + +private slots: + void deleteMenu(); + void slotRemoveMenuBar(); + +protected: + virtual void actionEvent(QActionEvent *event); + virtual void dragEnterEvent(QDragEnterEvent *event); + virtual void dragMoveEvent(QDragMoveEvent *event); + virtual void dragLeaveEvent(QDragLeaveEvent *event); + virtual void dropEvent(QDropEvent *event); + virtual void paintEvent(QPaintEvent *event); + virtual void focusOutEvent(QFocusEvent *event); + virtual void keyPressEvent(QKeyEvent *event); + virtual void keyReleaseEvent(QKeyEvent *event); + + bool handleEvent(QWidget *widget, QEvent *event); + bool handleMouseDoubleClickEvent(QWidget *widget, QMouseEvent *event); + bool handleMousePressEvent(QWidget *widget, QMouseEvent *event); + bool handleMouseReleaseEvent(QWidget *widget, QMouseEvent *event); + bool handleMouseMoveEvent(QWidget *widget, QMouseEvent *event); + bool handleContextMenuEvent(QWidget *widget, QContextMenuEvent *event); + bool handleKeyPressEvent(QWidget *widget, QKeyEvent *event); + + void startDrag(const QPoint &pos); + + enum ActionDragCheck { NoActionDrag, ActionDragOnSubMenu, AcceptActionDrag }; + ActionDragCheck checkAction(QAction *action) const; + + void adjustIndicator(const QPoint &pos); + int findAction(const QPoint &pos) const; + + QAction *currentAction() const; + int realActionCount() const; + + enum LeaveEditMode { + Default = 0, + ForceAccept + }; + + void enterEditMode(); + void leaveEditMode(LeaveEditMode mode); + void showLineEdit(); + + void showMenu(int index = -1); + void hideMenu(int index = -1); + + QAction *safeActionAt(int index) const; + + bool swapActions(int a, int b); + +private: + void updateCurrentAction(bool selectAction); + void movePrevious(bool ctrl); + void moveNext(bool ctrl); + + QAction *m_addMenu; + QPointer m_activeMenu; + QPoint m_startPosition; + int m_currentIndex; + bool m_interactive; + QLineEdit *m_editor; + bool m_dragging; + int m_lastMenuActionIndex; + QPointer m_lastFocusWidget; + qdesigner_internal::PromotionTaskMenu* m_promotionTaskMenu; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_MENUBAR_H diff --git a/src/designer/src/lib/shared/qdesigner_objectinspector.cpp b/src/designer/src/lib/shared/qdesigner_objectinspector.cpp new file mode 100644 index 000000000..314638c74 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_objectinspector.cpp @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_objectinspector_p.h" + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +QDesignerObjectInspector::QDesignerObjectInspector(QWidget *parent, Qt::WindowFlags flags) : + QDesignerObjectInspectorInterface(parent, flags) +{ +} + +void QDesignerObjectInspector::mainContainerChanged() +{ +} + +void Selection::clear() +{ + managed.clear(); + unmanaged.clear(); + objects.clear(); +} + +bool Selection::empty() const +{ + return managed.empty() && unmanaged.empty() && objects.empty(); +} + +QObjectList Selection::selection() const +{ + QObjectList rc(objects); + foreach (QObject* o, managed) + rc.push_back(o); + foreach (QObject* o, unmanaged) + rc.push_back(o); + return rc; +} +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_objectinspector_p.h b/src/designer/src/lib/shared/qdesigner_objectinspector_p.h new file mode 100644 index 000000000..9cc630ef6 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_objectinspector_p.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef DESIGNEROBJECTINSPECTOR_H +#define DESIGNEROBJECTINSPECTOR_H + +#include "shared_global_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerDnDItemInterface; + +namespace qdesigner_internal { + +struct QDESIGNER_SHARED_EXPORT Selection { + bool empty() const; + void clear(); + + // Merge all lists + QObjectList selection() const; + + // Selection in cursor (managed widgets) + QWidgetList managed; + // Unmanaged widgets + QWidgetList unmanaged; + // Remaining selected objects (non-widgets) + QObjectList objects; +}; + +// Extends the QDesignerObjectInspectorInterface by functionality +// to access the selection + +class QDESIGNER_SHARED_EXPORT QDesignerObjectInspector: public QDesignerObjectInspectorInterface +{ + Q_OBJECT +public: + explicit QDesignerObjectInspector(QWidget *parent = 0, Qt::WindowFlags flags = 0); + + // Select a qobject unmanaged by form window + virtual bool selectObject(QObject *o) = 0; + virtual void getSelection(Selection &s) const = 0; + virtual void clearSelection() = 0; + +public slots: + virtual void mainContainerChanged(); +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // DESIGNEROBJECTINSPECTOR_H diff --git a/src/designer/src/lib/shared/qdesigner_promotion.cpp b/src/designer/src/lib/shared/qdesigner_promotion.cpp new file mode 100644 index 000000000..bf96b473b --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_promotion.cpp @@ -0,0 +1,373 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_promotion_p.h" +#include "widgetdatabase_p.h" +#include "metadatabase_p.h" +#include "widgetdatabase_p.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace { + // Return a set of on-promotable classes + const QSet &nonPromotableClasses() { + static QSet rc; + if (rc.empty()) { + rc.insert(QLatin1String("Line")); + rc.insert(QLatin1String("QAction")); + rc.insert(QLatin1String("Spacer")); + rc.insert(QLatin1String("QMainWindow")); + rc.insert(QLatin1String("QDialog")); + rc.insert(QLatin1String("QWorkspace")); + rc.insert(QLatin1String("QMdiArea")); + rc.insert(QLatin1String("QMdiSubWindow")); + } + return rc; + } + + // Return widget database index of a promoted class or -1 with error message + int promotedWidgetDataBaseIndex(const QDesignerWidgetDataBaseInterface *widgetDataBase, + const QString &className, + QString *errorMessage) { + const int index = widgetDataBase->indexOfClassName(className); + if (index == -1 || !widgetDataBase->item(index)->isPromoted()) { + *errorMessage = QCoreApplication::tr("%1 is not a promoted class.").arg(className); + return -1; + } + return index; + } + + // Return widget database item of a promoted class or 0 with error message + QDesignerWidgetDataBaseItemInterface *promotedWidgetDataBaseItem(const QDesignerWidgetDataBaseInterface *widgetDataBase, + const QString &className, + QString *errorMessage) { + + const int index = promotedWidgetDataBaseIndex(widgetDataBase, className, errorMessage); + if (index == -1) + return 0; + return widgetDataBase->item(index); + } + + // extract class name from xml "". Quite a hack. + QString classNameFromXml(QString xml) { + static const QString tag = QLatin1String("class=\""); + const int pos = xml.indexOf(tag); + if (pos == -1) + return QString(); + xml.remove(0, pos + tag.size()); + const int closingPos = xml.indexOf(QLatin1Char('"')); + if (closingPos == -1) + return QString(); + xml.remove(closingPos, xml.size() - closingPos); + return xml; + } + + // return a list of class names in the scratch pad + QStringList getScratchPadClasses(const QDesignerWidgetBoxInterface *wb) { + QStringList rc; + const int catCount = wb->categoryCount(); + for (int c = 0; c < catCount; c++) { + const QDesignerWidgetBoxInterface::Category category = wb->category(c); + if (category.type() == QDesignerWidgetBoxInterface::Category::Scratchpad) { + const int widgetCount = category.widgetCount(); + for (int w = 0; w < widgetCount; w++) { + const QString className = classNameFromXml( category.widget(w).domXml()); + if (!className.isEmpty()) + rc += className; + } + } + } + return rc; + } +} + +namespace qdesigner_internal { + + QDesignerPromotion::QDesignerPromotion(QDesignerFormEditorInterface *core) : + m_core(core) { + } + + bool QDesignerPromotion::addPromotedClass(const QString &baseClass, + const QString &className, + const QString &includeFile, + QString *errorMessage) + { + QDesignerWidgetDataBaseInterface *widgetDataBase = m_core->widgetDataBase(); + const int baseClassIndex = widgetDataBase->indexOfClassName(baseClass); + + if (baseClassIndex == -1) { + *errorMessage = QCoreApplication::tr("The base class %1 is invalid.").arg(baseClass); + return false; + } + + const int existingClassIndex = widgetDataBase->indexOfClassName(className); + + if (existingClassIndex != -1) { + *errorMessage = QCoreApplication::tr("The class %1 already exists.").arg(className); + return false; + } + // Clone derived item. + QDesignerWidgetDataBaseItemInterface *promotedItem = WidgetDataBaseItem::clone(widgetDataBase->item(baseClassIndex)); + // Also inherit the container flag in case of QWidget-derived classes + // as it is most likely intended for stacked pages. + // set new props + promotedItem->setName(className); + promotedItem->setGroup(QCoreApplication::tr("Promoted Widgets")); + promotedItem->setCustom(true); + promotedItem->setPromoted(true); + promotedItem->setExtends(baseClass); + promotedItem->setIncludeFile(includeFile); + widgetDataBase->append(promotedItem); + return true; + } + + QList QDesignerPromotion::promotionBaseClasses() const + { + typedef QMap SortedDatabaseItemMap; + SortedDatabaseItemMap sortedDatabaseItemMap; + + QDesignerWidgetDataBaseInterface *widgetDataBase = m_core->widgetDataBase(); + + const int cnt = widgetDataBase->count(); + for (int i = 0; i < cnt; i++) { + QDesignerWidgetDataBaseItemInterface *dbItem = widgetDataBase->item(i); + if (canBePromoted(dbItem)) { + sortedDatabaseItemMap.insert(dbItem->name(), dbItem); + } + } + + return sortedDatabaseItemMap.values(); + } + + + bool QDesignerPromotion::canBePromoted(const QDesignerWidgetDataBaseItemInterface *dbItem) const + { + if (dbItem->isPromoted() || !dbItem->extends().isEmpty()) + return false; + + const QString name = dbItem->name(); + + if (nonPromotableClasses().contains(name)) + return false; + + if (name.startsWith(QLatin1String("QDesigner")) || + name.startsWith(QLatin1String("QLayout"))) + return false; + + return true; + } + + QDesignerPromotion::PromotedClasses QDesignerPromotion::promotedClasses() const + { + typedef QMap ClassNameItemMap; + // A map containing base classes and their promoted classes. + typedef QMap BaseClassPromotedMap; + + BaseClassPromotedMap baseClassPromotedMap; + + QDesignerWidgetDataBaseInterface *widgetDataBase = m_core->widgetDataBase(); + // Look for promoted classes and insert into map according to base class. + const int cnt = widgetDataBase->count(); + for (int i = 0; i < cnt; i++) { + QDesignerWidgetDataBaseItemInterface *dbItem = widgetDataBase->item(i); + if (dbItem->isPromoted()) { + const QString baseClassName = dbItem->extends(); + BaseClassPromotedMap::iterator it = baseClassPromotedMap.find(baseClassName); + if (it == baseClassPromotedMap.end()) { + it = baseClassPromotedMap.insert(baseClassName, ClassNameItemMap()); + } + it.value().insert(dbItem->name(), dbItem); + } + } + // convert map into list. + PromotedClasses rc; + + if (baseClassPromotedMap.empty()) + return rc; + + const BaseClassPromotedMap::const_iterator bcend = baseClassPromotedMap.constEnd(); + for (BaseClassPromotedMap::const_iterator bit = baseClassPromotedMap.constBegin(); bit != bcend; ++bit) { + const int baseIndex = widgetDataBase->indexOfClassName(bit.key()); + Q_ASSERT(baseIndex >= 0); + QDesignerWidgetDataBaseItemInterface *baseItem = widgetDataBase->item(baseIndex); + // promoted + const ClassNameItemMap::const_iterator pcend = bit.value().constEnd(); + for (ClassNameItemMap::const_iterator pit = bit.value().constBegin(); pit != pcend; ++pit) { + PromotedClass item; + item.baseItem = baseItem; + item.promotedItem = pit.value(); + rc.push_back(item); + } + } + + return rc; + } + + QSet QDesignerPromotion::referencedPromotedClassNames() const { + QSet rc; + const MetaDataBase *metaDataBase = qobject_cast(m_core->metaDataBase()); + if (!metaDataBase) + return rc; + + const QList objs = metaDataBase->objects(); + const QList::const_iterator cend = objs.constEnd(); + for ( QList::const_iterator it = objs.constBegin(); it != cend; ++it) { + const QString customClass = metaDataBase->metaDataBaseItem(*it)->customClassName(); + if (!customClass.isEmpty()) + rc.insert(customClass); + + } + // check the scratchpad of the widget box + if (QDesignerWidgetBoxInterface *widgetBox = m_core->widgetBox()) { + const QStringList scratchPadClasses = getScratchPadClasses(widgetBox); + if (!scratchPadClasses.empty()) { + // Check whether these are actually promoted + QDesignerWidgetDataBaseInterface *widgetDataBase = m_core->widgetDataBase(); + QStringList::const_iterator cend = scratchPadClasses.constEnd(); + for (QStringList::const_iterator it = scratchPadClasses.constBegin(); it != cend; ++it ) { + const int index = widgetDataBase->indexOfClassName(*it); + if (index != -1 && widgetDataBase->item(index)->isPromoted()) + rc += *it; + } + } + } + return rc; + } + + bool QDesignerPromotion::removePromotedClass(const QString &className, QString *errorMessage) { + // check if it exists and is promoted + WidgetDataBase *widgetDataBase = qobject_cast(m_core->widgetDataBase()); + if (!widgetDataBase) { + *errorMessage = QCoreApplication::tr("The class %1 cannot be removed").arg(className); + return false; + } + + const int index = promotedWidgetDataBaseIndex(widgetDataBase, className, errorMessage); + if (index == -1) + return false; + + if (referencedPromotedClassNames().contains(className)) { + *errorMessage = QCoreApplication::tr("The class %1 cannot be removed because it is still referenced.").arg(className); + return false; + } + widgetDataBase->remove(index); + return true; + } + + bool QDesignerPromotion::changePromotedClassName(const QString &oldclassName, const QString &newClassName, QString *errorMessage) { + const MetaDataBase *metaDataBase = qobject_cast(m_core->metaDataBase()); + if (!metaDataBase) { + *errorMessage = QCoreApplication::tr("The class %1 cannot be renamed").arg(oldclassName); + return false; + } + QDesignerWidgetDataBaseInterface *widgetDataBase = m_core->widgetDataBase(); + + // check the new name + if (newClassName.isEmpty()) { + *errorMessage = QCoreApplication::tr("The class %1 cannot be renamed to an empty name.").arg(oldclassName); + return false; + } + const int existingIndex = widgetDataBase->indexOfClassName(newClassName); + if (existingIndex != -1) { + *errorMessage = QCoreApplication::tr("There is already a class named %1.").arg(newClassName); + return false; + } + // Check old class + QDesignerWidgetDataBaseItemInterface *dbItem = promotedWidgetDataBaseItem(widgetDataBase, oldclassName, errorMessage); + if (!dbItem) + return false; + + // Change the name in the data base and change all referencing objects in the meta database + dbItem->setName(newClassName); + bool foundReferences = false; + foreach (QObject* object, metaDataBase->objects()) { + MetaDataBaseItem *item = metaDataBase->metaDataBaseItem(object); + Q_ASSERT(item); + if (item->customClassName() == oldclassName) { + item->setCustomClassName(newClassName); + foundReferences = true; + } + } + // set state + if (foundReferences) + refreshObjectInspector(); + + return true; + } + + bool QDesignerPromotion::setPromotedClassIncludeFile(const QString &className, const QString &includeFile, QString *errorMessage) { + // check file + if (includeFile.isEmpty()) { + *errorMessage = QCoreApplication::tr("Cannot set an empty include file."); + return false; + } + // check item + QDesignerWidgetDataBaseInterface *widgetDataBase = m_core->widgetDataBase(); + QDesignerWidgetDataBaseItemInterface *dbItem = promotedWidgetDataBaseItem(widgetDataBase, className, errorMessage); + if (!dbItem) + return false; + + dbItem->setIncludeFile(includeFile); + return true; + } + + void QDesignerPromotion::refreshObjectInspector() { + if (QDesignerFormWindowManagerInterface *fwm = m_core->formWindowManager()) { + if (QDesignerFormWindowInterface *fw = fwm->activeFormWindow()) + if ( QDesignerObjectInspectorInterface *oi = m_core->objectInspector()) { + oi->setFormWindow(fw); + } + } + } +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_promotion_p.h b/src/designer/src/lib/shared/qdesigner_promotion_p.h new file mode 100644 index 000000000..b1af1db93 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_promotion_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNERPROMOTION_H +#define QDESIGNERPROMOTION_H + +#include "shared_global_p.h" + +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + + class QDESIGNER_SHARED_EXPORT QDesignerPromotion : public QDesignerPromotionInterface + { + public: + explicit QDesignerPromotion(QDesignerFormEditorInterface *core); + + virtual PromotedClasses promotedClasses() const; + + virtual QSet referencedPromotedClassNames() const; + + virtual bool addPromotedClass(const QString &baseClass, + const QString &className, + const QString &includeFile, + QString *errorMessage); + + virtual bool removePromotedClass(const QString &className, QString *errorMessage); + + virtual bool changePromotedClassName(const QString &oldclassName, const QString &newClassName, QString *errorMessage); + + virtual bool setPromotedClassIncludeFile(const QString &className, const QString &includeFile, QString *errorMessage); + + virtual QList promotionBaseClasses() const; + + private: + bool canBePromoted(const QDesignerWidgetDataBaseItemInterface *) const; + void refreshObjectInspector(); + + QDesignerFormEditorInterface *m_core; + }; +} + +QT_END_NAMESPACE + +#endif // QDESIGNERPROMOTION_H diff --git a/src/designer/src/lib/shared/qdesigner_promotiondialog.cpp b/src/designer/src/lib/shared/qdesigner_promotiondialog.cpp new file mode 100644 index 000000000..6463016b1 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_promotiondialog.cpp @@ -0,0 +1,456 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_promotiondialog_p.h" +#include "promotionmodel_p.h" +#include "iconloader_p.h" +#include "widgetdatabase_p.h" +#include "signalslotdialog_p.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + // PromotionParameters + struct PromotionParameters { + QString m_baseClass; + QString m_className; + QString m_includeFile; + }; + + // NewPromotedClassPanel + NewPromotedClassPanel::NewPromotedClassPanel(const QStringList &baseClasses, + int selectedBaseClass, + QWidget *parent) : + QGroupBox(parent), + m_baseClassCombo(new QComboBox), + m_classNameEdit(new QLineEdit), + m_includeFileEdit(new QLineEdit), + m_globalIncludeCheckBox(new QCheckBox), + m_addButton(new QPushButton(tr("Add"))) + { + setTitle(tr("New Promoted Class")); + setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum); + QHBoxLayout *hboxLayout = new QHBoxLayout(this); + + m_classNameEdit->setValidator(new QRegExpValidator(QRegExp(QLatin1String("[_a-zA-Z:][:_a-zA-Z0-9]*")), m_classNameEdit)); + connect(m_classNameEdit, SIGNAL(textChanged(QString)), this, SLOT(slotNameChanged(QString))); + connect(m_includeFileEdit, SIGNAL(textChanged(QString)), this, SLOT(slotIncludeFileChanged(QString))); + + m_baseClassCombo->setEditable(false); + m_baseClassCombo->addItems(baseClasses); + if (selectedBaseClass != -1) + m_baseClassCombo->setCurrentIndex(selectedBaseClass); + + // Grid + QFormLayout *formLayout = new QFormLayout(); + formLayout->addRow(tr("Base class name:"), m_baseClassCombo); + formLayout->addRow(tr("Promoted class name:"), m_classNameEdit); + formLayout->addRow(tr("Header file:"), m_includeFileEdit); + formLayout->addRow(tr("Global include"), m_globalIncludeCheckBox); + hboxLayout->addLayout(formLayout); + hboxLayout->addItem(new QSpacerItem(15, 0, QSizePolicy::Fixed, QSizePolicy::Ignored)); + // Button box + QVBoxLayout *buttonLayout = new QVBoxLayout(); + + m_addButton->setAutoDefault(false); + connect(m_addButton, SIGNAL(clicked()), this, SLOT(slotAdd())); + m_addButton->setEnabled(false); + buttonLayout->addWidget(m_addButton); + + QPushButton *resetButton = new QPushButton(tr("Reset")); + resetButton->setAutoDefault(false); + connect(resetButton, SIGNAL(clicked()), this, SLOT(slotReset())); + + buttonLayout->addWidget(resetButton); + buttonLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::Expanding)); + hboxLayout->addLayout(buttonLayout); + + enableButtons(); + } + + void NewPromotedClassPanel::slotAdd() { + bool ok = false; + emit newPromotedClass(promotionParameters(), &ok); + if (ok) + slotReset(); + } + + void NewPromotedClassPanel::slotReset() { + const QString empty; + m_classNameEdit->setText(empty); + m_includeFileEdit->setText(empty); + m_globalIncludeCheckBox->setCheckState(Qt::Unchecked); + } + + void NewPromotedClassPanel::grabFocus() { + m_classNameEdit->setFocus(Qt::OtherFocusReason); + } + + void NewPromotedClassPanel::slotNameChanged(const QString &className) { + // Suggest a name + if (!className.isEmpty()) { + const QChar dot(QLatin1Char('.')); + QString suggestedHeader = m_promotedHeaderLowerCase ? + className.toLower() : className; + suggestedHeader.replace(QLatin1String("::"), QString(QLatin1Char('_'))); + if (!m_promotedHeaderSuffix.startsWith(dot)) + suggestedHeader += dot; + suggestedHeader += m_promotedHeaderSuffix; + + const bool blocked = m_includeFileEdit->blockSignals(true); + m_includeFileEdit->setText(suggestedHeader); + m_includeFileEdit->blockSignals(blocked); + } + enableButtons(); + } + + void NewPromotedClassPanel::slotIncludeFileChanged(const QString &){ + enableButtons(); + } + + void NewPromotedClassPanel::enableButtons() { + const bool enabled = !m_classNameEdit->text().isEmpty() && !m_includeFileEdit->text().isEmpty(); + m_addButton->setEnabled(enabled); + m_addButton->setDefault(enabled); + } + + PromotionParameters NewPromotedClassPanel::promotionParameters() const { + PromotionParameters rc; + rc.m_baseClass = m_baseClassCombo->currentText(); + rc.m_className = m_classNameEdit->text(); + rc.m_includeFile = buildIncludeFile(m_includeFileEdit->text(), + m_globalIncludeCheckBox->checkState() == Qt::Checked ? IncludeGlobal : IncludeLocal); + return rc; + } + + void NewPromotedClassPanel::chooseBaseClass(const QString &baseClass) { + const int index = m_baseClassCombo->findText (baseClass); + if (index != -1) + m_baseClassCombo->setCurrentIndex (index); + } + + // --------------- QDesignerPromotionDialog + QDesignerPromotionDialog::QDesignerPromotionDialog(QDesignerFormEditorInterface *core, + QWidget *parent, + const QString &promotableWidgetClassName, + QString *promoteTo) : + QDialog(parent), + m_mode(promotableWidgetClassName.isEmpty() || promoteTo == 0 ? ModeEdit : ModeEditChooseClass), + m_promotableWidgetClassName(promotableWidgetClassName), + m_core(core), + m_promoteTo(promoteTo), + m_promotion(core->promotion()), + m_model(new PromotionModel(core)), + m_treeView(new QTreeView), + m_buttonBox(0), + m_removeButton(new QPushButton(createIconSet(QString::fromUtf8("minus.png")), QString())) + { + m_buttonBox = createButtonBox(); + setModal(true); + setWindowTitle(tr("Promoted Widgets")); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + QVBoxLayout *vboxLayout = new QVBoxLayout(this); + + // tree view group + QGroupBox *treeViewGroup = new QGroupBox(); + treeViewGroup->setTitle(tr("Promoted Classes")); + QVBoxLayout *treeViewVBoxLayout = new QVBoxLayout(treeViewGroup); + // tree view + m_treeView->setModel (m_model); + m_treeView->setMinimumWidth(450); + m_treeView->setContextMenuPolicy(Qt::CustomContextMenu); + + connect(m_treeView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), + this, SLOT(slotSelectionChanged(QItemSelection,QItemSelection))); + + connect(m_treeView, SIGNAL(customContextMenuRequested(QPoint)), + this, SLOT(slotTreeViewContextMenu(QPoint))); + + QHeaderView *headerView = m_treeView->header(); + headerView->setResizeMode(QHeaderView::ResizeToContents); + treeViewVBoxLayout->addWidget(m_treeView); + // remove button + QHBoxLayout *hboxLayout = new QHBoxLayout(); + hboxLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored)); + + m_removeButton->setAutoDefault(false); + connect(m_removeButton, SIGNAL(clicked()), this, SLOT(slotRemove())); + m_removeButton->setEnabled(false); + hboxLayout->addWidget(m_removeButton); + treeViewVBoxLayout->addLayout(hboxLayout); + vboxLayout->addWidget(treeViewGroup); + // Create new panel: Try to be smart and preselect a base class. Default to QFrame + const QStringList &baseClassNameList = baseClassNames(m_promotion); + int preselectedBaseClass = -1; + if (m_mode == ModeEditChooseClass) { + preselectedBaseClass = baseClassNameList.indexOf(m_promotableWidgetClassName); + } + if (preselectedBaseClass == -1) + preselectedBaseClass = baseClassNameList.indexOf(QLatin1String("QFrame")); + + NewPromotedClassPanel *newPromotedClassPanel = new NewPromotedClassPanel(baseClassNameList, preselectedBaseClass); + newPromotedClassPanel->setPromotedHeaderSuffix(core->integration()->headerSuffix()); + newPromotedClassPanel->setPromotedHeaderLowerCase(core->integration()->isHeaderLowercase()); + connect(newPromotedClassPanel, SIGNAL(newPromotedClass(PromotionParameters,bool*)), this, SLOT(slotNewPromotedClass(PromotionParameters,bool*))); + connect(this, SIGNAL(selectedBaseClassChanged(QString)), + newPromotedClassPanel, SLOT(chooseBaseClass(QString))); + vboxLayout->addWidget(newPromotedClassPanel); + // button box + vboxLayout->addWidget(m_buttonBox); + // connect model + connect(m_model, SIGNAL(includeFileChanged(QDesignerWidgetDataBaseItemInterface*,QString)), + this, SLOT(slotIncludeFileChanged(QDesignerWidgetDataBaseItemInterface*,QString))); + + connect(m_model, SIGNAL(classNameChanged(QDesignerWidgetDataBaseItemInterface*,QString)), + this, SLOT(slotClassNameChanged(QDesignerWidgetDataBaseItemInterface*,QString))); + + // focus + if (m_mode == ModeEditChooseClass) + newPromotedClassPanel->grabFocus(); + + slotUpdateFromWidgetDatabase(); + } + + QDialogButtonBox *QDesignerPromotionDialog::createButtonBox() { + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Close); + + connect(buttonBox , SIGNAL(accepted()), this, SLOT(slotAcceptPromoteTo())); + buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Promote")); + buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + + connect(buttonBox , SIGNAL(rejected()), this, SLOT(reject())); + return buttonBox; + } + + void QDesignerPromotionDialog::slotUpdateFromWidgetDatabase() { + m_model->updateFromWidgetDatabase(); + m_treeView->expandAll(); + m_removeButton->setEnabled(false); + } + + void QDesignerPromotionDialog::delayedUpdateFromWidgetDatabase() { + QTimer::singleShot(0, this, SLOT(slotUpdateFromWidgetDatabase())); + } + + const QStringList &QDesignerPromotionDialog::baseClassNames(const QDesignerPromotionInterface *promotion) { + typedef QList WidgetDataBaseItemList; + static QStringList rc; + if (rc.empty()) { + // Convert the item list into a string list. + const WidgetDataBaseItemList dbItems = promotion->promotionBaseClasses(); + const WidgetDataBaseItemList::const_iterator cend = dbItems.constEnd(); + for (WidgetDataBaseItemList::const_iterator it = dbItems.constBegin() ; it != cend; ++it) { + rc.push_back( (*it)->name()); + } + } + return rc; + } + + void QDesignerPromotionDialog::slotAcceptPromoteTo() { + Q_ASSERT(m_mode == ModeEditChooseClass); + unsigned flags; + // Ok pressed: Promote to selected class + if (QDesignerWidgetDataBaseItemInterface *dbItem = databaseItemAt(m_treeView->selectionModel()->selection(), flags)) { + if (flags & CanPromote) { + *m_promoteTo = dbItem ->name(); + accept(); + } + } + } + + void QDesignerPromotionDialog::slotRemove() { + unsigned flags; + QDesignerWidgetDataBaseItemInterface *dbItem = databaseItemAt(m_treeView->selectionModel()->selection(), flags); + if (!dbItem || (flags & Referenced)) + return; + + QString errorMessage; + if (m_promotion->removePromotedClass(dbItem->name(), &errorMessage)) { + slotUpdateFromWidgetDatabase(); + } else { + displayError(errorMessage); + } + } + + void QDesignerPromotionDialog::slotSelectionChanged(const QItemSelection &selected, const QItemSelection &) { + // Enable deleting non-referenced items + unsigned flags; + const QDesignerWidgetDataBaseItemInterface *dbItem = databaseItemAt(selected, flags); + m_removeButton->setEnabled(dbItem && !(flags & Referenced)); + // In choose mode, can we promote to the class? + if (m_mode == ModeEditChooseClass) { + const bool enablePromoted = flags & CanPromote; + m_buttonBox->button(QDialogButtonBox::Ok)->setEnabled(enablePromoted); + m_buttonBox->button(QDialogButtonBox::Ok)->setDefault(enablePromoted); + } + // different base? + if (dbItem) { + const QString baseClass = dbItem->extends(); + if (baseClass != m_lastSelectedBaseClass) { + m_lastSelectedBaseClass = baseClass; + emit selectedBaseClassChanged(m_lastSelectedBaseClass); + } + } + } + + QDesignerWidgetDataBaseItemInterface *QDesignerPromotionDialog::databaseItemAt(const QItemSelection &selected, unsigned &flags) const { + flags = 0; + const QModelIndexList indexes = selected.indexes(); + if (indexes.empty()) + return 0; + + bool referenced; + QDesignerWidgetDataBaseItemInterface *dbItem = m_model->databaseItemAt(indexes.front(), &referenced); + + if (dbItem) { + if (referenced) + flags |= Referenced; + // In choose mode, can we promote to the class? + if (m_mode == ModeEditChooseClass && dbItem && dbItem->isPromoted() && dbItem->extends() == m_promotableWidgetClassName) + flags |= CanPromote; + + } + return dbItem; + } + + void QDesignerPromotionDialog::slotNewPromotedClass(const PromotionParameters &p, bool *ok) { + QString errorMessage; + *ok = m_promotion->addPromotedClass(p.m_baseClass, p.m_className, p.m_includeFile, &errorMessage); + if (*ok) { + // update and select + slotUpdateFromWidgetDatabase(); + const QModelIndex newClassIndex = m_model->indexOfClass(p.m_className); + if (newClassIndex.isValid()) { + m_treeView->selectionModel()->select(newClassIndex, QItemSelectionModel::SelectCurrent|QItemSelectionModel::Rows); + } + } else { + displayError(errorMessage); + } + } + + void QDesignerPromotionDialog::slotIncludeFileChanged(QDesignerWidgetDataBaseItemInterface *dbItem, const QString &includeFile) { + if (includeFile.isEmpty()) { + delayedUpdateFromWidgetDatabase(); + return; + } + + if (dbItem->includeFile() == includeFile) + return; + + QString errorMessage; + if (!m_promotion->setPromotedClassIncludeFile(dbItem->name(), includeFile, &errorMessage)) { + displayError(errorMessage); + delayedUpdateFromWidgetDatabase(); + } + } + + void QDesignerPromotionDialog::slotClassNameChanged(QDesignerWidgetDataBaseItemInterface *dbItem, const QString &newName) { + if (newName.isEmpty()) { + delayedUpdateFromWidgetDatabase(); + return; + } + const QString oldName = dbItem->name(); + if (newName == oldName) + return; + + QString errorMessage; + if (!m_promotion->changePromotedClassName(oldName , newName, &errorMessage)) { + displayError(errorMessage); + delayedUpdateFromWidgetDatabase(); + } + } + + void QDesignerPromotionDialog::slotTreeViewContextMenu(const QPoint &pos) { + unsigned flags; + const QDesignerWidgetDataBaseItemInterface *dbItem = databaseItemAt(m_treeView->selectionModel()->selection(), flags); + if (!dbItem) + return; + + QMenu menu; + QAction *signalSlotAction = menu.addAction(tr("Change signals/slots...")); + connect(signalSlotAction, SIGNAL(triggered()), this, SLOT(slotEditSignalsSlots())); + + menu.exec(m_treeView->viewport()->mapToGlobal(pos)); + } + + void QDesignerPromotionDialog::slotEditSignalsSlots() { + unsigned flags; + const QDesignerWidgetDataBaseItemInterface *dbItem = databaseItemAt(m_treeView->selectionModel()->selection(), flags); + if (!dbItem) + return; + + SignalSlotDialog::editPromotedClass(m_core, dbItem->name(), this); + } + + void QDesignerPromotionDialog::displayError(const QString &message) { + m_core->dialogGui()->message(this, QDesignerDialogGuiInterface::PromotionErrorMessage, QMessageBox::Warning, + tr("%1 - Error").arg(windowTitle()), message, QMessageBox::Close); + } +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_promotiondialog_p.h b/src/designer/src/lib/shared/qdesigner_promotiondialog_p.h new file mode 100644 index 000000000..73cf7ad50 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_promotiondialog_p.h @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef PROMOTIONEDITORDIALOG_H +#define PROMOTIONEDITORDIALOG_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; +class QDesignerFormWindowInterface; +class QDesignerPromotionInterface; +class QDesignerWidgetDataBaseItemInterface; + +class QTreeView; +class QPushButton; +class QItemSelection; +class QDialogButtonBox; +class QComboBox; +class QLineEdit; +class QCheckBox; + +namespace qdesigner_internal { + struct PromotionParameters; + class PromotionModel; + + + // Panel for adding a new promoted class. Separate class for code cleanliness. + class NewPromotedClassPanel : public QGroupBox { + Q_OBJECT + public: + explicit NewPromotedClassPanel(const QStringList &baseClasses, + int selectedBaseClass = -1, + QWidget *parent = 0); + + QString promotedHeaderSuffix() const { return m_promotedHeaderSuffix; } + void setPromotedHeaderSuffix(const QString &s) { m_promotedHeaderSuffix = s; } + + bool isPromotedHeaderLowerCase() const { return m_promotedHeaderLowerCase; } + void setPromotedHeaderLowerCase(bool l) { m_promotedHeaderLowerCase = l; } + + signals: + void newPromotedClass(const PromotionParameters &, bool *ok); + + public slots: + void grabFocus(); + void chooseBaseClass(const QString &); + private slots: + void slotNameChanged(const QString &); + void slotIncludeFileChanged(const QString &); + void slotAdd(); + void slotReset(); + + private: + PromotionParameters promotionParameters() const; + void enableButtons(); + + QString m_promotedHeaderSuffix; + bool m_promotedHeaderLowerCase; + + QComboBox *m_baseClassCombo; + QLineEdit *m_classNameEdit; + QLineEdit *m_includeFileEdit; + QCheckBox *m_globalIncludeCheckBox; + QPushButton *m_addButton; + }; + + // Dialog for editing promoted classes. + class QDesignerPromotionDialog : public QDialog { + Q_OBJECT + + public: + enum Mode { ModeEdit, ModeEditChooseClass }; + + explicit QDesignerPromotionDialog(QDesignerFormEditorInterface *core, + QWidget *parent = 0, + const QString &promotableWidgetClassName = QString(), + QString *promoteTo = 0); + // Return an alphabetically ordered list of base class names for adding new classes. + static const QStringList &baseClassNames(const QDesignerPromotionInterface *promotion); + + signals: + void selectedBaseClassChanged(const QString &); + private slots: + void slotRemove(); + void slotAcceptPromoteTo(); + void slotSelectionChanged(const QItemSelection &, const QItemSelection &); + void slotNewPromotedClass(const PromotionParameters &, bool *ok); + + void slotIncludeFileChanged(QDesignerWidgetDataBaseItemInterface *, const QString &includeFile); + void slotClassNameChanged(QDesignerWidgetDataBaseItemInterface *, const QString &newName); + void slotUpdateFromWidgetDatabase(); + void slotTreeViewContextMenu(const QPoint &); + void slotEditSignalsSlots(); + + private: + QDialogButtonBox *createButtonBox(); + void delayedUpdateFromWidgetDatabase(); + // Return item at model index and a combination of flags or 0. + enum { Referenced = 1, CanPromote = 2 }; + QDesignerWidgetDataBaseItemInterface *databaseItemAt(const QItemSelection &, unsigned &flags) const; + void displayError(const QString &message); + + const Mode m_mode; + const QString m_promotableWidgetClassName; + QDesignerFormEditorInterface *m_core; + QString *m_promoteTo; + QDesignerPromotionInterface *m_promotion; + PromotionModel *m_model; + QTreeView *m_treeView; + QDialogButtonBox *m_buttonBox; + QPushButton *m_removeButton; + QString m_lastSelectedBaseClass; + }; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // PROMOTIONEDITORDIALOG_H diff --git a/src/designer/src/lib/shared/qdesigner_propertycommand.cpp b/src/designer/src/lib/shared/qdesigner_propertycommand.cpp new file mode 100644 index 000000000..a9949d85c --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_propertycommand.cpp @@ -0,0 +1,1503 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_propertycommand_p.h" +#include "qdesigner_utils_p.h" +#include "dynamicpropertysheet.h" +#include "qdesigner_propertyeditor_p.h" +#include "qdesigner_integration_p.h" +#include "spacer_widget_p.h" +#include "qdesigner_propertysheet_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace { +enum { debugPropertyCommands = 0 }; + +// Debug resolve mask of font +QString fontMask(unsigned m) +{ + QString rc; + if (m & QFont::FamilyResolved) + rc += QLatin1String("Family"); + if (m & QFont::SizeResolved) + rc += QLatin1String("Size "); + if (m & QFont::WeightResolved) + rc += QLatin1String("Bold "); + if (m & QFont::StyleResolved) + rc += QLatin1String("Style "); + if (m & QFont::UnderlineResolved) + rc += QLatin1String("Underline "); + if (m & QFont::StrikeOutResolved) + rc += QLatin1String("StrikeOut "); + if (m & QFont::KerningResolved) + rc += QLatin1String("Kerning "); + if (m & QFont::StyleStrategyResolved) + rc += QLatin1String("StyleStrategy"); + return rc; +} + +// Debug font +QString fontString(const QFont &f) +{ + QString rc; { + const QChar comma = QLatin1Char(','); + QTextStream str(&rc); + str << QLatin1String("QFont(\"") << f.family() << comma << + f.pointSize(); + if (f.bold()) + str << comma << QLatin1String("bold"); + if (f.italic()) + str << comma << QLatin1String("italic"); + if (f.underline()) + str << comma << QLatin1String("underline"); + if (f.strikeOut()) + str << comma << QLatin1String("strikeOut"); + if (f.kerning()) + str << comma << QLatin1String("kerning"); + str << comma << f.styleStrategy() << QLatin1String(" resolve: ") + << fontMask(f.resolve()) << QLatin1Char(')'); + } + return rc; +} +QSize checkSize(const QSize &size) +{ + return size.boundedTo(QSize(0xFFFFFF, 0xFFFFFF)); +} + +QSize diffSize(QDesignerFormWindowInterface *fw) +{ + const QWidget *container = fw->core()->integration()->containerWindow(fw); + if (!container) + return QSize(); + + const QSize diff = container->size() - fw->size(); // decoration offset of container window + return diff; +} + +void checkSizes(QDesignerFormWindowInterface *fw, const QSize &size, QSize *formSize, QSize *containerSize) +{ + const QWidget *container = fw->core()->integration()->containerWindow(fw); + if (!container) + return; + + const QSize diff = diffSize(fw); // decoration offset of container window + + QSize newFormSize = checkSize(size).expandedTo(fw->mainContainer()->minimumSizeHint()); // don't try to resize to smaller size than minimumSizeHint + QSize newContainerSize = newFormSize + diff; + + newContainerSize = newContainerSize.expandedTo(container->minimumSizeHint()); + newContainerSize = newContainerSize.expandedTo(container->minimumSize()); + + newFormSize = newContainerSize - diff; + + newContainerSize = checkSize(newContainerSize); + + if (formSize) + *formSize = newFormSize; + if (containerSize) + *containerSize = newContainerSize; +} + +/* SubProperties: When applying a changed property to a multiselection, it sometimes makes + * sense to apply only parts (subproperties) of the property. + * For example, if someone changes the x-value of a geometry in the property editor + * and applies it to a multi-selection, y should not be applied as this would cause all + * the widgets to overlap. + * The following routines can be used to find out the changed subproperties of a property, + * which are represented as a mask, and to apply them while leaving the others intact. */ + +enum RectSubPropertyMask { SubPropertyX=1, SubPropertyY = 2, SubPropertyWidth = 4, SubPropertyHeight = 8 }; +enum SizePolicySubPropertyMask { SubPropertyHSizePolicy = 1, SubPropertyHStretch = 2, SubPropertyVSizePolicy = 4, SubPropertyVStretch = 8 }; +enum AlignmentSubPropertyMask { SubPropertyHorizontalAlignment = 1, SubPropertyVerticalAlignment = 2 }; +enum StringSubPropertyMask { SubPropertyStringValue = 1, SubPropertyStringComment = 2, SubPropertyStringTranslatable = 4, SubPropertyStringDisambiguation = 8 }; +enum KeySequenceSubPropertyMask { SubPropertyKeySequenceValue = 1, SubPropertyKeySequenceComment = 2, SubPropertyKeySequenceTranslatable = 4, SubPropertyKeySequenceDisambiguation = 8 }; + +enum CommonSubPropertyMask { SubPropertyAll = 0xFFFFFFFF }; + +// Set the mask flag in mask if the properties do not match. +#define COMPARE_SUBPROPERTY(object1, object2, getter, mask, maskFlag) if (object1.getter() != object2.getter()) mask |= maskFlag; + +// find changed subproperties of a rectangle +unsigned compareSubProperties(const QRect & r1, const QRect & r2) +{ + unsigned rc = 0; + COMPARE_SUBPROPERTY(r1, r2, x, rc, SubPropertyX) + COMPARE_SUBPROPERTY(r1, r2, y, rc, SubPropertyY) + COMPARE_SUBPROPERTY(r1, r2, width, rc, SubPropertyWidth) + COMPARE_SUBPROPERTY(r1, r2, height, rc, SubPropertyHeight) + return rc; +} + +// find changed subproperties of a QSize +unsigned compareSubProperties(const QSize & r1, const QSize & r2) +{ + unsigned rc = 0; + COMPARE_SUBPROPERTY(r1, r2, width, rc, SubPropertyWidth) + COMPARE_SUBPROPERTY(r1, r2, height, rc, SubPropertyHeight) + return rc; +} +// find changed subproperties of a QSizePolicy +unsigned compareSubProperties(const QSizePolicy & sp1, const QSizePolicy & sp2) +{ + unsigned rc = 0; + COMPARE_SUBPROPERTY(sp1, sp2, horizontalPolicy, rc, SubPropertyHSizePolicy) + COMPARE_SUBPROPERTY(sp1, sp2, horizontalStretch, rc, SubPropertyHStretch) + COMPARE_SUBPROPERTY(sp1, sp2, verticalPolicy, rc, SubPropertyVSizePolicy) + COMPARE_SUBPROPERTY(sp1, sp2, verticalStretch, rc, SubPropertyVStretch) + return rc; +} +// find changed subproperties of qdesigner_internal::PropertySheetStringValue +unsigned compareSubProperties(const qdesigner_internal::PropertySheetStringValue & str1, const qdesigner_internal::PropertySheetStringValue & str2) +{ + unsigned rc = 0; + COMPARE_SUBPROPERTY(str1, str2, value, rc, SubPropertyStringValue) + COMPARE_SUBPROPERTY(str1, str2, comment, rc, SubPropertyStringComment) + COMPARE_SUBPROPERTY(str1, str2, translatable, rc, SubPropertyStringTranslatable) + COMPARE_SUBPROPERTY(str1, str2, disambiguation, rc, SubPropertyStringDisambiguation) + return rc; +} +// find changed subproperties of qdesigner_internal::PropertySheetKeySequenceValue +unsigned compareSubProperties(const qdesigner_internal::PropertySheetKeySequenceValue & str1, const qdesigner_internal::PropertySheetKeySequenceValue & str2) +{ + unsigned rc = 0; + COMPARE_SUBPROPERTY(str1, str2, value, rc, SubPropertyKeySequenceValue) + COMPARE_SUBPROPERTY(str1, str2, comment, rc, SubPropertyKeySequenceComment) + COMPARE_SUBPROPERTY(str1, str2, translatable, rc, SubPropertyKeySequenceTranslatable) + COMPARE_SUBPROPERTY(str1, str2, disambiguation, rc, SubPropertyKeySequenceDisambiguation) + return rc; +} + +// Compare font-subproperties taking the [undocumented] +// resolve flag into account +template +void compareFontSubProperty(const QFont & f1, + const QFont & f2, + Property (QFont::*getter) () const, + unsigned maskBit, + unsigned &mask) +{ + const bool f1Changed = f1.resolve() & maskBit; + const bool f2Changed = f2.resolve() & maskBit; + // Role has been set/reset in editor + if (f1Changed != f2Changed) { + mask |= maskBit; + } else { + // Was modified in both palettes: Compare values. + if (f1Changed && f2Changed && (f1.*getter)() != (f2.*getter)()) + mask |= maskBit; + } +} +// find changed subproperties of a QFont +unsigned compareSubProperties(const QFont & f1, const QFont & f2) +{ + unsigned rc = 0; + compareFontSubProperty(f1, f2, &QFont::family, QFont::FamilyResolved, rc); + compareFontSubProperty(f1, f2, &QFont::pointSize, QFont::SizeResolved, rc); + compareFontSubProperty(f1, f2, &QFont::bold, QFont::WeightResolved, rc); + compareFontSubProperty(f1, f2, &QFont::italic, QFont::StyleResolved, rc); + compareFontSubProperty(f1, f2, &QFont::underline, QFont::UnderlineResolved, rc); + compareFontSubProperty(f1, f2, &QFont::strikeOut, QFont::StrikeOutResolved, rc); + compareFontSubProperty(f1, f2, &QFont::kerning, QFont::KerningResolved, rc); + compareFontSubProperty(f1, f2, &QFont::styleStrategy, QFont::StyleStrategyResolved, rc); + if (debugPropertyCommands) + qDebug() << "compareSubProperties " << fontString(f1) << fontString(f2) << "\n\treturns " << fontMask(rc); + return rc; +} + +// Compare colors of a role +bool roleColorChanged(const QPalette & p1, const QPalette & p2, QPalette::ColorRole role) +{ + for (int group = QPalette::Active; group < QPalette::NColorGroups; group++) { + const QPalette::ColorGroup pgroup = static_cast(group); + if (p1.color(pgroup, role) != p2.color(pgroup, role)) + return true; + } + return false; +} +// find changed subproperties of a QPalette taking the [undocumented] resolve flags into account +unsigned compareSubProperties(const QPalette & p1, const QPalette & p2) +{ + unsigned rc = 0; + unsigned maskBit = 1u; + // generate a mask for each role + const unsigned p1Changed = p1.resolve(); + const unsigned p2Changed = p2.resolve(); + for (int role = QPalette::WindowText; role < QPalette::NColorRoles; role++, maskBit <<= 1u) { + const bool p1RoleChanged = p1Changed & maskBit; + const bool p2RoleChanged = p2Changed & maskBit; + // Role has been set/reset in editor + if (p1RoleChanged != p2RoleChanged) { + rc |= maskBit; + } else { + // Was modified in both palettes: Compare values. + if (p1RoleChanged && p2RoleChanged && roleColorChanged(p1, p2, static_cast(role))) + rc |= maskBit; + } + } + return rc; +} + +// find changed subproperties of a QAlignment which is a flag combination of vertical and horizontal + +unsigned compareSubProperties(Qt::Alignment a1, Qt::Alignment a2) +{ + unsigned rc = 0; + if ((a1 & Qt::AlignHorizontal_Mask) != (a2 & Qt::AlignHorizontal_Mask)) + rc |= SubPropertyHorizontalAlignment; + if ((a1 & Qt::AlignVertical_Mask) != (a2 & Qt::AlignVertical_Mask)) + rc |= SubPropertyVerticalAlignment; + return rc; +} + +Qt::Alignment variantToAlignment(const QVariant & q) +{ + return Qt::Alignment(qdesigner_internal::Utils::valueOf(q)); +} +// find changed subproperties of a variant +unsigned compareSubProperties(const QVariant & q1, const QVariant & q2, qdesigner_internal::SpecialProperty specialProperty) +{ + // Do not clobber new value in the comparison function in + // case someone sets a QString on a PropertySheetStringValue. + if (q1.type() != q2.type()) + return SubPropertyAll; + switch (q1.type()) { + case QVariant::Rect: + return compareSubProperties(q1.toRect(), q2.toRect()); + case QVariant::Size: + return compareSubProperties(q1.toSize(), q2.toSize()); + case QVariant::SizePolicy: + return compareSubProperties(qvariant_cast(q1), qvariant_cast(q2)); + case QVariant::Font: + return compareSubProperties(qvariant_cast(q1), qvariant_cast(q2)); + case QVariant::Palette: + return compareSubProperties(qvariant_cast(q1), qvariant_cast(q2)); + default: + if (q1.userType() == qMetaTypeId()) + return qvariant_cast(q1).compare(qvariant_cast(q2)); + else if (q1.userType() == qMetaTypeId()) + return compareSubProperties(qvariant_cast(q1), qvariant_cast(q2)); + else if (q1.userType() == qMetaTypeId()) + return compareSubProperties(qvariant_cast(q1), qvariant_cast(q2)); + // Enumerations, flags + switch (specialProperty) { + case qdesigner_internal::SP_Alignment: + return compareSubProperties(variantToAlignment(q1), variantToAlignment(q2)); + default: + break; + } + break; + } + return SubPropertyAll; +} + +// Apply the sub property if mask flag is set in mask +#define SET_SUBPROPERTY(rc, newValue, getter, setter, mask, maskFlag) if (mask & maskFlag) rc.setter(newValue.getter()); + +// apply changed subproperties to a rectangle +QRect applyRectSubProperty(const QRect &oldValue, const QRect &newValue, unsigned mask) +{ + QRect rc = oldValue; + SET_SUBPROPERTY(rc, newValue, x, moveLeft, mask, SubPropertyX) + SET_SUBPROPERTY(rc, newValue, y, moveTop, mask, SubPropertyY) + SET_SUBPROPERTY(rc, newValue, width, setWidth, mask, SubPropertyWidth) + SET_SUBPROPERTY(rc, newValue, height, setHeight, mask, SubPropertyHeight) + return rc; +} + + +// apply changed subproperties to a rectangle QSize +QSize applySizeSubProperty(const QSize &oldValue, const QSize &newValue, unsigned mask) +{ + QSize rc = oldValue; + SET_SUBPROPERTY(rc, newValue, width, setWidth, mask, SubPropertyWidth) + SET_SUBPROPERTY(rc, newValue, height, setHeight, mask, SubPropertyHeight) + return rc; +} + + +// apply changed subproperties to a SizePolicy +QSizePolicy applySizePolicySubProperty(const QSizePolicy &oldValue, const QSizePolicy &newValue, unsigned mask) +{ + QSizePolicy rc = oldValue; + SET_SUBPROPERTY(rc, newValue, horizontalPolicy, setHorizontalPolicy, mask, SubPropertyHSizePolicy) + SET_SUBPROPERTY(rc, newValue, horizontalStretch, setHorizontalStretch, mask, SubPropertyHStretch) + SET_SUBPROPERTY(rc, newValue, verticalPolicy, setVerticalPolicy, mask, SubPropertyVSizePolicy) + SET_SUBPROPERTY(rc, newValue, verticalStretch, setVerticalStretch, mask, SubPropertyVStretch) + return rc; +} + +// apply changed subproperties to a qdesigner_internal::PropertySheetStringValue +qdesigner_internal::PropertySheetStringValue applyStringSubProperty(const qdesigner_internal::PropertySheetStringValue &oldValue, + const qdesigner_internal::PropertySheetStringValue &newValue, unsigned mask) +{ + qdesigner_internal::PropertySheetStringValue rc = oldValue; + SET_SUBPROPERTY(rc, newValue, value, setValue, mask, SubPropertyStringValue) + SET_SUBPROPERTY(rc, newValue, comment, setComment, mask, SubPropertyStringComment) + SET_SUBPROPERTY(rc, newValue, translatable, setTranslatable, mask, SubPropertyStringTranslatable) + SET_SUBPROPERTY(rc, newValue, disambiguation, setDisambiguation, mask, SubPropertyStringDisambiguation) + return rc; +} + +// apply changed subproperties to a qdesigner_internal::PropertySheetKeySequenceValue +qdesigner_internal::PropertySheetKeySequenceValue applyKeySequenceSubProperty(const qdesigner_internal::PropertySheetKeySequenceValue &oldValue, + const qdesigner_internal::PropertySheetKeySequenceValue &newValue, unsigned mask) +{ + qdesigner_internal::PropertySheetKeySequenceValue rc = oldValue; + SET_SUBPROPERTY(rc, newValue, value, setValue, mask, SubPropertyKeySequenceValue) + SET_SUBPROPERTY(rc, newValue, comment, setComment, mask, SubPropertyKeySequenceComment) + SET_SUBPROPERTY(rc, newValue, translatable, setTranslatable, mask, SubPropertyKeySequenceTranslatable) + SET_SUBPROPERTY(rc, newValue, disambiguation, setDisambiguation, mask, SubPropertyKeySequenceDisambiguation) + return rc; +} + +// Apply the font-subproperties keeping the [undocumented] +// resolve flag in sync (note that PropertySetterType might be something like const T&). +template +inline void setFontSubProperty(unsigned mask, + const QFont &newValue, + unsigned maskBit, + PropertyReturnType (QFont::*getter) () const, + void (QFont::*setter) (PropertySetterType), + QFont &value) +{ + if (mask & maskBit) { + (value.*setter)((newValue.*getter)()); + // Set the resolve bit from NewValue in return value + uint r = value.resolve(); + const bool origFlag = newValue.resolve() & maskBit; + if (origFlag) + r |= maskBit; + else + r &= ~maskBit; + value.resolve(r); + if (debugPropertyCommands) + qDebug() << "setFontSubProperty " << fontMask(maskBit) << " resolve=" << origFlag; + } +} +// apply changed subproperties to a QFont +QFont applyFontSubProperty(const QFont &oldValue, const QFont &newValue, unsigned mask) +{ + QFont rc = oldValue; + setFontSubProperty(mask, newValue, QFont::FamilyResolved, &QFont::family, &QFont::setFamily, rc); + setFontSubProperty(mask, newValue, QFont::SizeResolved, &QFont::pointSize, &QFont::setPointSize, rc); + setFontSubProperty(mask, newValue, QFont::WeightResolved, &QFont::bold, &QFont::setBold, rc); + setFontSubProperty(mask, newValue, QFont::StyleResolved, &QFont::italic, &QFont::setItalic, rc); + setFontSubProperty(mask, newValue, QFont::UnderlineResolved, &QFont::underline, &QFont::setUnderline, rc); + setFontSubProperty(mask, newValue, QFont::StrikeOutResolved, &QFont::strikeOut, &QFont::setStrikeOut, rc); + setFontSubProperty(mask, newValue, QFont::KerningResolved, &QFont::kerning, &QFont::setKerning, rc); + setFontSubProperty(mask, newValue, QFont::StyleStrategyResolved, &QFont::styleStrategy, &QFont::setStyleStrategy, rc); + if (debugPropertyCommands) + qDebug() << "applyFontSubProperty old " << fontMask(oldValue.resolve()) << " new " << fontMask(newValue.resolve()) << " return: " << fontMask(rc.resolve()); + return rc; +} + +// apply changed subproperties to a QPalette +QPalette applyPaletteSubProperty(const QPalette &oldValue, const QPalette &newValue, unsigned mask) +{ + QPalette rc = oldValue; + // apply a mask for each role + unsigned maskBit = 1u; + for (int role = QPalette::WindowText; role < QPalette::NColorRoles; role++, maskBit <<= 1u) { + if (mask & maskBit) { + for (int group = QPalette::Active; group < QPalette::NColorGroups; group++) { + const QPalette::ColorGroup pgroup = static_cast(group); + const QPalette::ColorRole prole = static_cast(role); + rc.setColor(pgroup, prole, newValue.color(pgroup, prole)); + } + // Set the resolve bit from NewValue in return value + uint r = rc.resolve(); + const bool origFlag = newValue.resolve() & maskBit; + if (origFlag) + r |= maskBit; + else + r &= ~maskBit; + rc.resolve(r); + } + } + return rc; +} + +// apply changed subproperties to a QAlignment which is a flag combination of vertical and horizontal +Qt::Alignment applyAlignmentSubProperty(Qt::Alignment oldValue, Qt::Alignment newValue, unsigned mask) +{ + // easy: both changed. + if (mask == (SubPropertyHorizontalAlignment|SubPropertyVerticalAlignment)) + return newValue; + // Change subprop + const Qt::Alignment changeMask = (mask & SubPropertyHorizontalAlignment) ? Qt::AlignHorizontal_Mask : Qt::AlignVertical_Mask; + const Qt::Alignment takeOverMask = (mask & SubPropertyHorizontalAlignment) ? Qt::AlignVertical_Mask : Qt::AlignHorizontal_Mask; + return (oldValue & takeOverMask) | (newValue & changeMask); +} + +} + +namespace qdesigner_internal { + +// apply changed subproperties to a variant +PropertyHelper::Value applySubProperty(const QVariant &oldValue, const QVariant &newValue, qdesigner_internal::SpecialProperty specialProperty, unsigned mask, bool changed) +{ + if (mask == SubPropertyAll) + return PropertyHelper::Value(newValue, changed); + + switch (oldValue.type()) { + case QVariant::Rect: + return PropertyHelper::Value(applyRectSubProperty(oldValue.toRect(), newValue.toRect(), mask), changed); + case QVariant::Size: + return PropertyHelper::Value(applySizeSubProperty(oldValue.toSize(), newValue.toSize(), mask), changed); + case QVariant::SizePolicy: + return PropertyHelper::Value(QVariant::fromValue(applySizePolicySubProperty(qvariant_cast(oldValue), qvariant_cast(newValue), mask)), changed); + case QVariant::Font: { + // Changed flag in case of font and palette depends on resolve mask only, not on the passed "changed" value. + + // The first case: the user changed bold subproperty and then pressed reset button for this subproperty (not for + // the whole font property). We instantiate SetPropertyCommand passing changed=true. But in this case no + // subproperty is changed and the whole property should be marked an unchanged. + + // The second case: there are 2 pushbuttons, for 1st the user set bold and italic subproperties, + // for the 2nd he set bold only. He does multiselection so that the current widget is the 2nd one. + // He press reset next to bold subproperty. In result the 2nd widget should have the whole + // font property marked as unchanged and the 1st widget should have the font property + // marked as changed and only italic subproperty should be marked as changed (the bold should be reset). + + // The third case: there are 2 pushbuttons, for 1st the user set bold and italic subproperties, + // for the 2nd he set bold only. He does multiselection so that the current widget is the 2nd one. + // He press reset button for the whole font property. In result whole font properties for both + // widgets should be marked as unchanged. + QFont font = applyFontSubProperty(qvariant_cast(oldValue), qvariant_cast(newValue), mask); + return PropertyHelper::Value(QVariant::fromValue(font), font.resolve()); + } + case QVariant::Palette: { + QPalette palette = applyPaletteSubProperty(qvariant_cast(oldValue), qvariant_cast(newValue), mask); + return PropertyHelper::Value(QVariant::fromValue(palette), palette.resolve()); + } + default: + if (oldValue.userType() == qMetaTypeId()) { + PropertySheetIconValue icon = qvariant_cast(oldValue); + icon.assign(qvariant_cast(newValue), mask); + return PropertyHelper::Value(QVariant::fromValue(icon), icon.mask()); + } else if (oldValue.userType() == qMetaTypeId()) { + qdesigner_internal::PropertySheetStringValue str = applyStringSubProperty( + qvariant_cast(oldValue), + qvariant_cast(newValue), mask); + return PropertyHelper::Value(QVariant::fromValue(str), changed); + } else if (oldValue.userType() == qMetaTypeId()) { + qdesigner_internal::PropertySheetKeySequenceValue key = applyKeySequenceSubProperty( + qvariant_cast(oldValue), + qvariant_cast(newValue), mask); + return PropertyHelper::Value(QVariant::fromValue(key), changed); + } + // Enumerations, flags + switch (specialProperty) { + case qdesigner_internal::SP_Alignment: { + qdesigner_internal::PropertySheetFlagValue f = qvariant_cast(oldValue); + f.value = applyAlignmentSubProperty(variantToAlignment(oldValue), variantToAlignment(newValue), mask); + QVariant v; + v.setValue(f); + return PropertyHelper::Value(v, changed); + } + default: + break; + } + break; + } + return PropertyHelper::Value(newValue, changed); + +} +// figure out special property +enum SpecialProperty getSpecialProperty(const QString& propertyName) +{ + if (propertyName == QLatin1String("objectName")) + return SP_ObjectName; + if (propertyName == QLatin1String("layoutName")) + return SP_LayoutName; + if (propertyName == QLatin1String("spacerName")) + return SP_SpacerName; + if (propertyName == QLatin1String("icon")) + return SP_Icon; + if (propertyName == QLatin1String("currentTabName")) + return SP_CurrentTabName; + if (propertyName == QLatin1String("currentItemName")) + return SP_CurrentItemName; + if (propertyName == QLatin1String("currentPageName")) + return SP_CurrentPageName; + if (propertyName == QLatin1String("geometry")) + return SP_Geometry; + if (propertyName == QLatin1String("windowTitle")) + return SP_WindowTitle; + if (propertyName == QLatin1String("minimumSize")) + return SP_MinimumSize; + if (propertyName == QLatin1String("maximumSize")) + return SP_MaximumSize; + if (propertyName == QLatin1String("alignment")) + return SP_Alignment; + if (propertyName == QLatin1String("autoDefault")) + return SP_AutoDefault; + if (propertyName == QLatin1String("shortcut")) + return SP_Shortcut; + if (propertyName == QLatin1String("orientation")) + return SP_Orientation; + return SP_None; +} + + +PropertyHelper::PropertyHelper(QObject* object, + SpecialProperty specialProperty, + QDesignerPropertySheetExtension *sheet, + int index) : + m_specialProperty(specialProperty), + m_object(object), + m_objectType(OT_Object), + m_propertySheet(sheet), m_index(index), + m_oldValue(m_propertySheet->property(m_index), m_propertySheet->isChanged(m_index)) +{ + if (object->isWidgetType()) { + m_parentWidget = (qobject_cast(object))->parentWidget(); + m_objectType = OT_Widget; + } else { + if (const QAction *action = qobject_cast(m_object)) + m_objectType = action->associatedWidgets().empty() ? OT_FreeAction : OT_AssociatedAction; + } + + if(debugPropertyCommands) + qDebug() << "PropertyHelper on " << m_object->objectName() << " index= " << m_index << " type = " << m_objectType; +} + +QDesignerIntegration *PropertyHelper::integration(QDesignerFormWindowInterface *fw) const +{ + return qobject_cast(fw->core()->integration()); +} + +// Set widget value, apply corrections and checks in case of main window. +void PropertyHelper::checkApplyWidgetValue(QDesignerFormWindowInterface *fw, QWidget* w, + SpecialProperty specialProperty, QVariant &value) +{ + + bool isMainContainer = false; + if (QDesignerFormWindowCursorInterface *cursor = fw->cursor()) { + if (cursor->isWidgetSelected(w)) { + if (cursor->isWidgetSelected(fw->mainContainer())) { + isMainContainer = true; + } + } + } + if (!isMainContainer) + return; + + QWidget *container = fw->core()->integration()->containerWindow(fw); + if (!container) + return; + + + switch (specialProperty) { + case SP_MinimumSize: { + const QSize size = checkSize(value.toSize()); + value.setValue(size); + } + + break; + case SP_MaximumSize: { + QSize fs, cs; + checkSizes(fw, value.toSize(), &fs, &cs); + container->setMaximumSize(cs); + fw->mainContainer()->setMaximumSize(fs); + value.setValue(fs); + + } + break; + case SP_Geometry: { + QRect r = value.toRect(); + QSize fs, cs; + checkSizes(fw, r.size(), &fs, &cs); + container->resize(cs); + r.setSize(fs); + value.setValue(r); + } + break; + default: + break; + } +} + +unsigned PropertyHelper::updateMask() const +{ + unsigned rc = 0; + switch (m_specialProperty) { + case SP_ObjectName: + case SP_LayoutName: + case SP_SpacerName: + case SP_CurrentTabName: + case SP_CurrentItemName: + case SP_CurrentPageName: + if (m_objectType != OT_FreeAction) + rc |= UpdateObjectInspector; + break; + case SP_Icon: + if (m_objectType == OT_AssociatedAction) + rc |= UpdateObjectInspector; + break; + case SP_Orientation: // for updating splitter icon + rc |= UpdateObjectInspector; + break; + default: + break; + + } + return rc; +} + + +bool PropertyHelper::canMerge(const PropertyHelper &other) const +{ + return m_object == other.m_object && m_index == other.m_index; +} + +void PropertyHelper::triggerActionChanged(QAction *a) +{ + a->setData(QVariant(true)); // this triggers signal "changed" in QAction + a->setData(QVariant(false)); +} + +// Update the object to reflect the changes +void PropertyHelper::updateObject(QDesignerFormWindowInterface *fw, const QVariant &oldValue, const QVariant &newValue) +{ + if(debugPropertyCommands){ + qDebug() << "PropertyHelper::updateObject(" << m_object->objectName() << ") " << oldValue << " -> " << newValue; + } + switch (m_objectType) { + case OT_Widget: { + switch (m_specialProperty) { + case SP_ObjectName: { + const QString oldName = qvariant_cast(oldValue).value(); + const QString newName = qvariant_cast(newValue).value(); + QDesignerFormWindowCommand::updateBuddies(fw, oldName, newName); + } + break; + default: + break; + } + } break; + case OT_AssociatedAction: + case OT_FreeAction: + // SP_Shortcut is a fake property, so, QAction::changed does not trigger. + if (m_specialProperty == SP_ObjectName || m_specialProperty == SP_Shortcut) + triggerActionChanged(qobject_cast(m_object)); + break; + default: + break; + } + + switch (m_specialProperty) { + case SP_ObjectName: + case SP_LayoutName: + case SP_SpacerName: + if (QDesignerIntegration *integr = integration(fw)) { + const QString oldName = qvariant_cast(oldValue).value(); + const QString newName = qvariant_cast(newValue).value(); + integr->emitObjectNameChanged(fw, m_object, newName, oldName); + } + break; + default: + break; + } +} + +void PropertyHelper::ensureUniqueObjectName(QDesignerFormWindowInterface *fw, QObject *object) const +{ + switch (m_specialProperty) { + case SP_SpacerName: + if (object->isWidgetType()) { + if (Spacer *sp = qobject_cast(object)) { + fw->ensureUniqueObjectName(sp); + return; + } + } + fw->ensureUniqueObjectName(object); + break; + case SP_LayoutName: // Layout name is invoked on the parent widget. + if (object->isWidgetType()) { + const QWidget * w = qobject_cast(object); + if (QLayout *wlayout = w->layout()) { + fw->ensureUniqueObjectName(wlayout); + return; + } + } + fw->ensureUniqueObjectName(object); + break; + case SP_ObjectName: + fw->ensureUniqueObjectName(object); + break; + default: + break; + } +} + +PropertyHelper::Value PropertyHelper::setValue(QDesignerFormWindowInterface *fw, const QVariant &value, bool changed, unsigned subPropertyMask) +{ + // Set new whole value + if (subPropertyMask == SubPropertyAll) + return applyValue(fw, m_oldValue.first, Value(value, changed)); + + // apply subproperties + const PropertyHelper::Value maskedNewValue = applySubProperty(m_oldValue.first, value, m_specialProperty, subPropertyMask, changed); + return applyValue(fw, m_oldValue.first, maskedNewValue); +} + +// Apply the value and update. Returns corrected value +PropertyHelper::Value PropertyHelper::applyValue(QDesignerFormWindowInterface *fw, const QVariant &oldValue, Value newValue) +{ + if(debugPropertyCommands){ + qDebug() << "PropertyHelper::applyValue(" << m_object << ") " << oldValue << " -> " << newValue.first << " changed=" << newValue.second; + } + + if (m_objectType == OT_Widget) { + checkApplyWidgetValue(fw, qobject_cast(m_object), m_specialProperty, newValue.first); + } + + m_propertySheet->setProperty(m_index, newValue.first); + m_propertySheet->setChanged(m_index, newValue.second); + + switch (m_specialProperty) { + case SP_LayoutName: + case SP_ObjectName: + case SP_SpacerName: + ensureUniqueObjectName(fw, m_object); + newValue.first = m_propertySheet->property(m_index); + break; + default: + break; + } + + updateObject(fw, oldValue, newValue.first); + return newValue; +} + +PropertyHelper::Value PropertyHelper::restoreOldValue(QDesignerFormWindowInterface *fw) +{ + return applyValue(fw, m_propertySheet->property(m_index), m_oldValue); +} + +// find the default value in widget DB in case PropertySheet::reset fails +QVariant PropertyHelper::findDefaultValue(QDesignerFormWindowInterface *fw) const +{ + if (m_specialProperty == SP_AutoDefault && qobject_cast(m_object)) { + // AutoDefault defaults to true on dialogs + const bool isDialog = qobject_cast(fw->mainContainer()); + return QVariant(isDialog); + } + + const int item_idx = fw->core()->widgetDataBase()->indexOfObject(m_object); + if (item_idx == -1) + return m_oldValue.first; // We simply don't know the value in this case + + const QDesignerWidgetDataBaseItemInterface *item = fw->core()->widgetDataBase()->item(item_idx); + const QList default_prop_values = item->defaultPropertyValues(); + if (m_index < default_prop_values.size()) + return default_prop_values.at(m_index); + + if (m_oldValue.first.type() == QVariant::Color) + return QColor(); + + return m_oldValue.first; // Again, we just don't know +} + +PropertyHelper::Value PropertyHelper::restoreDefaultValue(QDesignerFormWindowInterface *fw) +{ + + Value defaultValue = qMakePair(QVariant(), false); + const QVariant currentValue = m_propertySheet->property(m_index); + // try to reset sheet, else try to find default + if (m_propertySheet->reset(m_index)) { + defaultValue.first = m_propertySheet->property(m_index); + } else { + defaultValue.first = findDefaultValue(fw); + m_propertySheet->setProperty(m_index, defaultValue.first); + } + + m_propertySheet->setChanged(m_index, defaultValue.second); + + if (m_objectType == OT_Widget) { + checkApplyWidgetValue(fw, qobject_cast(m_object), m_specialProperty, defaultValue.first); + } + + switch (m_specialProperty) { + case SP_LayoutName: + case SP_ObjectName: + case SP_SpacerName: + ensureUniqueObjectName(fw, m_object); + defaultValue.first = m_propertySheet->property(m_index); + break; + default: + break; + } + + updateObject(fw, currentValue, defaultValue.first); + return defaultValue; +} + +// ---- PropertyListCommand::PropertyDescription( + + +PropertyListCommand::PropertyDescription::PropertyDescription(const QString &propertyName, + QDesignerPropertySheetExtension *propertySheet, + int index) : + m_propertyName(propertyName), + m_propertyGroup(propertySheet->propertyGroup(index)), + m_propertyType(propertySheet->property(index).type()), + m_specialProperty(getSpecialProperty(propertyName)) +{ +} + +PropertyListCommand::PropertyDescription::PropertyDescription() : + m_propertyType(QVariant::Invalid), + m_specialProperty(SP_None) +{ +} + +void PropertyListCommand::PropertyDescription::debug() const +{ + qDebug() << m_propertyName << m_propertyGroup << m_propertyType << m_specialProperty; +} + +bool PropertyListCommand::PropertyDescription::equals(const PropertyDescription &p) const +{ + return m_propertyType == p.m_propertyType && m_specialProperty == p.m_specialProperty && + m_propertyName == p.m_propertyName && m_propertyGroup == p.m_propertyGroup; +} + + +// ---- PropertyListCommand +PropertyListCommand::PropertyListCommand(QDesignerFormWindowInterface *formWindow, + QUndoCommand *parent) : + QDesignerFormWindowCommand(QString(), formWindow, parent) +{ +} + +const QString PropertyListCommand::propertyName() const +{ + return m_propertyDescription.m_propertyName; +} + +SpecialProperty PropertyListCommand::specialProperty() const +{ + return m_propertyDescription.m_specialProperty; +} + +// add an object +bool PropertyListCommand::add(QObject *object, const QString &propertyName) +{ + QDesignerPropertySheetExtension* sheet = propertySheet(object); + Q_ASSERT(sheet); + + const int index = sheet->indexOf(propertyName); + if (index == -1) + return false; + + if (QDesignerPropertySheet *exSheet = qobject_cast(core()->extensionManager()->extension(object, Q_TYPEID(QDesignerPropertySheetExtension)))) + if (!exSheet->isEnabled(index)) + return false; + + const PropertyDescription description(propertyName, sheet, index); + + if (m_propertyHelperList.empty()) { + // first entry + m_propertyDescription = description; + } else { + // checks: mismatch or only one object in case of name + const bool match = m_propertyDescription.equals(description); + if (!match || m_propertyDescription.m_specialProperty == SP_ObjectName) + return false; + } + + const PropertyHelperPtr ph(createPropertyHelper(object, m_propertyDescription.m_specialProperty, sheet, index)); + m_propertyHelperList.push_back(ph); + return true; +} + +PropertyHelper *PropertyListCommand::createPropertyHelper(QObject *object, SpecialProperty sp, + QDesignerPropertySheetExtension *sheet, int sheetIndex) const +{ + return new PropertyHelper(object, sp, sheet, sheetIndex); +} + +// Init from a list and make sure referenceObject is added first to obtain the right property group +bool PropertyListCommand::initList(const ObjectList &list, const QString &apropertyName, QObject *referenceObject) +{ + propertyHelperList().clear(); + + // Ensure the referenceObject (property editor) is first, so the right property group is chosen. + if (referenceObject) { + if (!add(referenceObject, apropertyName)) + return false; + } + foreach (QObject *o, list) { + if (o != referenceObject) + add(o, apropertyName); + } + + return !propertyHelperList().empty(); +} + + +QObject* PropertyListCommand::object(int index) const +{ + Q_ASSERT(index < m_propertyHelperList.size()); + return m_propertyHelperList.at(index)->object(); +} + +QVariant PropertyListCommand::oldValue(int index) const +{ + Q_ASSERT(index < m_propertyHelperList.size()); + return m_propertyHelperList.at(index)->oldValue(); +} + +void PropertyListCommand::setOldValue(const QVariant &oldValue, int index) +{ + Q_ASSERT(index < m_propertyHelperList.size()); + m_propertyHelperList.at(index)->setOldValue(oldValue); +} +// ----- SetValueFunction: Set a new value when applied to a PropertyHelper. +class SetValueFunction { +public: + SetValueFunction(QDesignerFormWindowInterface *formWindow, const PropertyHelper::Value &newValue, unsigned subPropertyMask); + + PropertyHelper::Value operator()(PropertyHelper&); +private: + QDesignerFormWindowInterface *m_formWindow; + const PropertyHelper::Value m_newValue; + const unsigned m_subPropertyMask; +}; + + +SetValueFunction::SetValueFunction(QDesignerFormWindowInterface *formWindow, const PropertyHelper::Value &newValue, unsigned subPropertyMask) : + m_formWindow(formWindow), + m_newValue(newValue), + m_subPropertyMask(subPropertyMask) +{ +} + +PropertyHelper::Value SetValueFunction::operator()(PropertyHelper &ph) { + return ph.setValue(m_formWindow, m_newValue.first, m_newValue.second, m_subPropertyMask); +} + +// ----- UndoSetValueFunction: Restore old value when applied to a PropertyHelper. +class UndoSetValueFunction { +public: + UndoSetValueFunction(QDesignerFormWindowInterface *formWindow) : m_formWindow(formWindow) {} + PropertyHelper::Value operator()(PropertyHelper& ph) { return ph.restoreOldValue(m_formWindow); } +private: + QDesignerFormWindowInterface *m_formWindow; +}; + +// ----- RestoreDefaultFunction: Restore default value when applied to a PropertyHelper. +class RestoreDefaultFunction { +public: + RestoreDefaultFunction(QDesignerFormWindowInterface *formWindow) : m_formWindow(formWindow) {} + PropertyHelper::Value operator()(PropertyHelper& ph) { return ph.restoreDefaultValue(m_formWindow); } +private: + QDesignerFormWindowInterface *m_formWindow; +}; + +// ----- changePropertyList: Iterates over a sequence of PropertyHelpers and +// applies a function to them. +// The function returns the corrected value which is then set in the property editor. +// Returns a combination of update flags. +template + unsigned changePropertyList(QDesignerFormEditorInterface *core, + const QString &propertyName, + PropertyListIterator begin, + PropertyListIterator end, + Function function) +{ + unsigned updateMask = 0; + QDesignerPropertyEditorInterface *propertyEditor = core->propertyEditor(); + bool updatedPropertyEditor = false; + + for (PropertyListIterator it = begin; it != end; ++it) { + PropertyHelper *ph = it->data(); + if (QObject* object = ph->object()) { // Might have been deleted in the meantime + const PropertyHelper::Value newValue = function( *ph ); + updateMask |= ph->updateMask(); + // Update property editor if it is the current object + if (!updatedPropertyEditor && propertyEditor && object == propertyEditor->object()) { + propertyEditor->setPropertyValue(propertyName, newValue.first, newValue.second); + updatedPropertyEditor = true; + } + } + } + if (!updatedPropertyEditor) updateMask |= PropertyHelper::UpdatePropertyEditor; + return updateMask; +} + + +// set a new value, return update mask +unsigned PropertyListCommand::setValue(QVariant value, bool changed, unsigned subPropertyMask) +{ + if(debugPropertyCommands) + qDebug() << "PropertyListCommand::setValue(" << value + << changed << subPropertyMask << ')'; + return changePropertyList(formWindow()->core(), + m_propertyDescription.m_propertyName, + m_propertyHelperList.begin(), m_propertyHelperList.end(), + SetValueFunction(formWindow(), PropertyHelper::Value(value, changed), subPropertyMask)); +} + +// restore old value, return update mask +unsigned PropertyListCommand::restoreOldValue() +{ + if(debugPropertyCommands) + qDebug() << "PropertyListCommand::restoreOldValue()"; + + return changePropertyList(formWindow()->core(), + m_propertyDescription.m_propertyName, m_propertyHelperList.begin(), m_propertyHelperList.end(), + UndoSetValueFunction(formWindow())); +} +// set default value, return update mask +unsigned PropertyListCommand::restoreDefaultValue() +{ + if(debugPropertyCommands) + qDebug() << "PropertyListCommand::restoreDefaultValue()"; + + return changePropertyList(formWindow()->core(), + m_propertyDescription.m_propertyName, m_propertyHelperList.begin(), m_propertyHelperList.end(), + RestoreDefaultFunction(formWindow())); +} + +// update +void PropertyListCommand::update(unsigned updateMask) +{ + if(debugPropertyCommands) + qDebug() << "PropertyListCommand::update(" << updateMask << ')'; + + if (updateMask & PropertyHelper::UpdateObjectInspector) { + if (QDesignerObjectInspectorInterface *oi = formWindow()->core()->objectInspector()) + oi->setFormWindow(formWindow()); + } + + if (updateMask & PropertyHelper::UpdatePropertyEditor) { + // this is needed when f.ex. undo, changes parent's palette, but + // the child is the active widget, + // TODO: current object? + if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) { + propertyEditor->setObject(propertyEditor->object()); + } + } +} + +void PropertyListCommand::undo() +{ + update(restoreOldValue()); + QDesignerPropertyEditor *designerPropertyEditor = qobject_cast(core()->propertyEditor()); + if (designerPropertyEditor) + designerPropertyEditor->updatePropertySheet(); +} + +// check if lists are aequivalent for command merging (same widgets and props) +bool PropertyListCommand::canMergeLists(const PropertyHelperList& other) const +{ + if (m_propertyHelperList.size() != other.size()) + return false; + for (int i = 0; i < m_propertyHelperList.size(); i++) { + if (!m_propertyHelperList.at(i)->canMerge(*other.at(i))) + return false; + } + return true; +} + +// ---- SetPropertyCommand ---- +SetPropertyCommand::SetPropertyCommand(QDesignerFormWindowInterface *formWindow, + QUndoCommand *parent) + : PropertyListCommand(formWindow, parent), + m_subPropertyMask(SubPropertyAll) +{ +} + +bool SetPropertyCommand::init(QObject *object, const QString &apropertyName, const QVariant &newValue) +{ + Q_ASSERT(object); + + m_newValue = newValue; + + propertyHelperList().clear(); + if (!add(object, apropertyName)) + return false; + + setDescription(); + return true; +} + +bool SetPropertyCommand::init(const ObjectList &list, const QString &apropertyName, const QVariant &newValue, + QObject *referenceObject, bool enableSubPropertyHandling) +{ + if (!initList(list, apropertyName, referenceObject)) + return false; + + m_newValue = newValue; + + if(debugPropertyCommands) + qDebug() << "SetPropertyCommand::init()" << propertyHelperList().size() << '/' << list.size() << " reference " << referenceObject; + + setDescription(); + + if (enableSubPropertyHandling) + m_subPropertyMask = subPropertyMask(newValue, referenceObject); + return true; +} + +unsigned SetPropertyCommand::subPropertyMask(const QVariant &newValue, QObject *referenceObject) +{ + // figure out the mask of changed sub properties when comparing newValue to the current value of the reference object. + if (!referenceObject) + return SubPropertyAll; + + QDesignerPropertySheetExtension* sheet = propertySheet(referenceObject); + Q_ASSERT(sheet); + + const int index = sheet->indexOf(propertyName()); + if (index == -1 || !sheet->isVisible(index)) + return SubPropertyAll; + + return compareSubProperties(sheet->property(index), newValue, specialProperty()); +} + +void SetPropertyCommand::setDescription() +{ + if (propertyHelperList().size() == 1) { + setText(QApplication::translate("Command", "Changed '%1' of '%2'").arg(propertyName()).arg(propertyHelperList().at(0)->object()->objectName())); + } else { + int count = propertyHelperList().size(); + setText(QApplication::translate("Command", "Changed '%1' of %n objects", "", QCoreApplication::UnicodeUTF8, count).arg(propertyName())); + } +} + +void SetPropertyCommand::redo() +{ + update(setValue(m_newValue, true, m_subPropertyMask)); + QDesignerPropertyEditor *designerPropertyEditor = qobject_cast(core()->propertyEditor()); + if (designerPropertyEditor) + designerPropertyEditor->updatePropertySheet(); +} + + +int SetPropertyCommand::id() const +{ + return 1976; +} + +QVariant SetPropertyCommand::mergeValue(const QVariant &newValue) +{ + return newValue; +} + +bool SetPropertyCommand::mergeWith(const QUndoCommand *other) +{ + if (id() != other->id() || !formWindow()->isDirty()) + return false; + + // Merging: When for example when the user types ahead in an inplace-editor, + // it makes sense to merge all the generated commands containing the one-character changes. + // In the case of subproperties, if the user changes the font size from 10 to 30 via 20 + // and then changes to bold, it makes sense to merge the font size commands only. + // This is why the m_subPropertyMask is checked. + + const SetPropertyCommand *cmd = static_cast(other); + if (!propertyDescription().equals(cmd->propertyDescription()) || + m_subPropertyMask != cmd->m_subPropertyMask || + !canMergeLists(cmd->propertyHelperList())) + return false; + + const QVariant newValue = mergeValue(cmd->newValue()); + if (!newValue.isValid()) + return false; + m_newValue = newValue; + m_subPropertyMask |= cmd->m_subPropertyMask; + if(debugPropertyCommands) + qDebug() << "SetPropertyCommand::mergeWith() succeeded " << propertyName(); + + return true; +} + +// ---- ResetPropertyCommand ---- +ResetPropertyCommand::ResetPropertyCommand(QDesignerFormWindowInterface *formWindow) + : PropertyListCommand(formWindow) +{ +} + +bool ResetPropertyCommand::init(QObject *object, const QString &apropertyName) +{ + Q_ASSERT(object); + + propertyHelperList().clear(); + if (!add(object, apropertyName)) + return false; + + setDescription(); + return true; +} + +bool ResetPropertyCommand::init(const ObjectList &list, const QString &apropertyName, QObject *referenceObject) +{ + if (!initList(list, apropertyName, referenceObject)) + return false; + + if(debugPropertyCommands) + qDebug() << "ResetPropertyCommand::init()" << propertyHelperList().size() << '/' << list.size(); + + setDescription(); + return true; +} + +void ResetPropertyCommand::setDescription() +{ + if (propertyHelperList().size() == 1) { + setText(QApplication::translate("Command", "Reset '%1' of '%2'").arg(propertyName()).arg(propertyHelperList().at(0)->object()->objectName())); + } else { + int count = propertyHelperList().size(); + setText(QApplication::translate("Command", "Reset '%1' of %n objects", "", QCoreApplication::UnicodeUTF8, count).arg(propertyName())); + } +} + +void ResetPropertyCommand::redo() +{ + update(restoreDefaultValue()); + QDesignerPropertyEditor *designerPropertyEditor = qobject_cast(core()->propertyEditor()); + if (designerPropertyEditor) + designerPropertyEditor->updatePropertySheet(); +} + +AddDynamicPropertyCommand::AddDynamicPropertyCommand(QDesignerFormWindowInterface *formWindow) + : QDesignerFormWindowCommand(QString(), formWindow) +{ + +} + +bool AddDynamicPropertyCommand::init(const QList &selection, QObject *current, + const QString &propertyName, const QVariant &value) +{ + Q_ASSERT(current); + m_propertyName = propertyName; + + QDesignerFormEditorInterface *core = formWindow()->core(); + QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension(core->extensionManager(), current); + Q_ASSERT(dynamicSheet); + + m_selection.clear(); + + if (!value.isValid()) + return false; + + if (!dynamicSheet->canAddDynamicProperty(m_propertyName)) + return false; + + m_selection.append(current); + + m_value = value; + + QListIterator it(selection); + while (it.hasNext()) { + QObject *obj = it.next(); + if (m_selection.contains(obj)) + continue; + dynamicSheet = qt_extension(core->extensionManager(), obj); + Q_ASSERT(dynamicSheet); + if (dynamicSheet->canAddDynamicProperty(m_propertyName)) + m_selection.append(obj); + } + + setDescription(); + return true; +} + +void AddDynamicPropertyCommand::redo() +{ + QDesignerFormEditorInterface *core = formWindow()->core(); + QListIterator it(m_selection); + while (it.hasNext()) { + QObject *obj = it.next(); + QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension(core->extensionManager(), obj); + dynamicSheet->addDynamicProperty(m_propertyName, m_value); + if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) { + if (propertyEditor->object() == obj) + propertyEditor->setObject(obj); + } + } +} + +void AddDynamicPropertyCommand::undo() +{ + QDesignerFormEditorInterface *core = formWindow()->core(); + QListIterator it(m_selection); + while (it.hasNext()) { + QObject *obj = it.next(); + QDesignerPropertySheetExtension *sheet = qt_extension(core->extensionManager(), obj); + QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension(core->extensionManager(), obj); + dynamicSheet->removeDynamicProperty(sheet->indexOf(m_propertyName)); + if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) { + if (propertyEditor->object() == obj) + propertyEditor->setObject(obj); + } + } +} + +void AddDynamicPropertyCommand::setDescription() +{ + if (m_selection.size() == 1) { + setText(QApplication::translate("Command", "Add dynamic property '%1' to '%2'").arg(m_propertyName).arg(m_selection.first()->objectName())); + } else { + int count = m_selection.size(); + setText(QApplication::translate("Command", "Add dynamic property '%1' to %n objects", "", QCoreApplication::UnicodeUTF8, count).arg(m_propertyName)); + } +} + + +RemoveDynamicPropertyCommand::RemoveDynamicPropertyCommand(QDesignerFormWindowInterface *formWindow) + : QDesignerFormWindowCommand(QString(), formWindow) +{ + +} + +bool RemoveDynamicPropertyCommand::init(const QList &selection, QObject *current, + const QString &propertyName) +{ + Q_ASSERT(current); + m_propertyName = propertyName; + + QDesignerFormEditorInterface *core = formWindow()->core(); + QDesignerPropertySheetExtension *propertySheet = qt_extension(core->extensionManager(), current); + Q_ASSERT(propertySheet); + QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension(core->extensionManager(), current); + Q_ASSERT(dynamicSheet); + + m_objectToValueAndChanged.clear(); + + const int index = propertySheet->indexOf(m_propertyName); + if (!dynamicSheet->isDynamicProperty(index)) + return false; + + m_objectToValueAndChanged[current] = qMakePair(propertySheet->property(index), propertySheet->isChanged(index)); + + QListIterator it(selection); + while (it.hasNext()) { + QObject *obj = it.next(); + if (m_objectToValueAndChanged.contains(obj)) + continue; + + propertySheet = qt_extension(core->extensionManager(), obj); + dynamicSheet = qt_extension(core->extensionManager(), obj); + const int idx = propertySheet->indexOf(m_propertyName); + if (dynamicSheet->isDynamicProperty(idx)) + m_objectToValueAndChanged[obj] = qMakePair(propertySheet->property(idx), propertySheet->isChanged(idx)); + } + + setDescription(); + return true; +} + +void RemoveDynamicPropertyCommand::redo() +{ + QDesignerFormEditorInterface *core = formWindow()->core(); + QMap >::ConstIterator it = m_objectToValueAndChanged.constBegin(); + while (it != m_objectToValueAndChanged.constEnd()) { + QObject *obj = it.key(); + QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension(core->extensionManager(), obj); + QDesignerPropertySheetExtension *sheet = qt_extension(core->extensionManager(), obj); + dynamicSheet->removeDynamicProperty(sheet->indexOf(m_propertyName)); + if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) { + if (propertyEditor->object() == obj) + propertyEditor->setObject(obj); + } + ++it; + } +} + +void RemoveDynamicPropertyCommand::undo() +{ + QDesignerFormEditorInterface *core = formWindow()->core(); + QMap >::ConstIterator it = m_objectToValueAndChanged.constBegin(); + while (it != m_objectToValueAndChanged.constEnd()) { + QObject *obj = it.key(); + QDesignerPropertySheetExtension *propertySheet = qt_extension(core->extensionManager(), obj); + QDesignerDynamicPropertySheetExtension *dynamicSheet = qt_extension(core->extensionManager(), obj); + const int index = dynamicSheet->addDynamicProperty(m_propertyName, it.value().first); + propertySheet->setChanged(index, it.value().second); + if (QDesignerPropertyEditorInterface *propertyEditor = formWindow()->core()->propertyEditor()) { + if (propertyEditor->object() == obj) + propertyEditor->setObject(obj); + } + ++it; + } +} + +void RemoveDynamicPropertyCommand::setDescription() +{ + if (m_objectToValueAndChanged.size() == 1) { + setText(QApplication::translate("Command", "Remove dynamic property '%1' from '%2'").arg(m_propertyName).arg(m_objectToValueAndChanged.constBegin().key()->objectName())); + } else { + int count = m_objectToValueAndChanged.size(); + setText(QApplication::translate("Command", "Remove dynamic property '%1' from %n objects", "", QCoreApplication::UnicodeUTF8, count).arg(m_propertyName)); + } +} + + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_propertycommand_p.h b/src/designer/src/lib/shared/qdesigner_propertycommand_p.h new file mode 100644 index 000000000..0dc1825fe --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_propertycommand_p.h @@ -0,0 +1,313 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_PROPERTYCOMMAND_H +#define QDESIGNER_PROPERTYCOMMAND_H + +#include "qdesigner_formwindowcommand_p.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QDesignerPropertySheetExtension; + +namespace qdesigner_internal { + +class QDesignerIntegration; + +enum SpecialProperty { + SP_None, SP_ObjectName, SP_LayoutName, SP_SpacerName,SP_WindowTitle, + SP_MinimumSize, SP_MaximumSize, SP_Geometry, SP_Icon, SP_CurrentTabName, SP_CurrentItemName, SP_CurrentPageName, + SP_AutoDefault, SP_Alignment, SP_Shortcut, SP_Orientation +}; + +//Determine special property +enum SpecialProperty getSpecialProperty(const QString& propertyName); + +// A helper class for applying properties to objects. +// Can be used for Set commands (setValue(), restoreOldValue()) or +// Reset Commands restoreDefaultValue(), restoreOldValue()). +// +class QDESIGNER_SHARED_EXPORT PropertyHelper { + Q_DISABLE_COPY(PropertyHelper) +public: + // A pair of Value and changed flag + typedef QPair Value; + + enum ObjectType {OT_Object, OT_FreeAction, OT_AssociatedAction, OT_Widget}; + + PropertyHelper(QObject* object, + SpecialProperty specialProperty, + QDesignerPropertySheetExtension *sheet, + int index); + virtual ~PropertyHelper() {} + + QObject *object() const { return m_object; } + SpecialProperty specialProperty() const { return m_specialProperty; } + // set a new value. Can be overwritten to perform a transformation (see + // handling of Arrow key move in FormWindow class). + virtual Value setValue(QDesignerFormWindowInterface *fw, const QVariant &value, bool changed, unsigned subPropertyMask); + + // restore old value + Value restoreOldValue(QDesignerFormWindowInterface *fw); + // set default value + Value restoreDefaultValue(QDesignerFormWindowInterface *fw); + + inline QVariant oldValue() const + { return m_oldValue.first; } + + inline void setOldValue(const QVariant &oldValue) + { m_oldValue.first = oldValue; } + + // required updates for this property (bit mask) + enum UpdateMask { UpdatePropertyEditor=1, UpdateObjectInspector=2 }; + unsigned updateMask() const; + + // can be merged into one command (that is, object and name match) + bool canMerge(const PropertyHelper &other) const; + QDesignerIntegration *integration(QDesignerFormWindowInterface *fw) const; + + static void triggerActionChanged(QAction *a); + +private: + // Apply the value and update. Returns corrected value + Value applyValue(QDesignerFormWindowInterface *fw, const QVariant &oldValue, Value newValue); + + static void checkApplyWidgetValue(QDesignerFormWindowInterface *fw, QWidget* w, + SpecialProperty specialProperty, QVariant &v); + + void updateObject(QDesignerFormWindowInterface *fw, const QVariant &oldValue, const QVariant &newValue); + QVariant findDefaultValue(QDesignerFormWindowInterface *fw) const; + void ensureUniqueObjectName(QDesignerFormWindowInterface *fw, QObject *object) const; + SpecialProperty m_specialProperty; + + QPointer m_object; + ObjectType m_objectType; + QPointer m_parentWidget; + + QDesignerPropertySheetExtension *m_propertySheet; + int m_index; + + Value m_oldValue; +}; + +// Base class for commands that can be applied to several widgets + +class QDESIGNER_SHARED_EXPORT PropertyListCommand : public QDesignerFormWindowCommand { +public: + typedef QList ObjectList; + + explicit PropertyListCommand(QDesignerFormWindowInterface *formWindow, QUndoCommand *parent = 0); + + QObject* object(int index = 0) const; + + QVariant oldValue(int index = 0) const; + + void setOldValue(const QVariant &oldValue, int index = 0); + + // Calls restoreDefaultValue() and update() + virtual void undo(); + +protected: + typedef QSharedPointer PropertyHelperPtr; + typedef QList PropertyHelperList; + + // add an object + bool add(QObject *object, const QString &propertyName); + + // Init from a list and make sure referenceObject is added first to obtain the right property group + bool initList(const ObjectList &list, const QString &apropertyName, QObject *referenceObject = 0); + + // set a new value, return update mask + unsigned setValue(QVariant value, bool changed, unsigned subPropertyMask); + + // restore old value, return update mask + unsigned restoreOldValue(); + // set default value, return update mask + unsigned restoreDefaultValue(); + + // update designer + void update(unsigned updateMask); + + // check if lists are aequivalent for command merging (same widgets and props) + bool canMergeLists(const PropertyHelperList& other) const; + + PropertyHelperList& propertyHelperList() { return m_propertyHelperList; } + const PropertyHelperList& propertyHelperList() const { return m_propertyHelperList; } + + const QString propertyName() const; + SpecialProperty specialProperty() const; + + // Helper struct describing a property used for checking whether + // properties of different widgets are equivalent + struct PropertyDescription { + public: + PropertyDescription(); + PropertyDescription(const QString &propertyName, QDesignerPropertySheetExtension *propertySheet, int index); + bool equals(const PropertyDescription &p) const; + void debug() const; + + QString m_propertyName; + QString m_propertyGroup; + QVariant::Type m_propertyType; + SpecialProperty m_specialProperty; + }; + const PropertyDescription &propertyDescription() const { return m_propertyDescription; } + +protected: + virtual PropertyHelper *createPropertyHelper(QObject *o, SpecialProperty sp, + QDesignerPropertySheetExtension *sheet, int sheetIndex) const; + +private: + PropertyDescription m_propertyDescription; + PropertyHelperList m_propertyHelperList; +}; + +class QDESIGNER_SHARED_EXPORT SetPropertyCommand: public PropertyListCommand +{ + +public: + typedef QList ObjectList; + + explicit SetPropertyCommand(QDesignerFormWindowInterface *formWindow, QUndoCommand *parent = 0); + + bool init(QObject *object, const QString &propertyName, const QVariant &newValue); + bool init(const ObjectList &list, const QString &propertyName, const QVariant &newValue, + QObject *referenceObject = 0, bool enableSubPropertyHandling = true); + + + inline QVariant newValue() const + { return m_newValue; } + + inline void setNewValue(const QVariant &newValue) + { m_newValue = newValue; } + + int id() const; + bool mergeWith(const QUndoCommand *other); + + virtual void redo(); + +protected: + virtual QVariant mergeValue(const QVariant &newValue); + +private: + unsigned subPropertyMask(const QVariant &newValue, QObject *referenceObject); + void setDescription(); + QVariant m_newValue; + unsigned m_subPropertyMask; +}; + +class QDESIGNER_SHARED_EXPORT ResetPropertyCommand: public PropertyListCommand +{ + +public: + typedef QList ObjectList; + + explicit ResetPropertyCommand(QDesignerFormWindowInterface *formWindow); + + bool init(QObject *object, const QString &propertyName); + bool init(const ObjectList &list, const QString &propertyName, QObject *referenceObject = 0); + + virtual void redo(); + +protected: + virtual bool mergeWith(const QUndoCommand *) { return false; } + +private: + void setDescription(); + QString m_propertyName; +}; + + +class QDESIGNER_SHARED_EXPORT AddDynamicPropertyCommand: public QDesignerFormWindowCommand +{ + +public: + explicit AddDynamicPropertyCommand(QDesignerFormWindowInterface *formWindow); + + bool init(const QList &selection, QObject *current, const QString &propertyName, const QVariant &value); + + virtual void redo(); + virtual void undo(); +private: + void setDescription(); + QString m_propertyName; + QList m_selection; + QVariant m_value; +}; + +class QDESIGNER_SHARED_EXPORT RemoveDynamicPropertyCommand: public QDesignerFormWindowCommand +{ + +public: + explicit RemoveDynamicPropertyCommand(QDesignerFormWindowInterface *formWindow); + + bool init(const QList &selection, QObject *current, const QString &propertyName); + + virtual void redo(); + virtual void undo(); +private: + void setDescription(); + QString m_propertyName; + QMap > m_objectToValueAndChanged; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QDESIGNER_PROPERTYCOMMAND_H diff --git a/src/designer/src/lib/shared/qdesigner_propertyeditor.cpp b/src/designer/src/lib/shared/qdesigner_propertyeditor.cpp new file mode 100644 index 000000000..e3a92e289 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_propertyeditor.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_propertyeditor_p.h" +#include "pluginmanager_p.h" + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { +typedef QDesignerPropertyEditor::StringPropertyParameters StringPropertyParameters; +// A map of property name to type +typedef QHash PropertyNameTypeMap; + +// Compile a map of hard-coded string property types +static const PropertyNameTypeMap &stringPropertyTypes() +{ + static PropertyNameTypeMap propertyNameTypeMap; + if (propertyNameTypeMap.empty()) { + const StringPropertyParameters richtext(ValidationRichText, true); + // Accessibility. Both are texts the narrator reads + propertyNameTypeMap.insert(QLatin1String("accessibleDescription"), richtext); + propertyNameTypeMap.insert(QLatin1String("accessibleName"), richtext); + // object names + const StringPropertyParameters objectName(ValidationObjectName, false); + propertyNameTypeMap.insert(QLatin1String("buddy"), objectName); + propertyNameTypeMap.insert(QLatin1String("currentItemName"), objectName); + propertyNameTypeMap.insert(QLatin1String("currentPageName"), objectName); + propertyNameTypeMap.insert(QLatin1String("currentTabName"), objectName); + propertyNameTypeMap.insert(QLatin1String("layoutName"), objectName); + propertyNameTypeMap.insert(QLatin1String("spacerName"), objectName); + // Style sheet + propertyNameTypeMap.insert(QLatin1String("styleSheet"), StringPropertyParameters(ValidationStyleSheet, false)); + // Buttons/ QCommandLinkButton + const StringPropertyParameters multiline(ValidationMultiLine, true); + propertyNameTypeMap.insert(QLatin1String("description"), multiline); + propertyNameTypeMap.insert(QLatin1String("iconText"), multiline); + // Tooltips, etc. + propertyNameTypeMap.insert(QLatin1String("toolTip"), richtext); + propertyNameTypeMap.insert(QLatin1String("whatsThis"), richtext); + propertyNameTypeMap.insert(QLatin1String("windowIconText"), richtext); + propertyNameTypeMap.insert(QLatin1String("html"), richtext); + // A QWizard page id + propertyNameTypeMap.insert(QLatin1String("pageId"), StringPropertyParameters(ValidationSingleLine, false)); + // QPlainTextEdit + propertyNameTypeMap.insert(QLatin1String("plainText"), StringPropertyParameters(ValidationMultiLine, true)); + } + return propertyNameTypeMap; +} + +QDesignerPropertyEditor::QDesignerPropertyEditor(QWidget *parent, Qt::WindowFlags flags) : + QDesignerPropertyEditorInterface(parent, flags), + m_propertyChangedForwardingBlocked(false) +{ + // Make old signal work for compatibility + connect(this, SIGNAL(propertyChanged(QString,QVariant)), this, SLOT(slotPropertyChanged(QString,QVariant))); +} + +QDesignerPropertyEditor::StringPropertyParameters QDesignerPropertyEditor::textPropertyValidationMode( + QDesignerFormEditorInterface *core, const QObject *object, + const QString &propertyName, bool isMainContainer) +{ + // object name - no comment + if (propertyName == QLatin1String("objectName")) { + const TextPropertyValidationMode vm = isMainContainer ? ValidationObjectNameScope : ValidationObjectName; + return StringPropertyParameters(vm, false); + } + + // Check custom widgets by class. + const QString className = WidgetFactory::classNameOf(core, object); + const QDesignerCustomWidgetData customData = core->pluginManager()->customWidgetData(className); + if (!customData.isNull()) { + StringPropertyParameters customType; + if (customData.xmlStringPropertyType(propertyName, &customType)) + return customType; + } + + // Check hardcoded property ames + const PropertyNameTypeMap::const_iterator hit = stringPropertyTypes().constFind(propertyName); + if (hit != stringPropertyTypes().constEnd()) + return hit.value(); + + // text: Check according to widget type. + if (propertyName == QLatin1String("text")) { + if (qobject_cast(object) || qobject_cast(object)) + return StringPropertyParameters(ValidationSingleLine, true); + if (qobject_cast(object)) + return StringPropertyParameters(ValidationMultiLine, true); + return StringPropertyParameters(ValidationRichText, true); + } + + // Fuzzy matching + if (propertyName.endsWith(QLatin1String("Name"))) + return StringPropertyParameters(ValidationSingleLine, true); + + if (propertyName.endsWith(QLatin1String("ToolTip"))) + return StringPropertyParameters(ValidationRichText, true); + +#ifdef Q_OS_WIN // No translation for the active X "control" property + if (propertyName == QLatin1String("control") && className == QLatin1String("QAxWidget")) + return StringPropertyParameters(ValidationSingleLine, false); +#endif + + // default to single + return StringPropertyParameters(ValidationSingleLine, true); +} + +void QDesignerPropertyEditor::emitPropertyValueChanged(const QString &name, const QVariant &value, bool enableSubPropertyHandling) +{ + // Avoid duplicate signal emission - see below + m_propertyChangedForwardingBlocked = true; + emit propertyValueChanged(name, value, enableSubPropertyHandling); + emit propertyChanged(name, value); + m_propertyChangedForwardingBlocked = false; +} + +void QDesignerPropertyEditor::slotPropertyChanged(const QString &name, const QVariant &value) +{ + // Forward signal from Integration using the old interfaces. + if (!m_propertyChangedForwardingBlocked) + emit propertyValueChanged(name, value, true); +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_propertyeditor_p.h b/src/designer/src/lib/shared/qdesigner_propertyeditor_p.h new file mode 100644 index 000000000..72d6f05b6 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_propertyeditor_p.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + + +#ifndef DESIGNERPROPERTYEDITOR_H +#define DESIGNERPROPERTYEDITOR_H + +#include "shared_global_p.h" +#include "shared_enums_p.h" +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +// Extends the QDesignerPropertyEditorInterface by property comment handling and +// a signal for resetproperty. + +class QDESIGNER_SHARED_EXPORT QDesignerPropertyEditor: public QDesignerPropertyEditorInterface +{ + Q_OBJECT +public: + explicit QDesignerPropertyEditor(QWidget *parent = 0, Qt::WindowFlags flags = 0); + + // A pair . + typedef QPair StringPropertyParameters; + + // Return a pair of validation mode and flag indicating whether property is translatable + // for textual properties. + static StringPropertyParameters textPropertyValidationMode(QDesignerFormEditorInterface *core, + const QObject *object, const QString &propertyName, bool isMainContainer); + +Q_SIGNALS: + void propertyValueChanged(const QString &name, const QVariant &value, bool enableSubPropertyHandling); + void resetProperty(const QString &name); + void addDynamicProperty(const QString &name, const QVariant &value); + void removeDynamicProperty(const QString &name); + void editorOpened(); + void editorClosed(); + +public Q_SLOTS: + /* Quick update that assumes the actual count of properties has not changed + * (as opposed to setObject()). N/A when for example executing a + * layout command and margin properties appear. */ + virtual void updatePropertySheet() = 0; + virtual void reloadResourceProperties() = 0; + +private Q_SLOTS: + void slotPropertyChanged(const QString &name, const QVariant &value); + +protected: + void emitPropertyValueChanged(const QString &name, const QVariant &value, bool enableSubPropertyHandling); + +private: + bool m_propertyChangedForwardingBlocked; + +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // DESIGNERPROPERTYEDITOR_H diff --git a/src/designer/src/lib/shared/qdesigner_propertysheet.cpp b/src/designer/src/lib/shared/qdesigner_propertysheet.cpp new file mode 100644 index 000000000..27527da05 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_propertysheet.cpp @@ -0,0 +1,1657 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_propertysheet_p.h" +#include "qdesigner_utils_p.h" +#include "formwindowbase_p.h" +#include "layoutinfo_p.h" +#include "qlayout_widget_p.h" +#include "qdesigner_introspection_p.h" + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +#define USE_LAYOUT_SIZE_CONSTRAINT + +static const QDesignerMetaObjectInterface *propertyIntroducedBy(const QDesignerMetaObjectInterface *meta, int index) +{ + if (index >= meta->propertyOffset()) + return meta; + + if (meta->superClass()) + return propertyIntroducedBy(meta->superClass(), index); + + return 0; +} + +// Layout fake properties (prefixed by 'layout' to distinguish them from other 'margins' +// that might be around. These are forwarded to the layout sheet (after name transformation). +// +// 'layoutObjectName' is new for 4.4. It is the name of the actual layout. +// Up to 4.3, QLayoutWidget's name was displayed in the objectinspector. +// This changes with 4.4; the layout name is displayed. This means that for +// old forms, QLayoutWidget will show up as ''; however, the uic code will +// still use 'verticalLayout' (in case someone accesses it). New Layouts get autogenerated names, +// legacy forms will keep their empty names (unless someone types in a new name). +static const char *layoutObjectNameC = "layoutName"; +static const char *layoutLeftMarginC = "layoutLeftMargin"; +static const char *layoutTopMarginC = "layoutTopMargin"; +static const char *layoutRightMarginC = "layoutRightMargin"; +static const char *layoutBottomMarginC = "layoutBottomMargin"; +static const char *layoutSpacingC = "layoutSpacing"; +static const char *layoutHorizontalSpacingC = "layoutHorizontalSpacing"; +static const char *layoutVerticalSpacingC = "layoutVerticalSpacing"; +static const char *layoutSizeConstraintC = "layoutSizeConstraint"; +// form layout +static const char *layoutFieldGrowthPolicyC = "layoutFieldGrowthPolicy"; +static const char *layoutRowWrapPolicyC = "layoutRowWrapPolicy"; +static const char *layoutLabelAlignmentC = "layoutLabelAlignment"; +static const char *layoutFormAlignmentC = "layoutFormAlignment"; +// stretches +static const char *layoutboxStretchPropertyC = "layoutStretch"; +static const char *layoutGridRowStretchPropertyC = "layoutRowStretch"; +static const char *layoutGridColumnStretchPropertyC = "layoutColumnStretch"; +static const char *layoutGridRowMinimumHeightC = "layoutRowMinimumHeight"; +static const char *layoutGridColumnMinimumWidthC = "layoutColumnMinimumWidth"; + +// Find the form editor in the hierarchy. +// We know that the parent of the sheet is the extension manager +// whose parent is the core. + +static QDesignerFormEditorInterface *formEditorForObject(QObject *o) { + do { + if (QDesignerFormEditorInterface* core = qobject_cast(o)) + return core; + o = o->parent(); + } while(o); + Q_ASSERT(o); + return 0; +} + +static bool hasLayoutAttributes(QDesignerFormEditorInterface *core, QObject *object) +{ + if (!object->isWidgetType()) + return false; + + QWidget *w = qobject_cast(object); + if (const QDesignerWidgetDataBaseInterface *db = core->widgetDataBase()) { + if (db->isContainer(w)) + return true; + } + return false; +} + +// Cache DesignerMetaEnum by scope/name of a QMetaEnum +static const qdesigner_internal::DesignerMetaEnum &designerMetaEnumFor(const QDesignerMetaEnumInterface *me) +{ + typedef QPair ScopeNameKey; + typedef QMap DesignerMetaEnumCache; + static DesignerMetaEnumCache cache; + + const QString name = me->name(); + const QString scope = me->scope(); + + const ScopeNameKey key = ScopeNameKey(scope, name); + DesignerMetaEnumCache::iterator it = cache.find(key); + if (it == cache.end()) { + qdesigner_internal::DesignerMetaEnum dme = qdesigner_internal::DesignerMetaEnum(name, scope, me->separator()); + const int keyCount = me->keyCount(); + for (int i=0; i < keyCount; ++i) + dme.addKey(me->value(i), me->key(i)); + it = cache.insert(key, dme); + } + return it.value(); +} + +// Cache DesignerMetaFlags by scope/name of a QMetaEnum +static const qdesigner_internal::DesignerMetaFlags &designerMetaFlagsFor(const QDesignerMetaEnumInterface *me) +{ + typedef QPair ScopeNameKey; + typedef QMap DesignerMetaFlagsCache; + static DesignerMetaFlagsCache cache; + + const QString name = me->name(); + const QString scope = me->scope(); + + const ScopeNameKey key = ScopeNameKey(scope, name); + DesignerMetaFlagsCache::iterator it = cache.find(key); + if (it == cache.end()) { + qdesigner_internal::DesignerMetaFlags dme = qdesigner_internal::DesignerMetaFlags(name, scope, me->separator()); + const int keyCount = me->keyCount(); + for (int i=0; i < keyCount; ++i) + dme.addKey(me->value(i), me->key(i)); + it = cache.insert(key, dme); + } + return it.value(); +} + +// ------------ QDesignerMemberSheetPrivate +class QDesignerPropertySheetPrivate { +public: + typedef QDesignerPropertySheet::PropertyType PropertyType; + typedef QDesignerPropertySheet::ObjectType ObjectType; + + explicit QDesignerPropertySheetPrivate(QDesignerPropertySheet *sheetPublic, QObject *object, QObject *sheetParent); + + bool invalidIndex(const char *functionName, int index) const; + inline int count() const { return m_meta->propertyCount() + m_addProperties.count(); } + + PropertyType propertyType(int index) const; + QString transformLayoutPropertyName(int index) const; + QLayout* layout(QDesignerPropertySheetExtension **layoutPropertySheet = 0) const; + static ObjectType objectType(const QObject *o); + + bool isReloadableProperty(int index) const; + bool isResourceProperty(int index) const; + void addResourceProperty(int index, QVariant::Type type); + QVariant resourceProperty(int index) const; + void setResourceProperty(int index, const QVariant &value); + QVariant emptyResourceProperty(int index) const; // of type PropertySheetPixmapValue / PropertySheetIconValue + QVariant defaultResourceProperty(int index) const; // of type QPixmap / QIcon (maybe it can be generalized for all types, not resource only) + + bool isStringProperty(int index) const; + void addStringProperty(int index); + qdesigner_internal::PropertySheetStringValue stringProperty(int index) const; + void setStringProperty(int index, const qdesigner_internal::PropertySheetStringValue &value); + + bool isKeySequenceProperty(int index) const; + void addKeySequenceProperty(int index); + qdesigner_internal::PropertySheetKeySequenceValue keySequenceProperty(int index) const; + void setKeySequenceProperty(int index, const qdesigner_internal::PropertySheetKeySequenceValue &value); + + enum PropertyKind { NormalProperty, FakeProperty, DynamicProperty, DefaultDynamicProperty }; + class Info { + public: + Info(); + + QString group; + QVariant defaultValue; + bool changed; + bool visible; + bool attribute; + bool reset; + PropertyType propertyType; + PropertyKind kind; + }; + + Info &ensureInfo(int index); + + QDesignerPropertySheet *q; + QDesignerFormEditorInterface *m_core; + const QDesignerMetaObjectInterface *m_meta; + const ObjectType m_objectType; + + typedef QHash InfoHash; + InfoHash m_info; + QHash m_fakeProperties; + QHash m_addProperties; + QHash m_addIndex; + QHash m_resourceProperties; // only PropertySheetPixmapValue snd PropertySheetIconValue here + QHash m_stringProperties; // only PropertySheetStringValue + QHash m_keySequenceProperties; // only PropertySheetKeySequenceValue + + const bool m_canHaveLayoutAttributes; + + // Variables used for caching the layout, access via layout(). + QPointer m_object; + mutable QPointer m_lastLayout; + mutable QDesignerPropertySheetExtension *m_lastLayoutPropertySheet; + mutable bool m_LastLayoutByDesigner; + + qdesigner_internal::DesignerPixmapCache *m_pixmapCache; + qdesigner_internal::DesignerIconCache *m_iconCache; + QPointer m_fwb; + + // Enable Qt's internal properties starting with prefix "_q_" + static bool m_internalDynamicPropertiesEnabled; +}; + +bool QDesignerPropertySheetPrivate::m_internalDynamicPropertiesEnabled = false; + +/* + The property is reloadable if its contents depends on resource. +*/ +bool QDesignerPropertySheetPrivate::isReloadableProperty(int index) const +{ + return isResourceProperty(index) + || propertyType(index) == QDesignerPropertySheet::PropertyStyleSheet + || propertyType(index) == QDesignerPropertySheet::PropertyText + || q->property(index).type() == QVariant::Url; +} + +/* + Resource properties are those which: + 1) are reloadable + 2) their state is associated with a file which can be taken from resources + 3) we don't store them in Qt meta object system (because designer keeps different data structure for them) +*/ + +bool QDesignerPropertySheetPrivate::isResourceProperty(int index) const +{ + return m_resourceProperties.contains(index); +} + +void QDesignerPropertySheetPrivate::addResourceProperty(int index, QVariant::Type type) +{ + if (type == QVariant::Pixmap) + m_resourceProperties.insert(index, QVariant::fromValue(qdesigner_internal::PropertySheetPixmapValue())); + else if (type == QVariant::Icon) + m_resourceProperties.insert(index, QVariant::fromValue(qdesigner_internal::PropertySheetIconValue())); +} + +QVariant QDesignerPropertySheetPrivate::emptyResourceProperty(int index) const +{ + QVariant v = m_resourceProperties.value(index); + if (v.canConvert()) + return QVariant::fromValue(qdesigner_internal::PropertySheetPixmapValue()); + if (v.canConvert()) + return QVariant::fromValue(qdesigner_internal::PropertySheetIconValue()); + return v; +} + +QVariant QDesignerPropertySheetPrivate::defaultResourceProperty(int index) const +{ + return m_info.value(index).defaultValue; +} + +QVariant QDesignerPropertySheetPrivate::resourceProperty(int index) const +{ + return m_resourceProperties.value(index); +} + +void QDesignerPropertySheetPrivate::setResourceProperty(int index, const QVariant &value) +{ + Q_ASSERT(isResourceProperty(index)); + + QVariant &v = m_resourceProperties[index]; + if ((value.canConvert() && v.canConvert()) + || (value.canConvert() && v.canConvert())) + v = value; +} + +bool QDesignerPropertySheetPrivate::isStringProperty(int index) const +{ + return m_stringProperties.contains(index); +} + +void QDesignerPropertySheetPrivate::addStringProperty(int index) +{ + m_stringProperties.insert(index, qdesigner_internal::PropertySheetStringValue()); +} + +qdesigner_internal::PropertySheetStringValue QDesignerPropertySheetPrivate::stringProperty(int index) const +{ + return m_stringProperties.value(index); +} + +void QDesignerPropertySheetPrivate::setStringProperty(int index, const qdesigner_internal::PropertySheetStringValue &value) +{ + Q_ASSERT(isStringProperty(index)); + + m_stringProperties[index] = value; +} + +bool QDesignerPropertySheetPrivate::isKeySequenceProperty(int index) const +{ + return m_keySequenceProperties.contains(index); +} + +void QDesignerPropertySheetPrivate::addKeySequenceProperty(int index) +{ + m_keySequenceProperties.insert(index, qdesigner_internal::PropertySheetKeySequenceValue()); +} + +qdesigner_internal::PropertySheetKeySequenceValue QDesignerPropertySheetPrivate::keySequenceProperty(int index) const +{ + return m_keySequenceProperties.value(index); +} + +void QDesignerPropertySheetPrivate::setKeySequenceProperty(int index, const qdesigner_internal::PropertySheetKeySequenceValue &value) +{ + Q_ASSERT(isKeySequenceProperty(index)); + + m_keySequenceProperties[index] = value; +} + +QDesignerPropertySheetPrivate::Info::Info() : + changed(false), + visible(true), + attribute(false), + reset(true), + propertyType(QDesignerPropertySheet::PropertyNone), + kind(NormalProperty) +{ +} + +QDesignerPropertySheetPrivate::QDesignerPropertySheetPrivate(QDesignerPropertySheet *sheetPublic, QObject *object, QObject *sheetParent) : + q(sheetPublic), + m_core(formEditorForObject(sheetParent)), + m_meta(m_core->introspection()->metaObject(object)), + m_objectType(QDesignerPropertySheet::objectTypeFromObject(object)), + m_canHaveLayoutAttributes(hasLayoutAttributes(m_core, object)), + m_object(object), + m_lastLayout(0), + m_lastLayoutPropertySheet(0), + m_LastLayoutByDesigner(false), + m_pixmapCache(0), + m_iconCache(0) +{ +} + +qdesigner_internal::FormWindowBase *QDesignerPropertySheet::formWindowBase() const +{ + return d->m_fwb; +} + +bool QDesignerPropertySheetPrivate::invalidIndex(const char *functionName, int index) const +{ + if (index < 0 || index >= count()) { + qWarning() << "** WARNING " << functionName << " invoked for " << m_object->objectName() << " was passed an invalid index " << index << '.'; + return true; + } + return false; +} + +QLayout* QDesignerPropertySheetPrivate::layout(QDesignerPropertySheetExtension **layoutPropertySheet) const +{ + // Return the layout and its property sheet + // only if it is managed by designer and not one created on a custom widget. + // (attempt to cache the value as this requires some hoops). + if (layoutPropertySheet) + *layoutPropertySheet = 0; + + if (!m_object->isWidgetType() || !m_canHaveLayoutAttributes) + return 0; + + QWidget *widget = qobject_cast(m_object); + QLayout *widgetLayout = qdesigner_internal::LayoutInfo::internalLayout(widget); + if (!widgetLayout) { + m_lastLayout = 0; + m_lastLayoutPropertySheet = 0; + return 0; + } + // Smart logic to avoid retrieving the meta DB from the widget every time. + if (widgetLayout != m_lastLayout) { + m_lastLayout = widgetLayout; + m_LastLayoutByDesigner = false; + m_lastLayoutPropertySheet = 0; + // Is this a layout managed by designer or some layout on a custom widget? + if (qdesigner_internal::LayoutInfo::managedLayout(m_core ,widgetLayout)) { + m_LastLayoutByDesigner = true; + m_lastLayoutPropertySheet = qt_extension(m_core->extensionManager(), m_lastLayout); + } + } + if (!m_LastLayoutByDesigner) + return 0; + + if (layoutPropertySheet) + *layoutPropertySheet = m_lastLayoutPropertySheet; + + return m_lastLayout; +} + +QDesignerPropertySheetPrivate::Info &QDesignerPropertySheetPrivate::ensureInfo(int index) +{ + InfoHash::iterator it = m_info.find(index); + if (it == m_info.end()) + it = m_info.insert(index, Info()); + return it.value(); +} + +QDesignerPropertySheet::PropertyType QDesignerPropertySheetPrivate::propertyType(int index) const +{ + const InfoHash::const_iterator it = m_info.constFind(index); + if (it == m_info.constEnd()) + return QDesignerPropertySheet::PropertyNone; + return it.value().propertyType; +} + +QString QDesignerPropertySheetPrivate::transformLayoutPropertyName(int index) const +{ + typedef QMap TypeNameMap; + static TypeNameMap typeNameMap; + if (typeNameMap.empty()) { + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutObjectName, QLatin1String("objectName")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutLeftMargin, QLatin1String("leftMargin")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutTopMargin, QLatin1String("topMargin")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutRightMargin, QLatin1String("rightMargin")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutBottomMargin, QLatin1String("bottomMargin")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutSpacing, QLatin1String("spacing")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutHorizontalSpacing, QLatin1String("horizontalSpacing")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutVerticalSpacing, QLatin1String("verticalSpacing")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutSizeConstraint, QLatin1String("sizeConstraint")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutFieldGrowthPolicy, QLatin1String("fieldGrowthPolicy")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutRowWrapPolicy, QLatin1String("rowWrapPolicy")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutLabelAlignment, QLatin1String("labelAlignment")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutFormAlignment, QLatin1String("formAlignment")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutBoxStretch, QLatin1String("stretch")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutGridRowStretch, QLatin1String("rowStretch")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutGridColumnStretch, QLatin1String("columnStretch")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutGridRowMinimumHeight, QLatin1String("rowMinimumHeight")); + typeNameMap.insert(QDesignerPropertySheet::PropertyLayoutGridColumnMinimumWidth, QLatin1String("columnMinimumWidth")); + } + const TypeNameMap::const_iterator it = typeNameMap.constFind(propertyType(index)); + if (it != typeNameMap.constEnd()) + return it.value(); + return QString(); +} + +// ----------- QDesignerPropertySheet + +QDesignerPropertySheet::ObjectType QDesignerPropertySheet::objectTypeFromObject(const QObject *o) +{ + if (qobject_cast(o)) + return ObjectLayout; + + if (!o->isWidgetType()) + return ObjectNone; + + if (qobject_cast(o)) + return ObjectLayoutWidget; + + if (qobject_cast(o)) + return ObjectLabel; + + if (o->inherits("Q3GroupBox")) + return ObjectQ3GroupBox; + + return ObjectNone; +} + +QDesignerPropertySheet::PropertyType QDesignerPropertySheet::propertyTypeFromName(const QString &name) +{ + typedef QHash PropertyTypeHash; + static PropertyTypeHash propertyTypeHash; + if (propertyTypeHash.empty()) { + propertyTypeHash.insert(QLatin1String(layoutObjectNameC), PropertyLayoutObjectName); + propertyTypeHash.insert(QLatin1String(layoutLeftMarginC), PropertyLayoutLeftMargin); + propertyTypeHash.insert(QLatin1String(layoutTopMarginC), PropertyLayoutTopMargin); + propertyTypeHash.insert(QLatin1String(layoutRightMarginC), PropertyLayoutRightMargin); + propertyTypeHash.insert(QLatin1String(layoutBottomMarginC), PropertyLayoutBottomMargin); + propertyTypeHash.insert(QLatin1String(layoutSpacingC), PropertyLayoutSpacing); + propertyTypeHash.insert(QLatin1String(layoutHorizontalSpacingC), PropertyLayoutHorizontalSpacing); + propertyTypeHash.insert(QLatin1String(layoutVerticalSpacingC), PropertyLayoutVerticalSpacing); + propertyTypeHash.insert(QLatin1String(layoutSizeConstraintC), PropertyLayoutSizeConstraint); + propertyTypeHash.insert(QLatin1String(layoutFieldGrowthPolicyC), PropertyLayoutFieldGrowthPolicy); + propertyTypeHash.insert(QLatin1String(layoutRowWrapPolicyC), PropertyLayoutRowWrapPolicy); + propertyTypeHash.insert(QLatin1String(layoutLabelAlignmentC), PropertyLayoutLabelAlignment); + propertyTypeHash.insert(QLatin1String(layoutFormAlignmentC), PropertyLayoutFormAlignment); + propertyTypeHash.insert(QLatin1String(layoutboxStretchPropertyC), PropertyLayoutBoxStretch); + propertyTypeHash.insert(QLatin1String(layoutGridRowStretchPropertyC), PropertyLayoutGridRowStretch); + propertyTypeHash.insert(QLatin1String(layoutGridColumnStretchPropertyC), PropertyLayoutGridColumnStretch); + propertyTypeHash.insert(QLatin1String(layoutGridRowMinimumHeightC), PropertyLayoutGridRowMinimumHeight); + propertyTypeHash.insert(QLatin1String(layoutGridColumnMinimumWidthC), PropertyLayoutGridColumnMinimumWidth); + propertyTypeHash.insert(QLatin1String("buddy"), PropertyBuddy); + propertyTypeHash.insert(QLatin1String("geometry"), PropertyGeometry); + propertyTypeHash.insert(QLatin1String("checkable"), PropertyCheckable); + propertyTypeHash.insert(QLatin1String("accessibleName"), PropertyAccessibility); + propertyTypeHash.insert(QLatin1String("accessibleDescription"), PropertyAccessibility); + propertyTypeHash.insert(QLatin1String("windowTitle"), PropertyWindowTitle); + propertyTypeHash.insert(QLatin1String("windowIcon"), PropertyWindowIcon); + propertyTypeHash.insert(QLatin1String("windowFilePath"), PropertyWindowFilePath); + propertyTypeHash.insert(QLatin1String("windowOpacity"), PropertyWindowOpacity); + propertyTypeHash.insert(QLatin1String("windowIconText"), PropertyWindowIconText); + propertyTypeHash.insert(QLatin1String("windowModality"), PropertyWindowModality); + propertyTypeHash.insert(QLatin1String("windowModified"), PropertyWindowModified); + propertyTypeHash.insert(QLatin1String("styleSheet"), PropertyStyleSheet); + propertyTypeHash.insert(QLatin1String("text"), PropertyText); + } + return propertyTypeHash.value(name, PropertyNone); +} + +QDesignerPropertySheet::QDesignerPropertySheet(QObject *object, QObject *parent) : + QObject(parent), + d(new QDesignerPropertySheetPrivate(this, object, parent)) +{ + typedef QDesignerPropertySheetPrivate::Info Info; + const QDesignerMetaObjectInterface *baseMeta = d->m_meta; + + while (baseMeta &&baseMeta->className().startsWith(QLatin1String("QDesigner"))) { + baseMeta = baseMeta->superClass(); + } + Q_ASSERT(baseMeta != 0); + + QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(d->m_object); + d->m_fwb = qobject_cast(formWindow); + if (d->m_fwb) { + d->m_pixmapCache = d->m_fwb->pixmapCache(); + d->m_iconCache = d->m_fwb->iconCache(); + d->m_fwb->addReloadablePropertySheet(this, object); + } + + for (int index=0; indexm_meta->property(index); + const QString name = p->name(); + if (p->type() == QVariant::KeySequence) { + createFakeProperty(name); + } else { + setVisible(index, false); // use the default for `real' properties + } + + QString pgroup = baseMeta->className(); + + if (const QDesignerMetaObjectInterface *pmeta = propertyIntroducedBy(baseMeta, index)) { + pgroup = pmeta->className(); + } + + Info &info = d->ensureInfo(index); + info.group = pgroup; + info.propertyType = propertyTypeFromName(name); + + if (p->type() == QVariant::Cursor || p->type() == QVariant::Icon || p->type() == QVariant::Pixmap) { + info.defaultValue = p->read(d->m_object); + if (p->type() == QVariant::Icon || p->type() == QVariant::Pixmap) + d->addResourceProperty(index, p->type()); + } else if (p->type() == QVariant::String) { + d->addStringProperty(index); + } else if (p->type() == QVariant::KeySequence) { + d->addKeySequenceProperty(index); + } + } + + if (object->isWidgetType()) { + createFakeProperty(QLatin1String("focusPolicy")); + createFakeProperty(QLatin1String("cursor")); + createFakeProperty(QLatin1String("toolTip")); + createFakeProperty(QLatin1String("whatsThis")); + createFakeProperty(QLatin1String("acceptDrops")); + createFakeProperty(QLatin1String("dragEnabled")); + // windowModality/Opacity is visible only for the main container, in which case the form windows enables it on loading + setVisible(createFakeProperty(QLatin1String("windowModality")), false); + setVisible(createFakeProperty(QLatin1String("windowOpacity"), double(1.0)), false); + if (qobject_cast(d->m_object)) { // prevent toolbars from being dragged off + createFakeProperty(QLatin1String("floatable"), QVariant(true)); + } else { + if (qobject_cast(d->m_object)) { + // Keep the menu bar editable in the form even if a native menu bar is used. + const bool nativeMenuBarDefault = !qApp->testAttribute(Qt::AA_DontUseNativeMenuBar); + createFakeProperty(QLatin1String("nativeMenuBar"), QVariant(nativeMenuBarDefault)); + } + } + if (d->m_canHaveLayoutAttributes) { + static const QString layoutGroup = QLatin1String("Layout"); + const char* fakeLayoutProperties[] = { + layoutObjectNameC, layoutLeftMarginC, layoutTopMarginC, layoutRightMarginC, layoutBottomMarginC, layoutSpacingC, layoutHorizontalSpacingC, layoutVerticalSpacingC, + layoutFieldGrowthPolicyC, layoutRowWrapPolicyC, layoutLabelAlignmentC, layoutFormAlignmentC, + layoutboxStretchPropertyC, layoutGridRowStretchPropertyC, layoutGridColumnStretchPropertyC, + layoutGridRowMinimumHeightC, layoutGridColumnMinimumWidthC +#ifdef USE_LAYOUT_SIZE_CONSTRAINT + , layoutSizeConstraintC +#endif + }; + const int fakeLayoutPropertyCount = sizeof(fakeLayoutProperties)/sizeof(const char*); + const int size = count(); + for (int i = 0; i < fakeLayoutPropertyCount; i++) { + createFakeProperty(QLatin1String(fakeLayoutProperties[i]), 0); + setAttribute(size + i, true); + setPropertyGroup(size + i, layoutGroup); + } + } + + if (d->m_objectType == ObjectLabel) + createFakeProperty(QLatin1String("buddy"), QVariant(QByteArray())); + /* We need to create a fake property since the property does not work + * for non-toplevel windows or on other systems than Mac and only if + * it is above a certain Mac OS version. */ + if (qobject_cast(d->m_object)) + createFakeProperty(QLatin1String("unifiedTitleAndToolBarOnMac"), false); + } + + if (qobject_cast(object)) { + createFakeProperty(QLatin1String("modal")); + } + if (qobject_cast(object)) { + createFakeProperty(QLatin1String("floating")); + } + + typedef QList ByteArrayList; + const ByteArrayList names = object->dynamicPropertyNames(); + if (!names.empty()) { + const ByteArrayList::const_iterator cend = names.constEnd(); + for (ByteArrayList::const_iterator it = names.constBegin(); it != cend; ++it) { + const char* cName = it->constData(); + const QString name = QString::fromLatin1(cName); + const int idx = addDynamicProperty(name, object->property(cName)); + if (idx != -1) + d->ensureInfo(idx).kind = QDesignerPropertySheetPrivate::DefaultDynamicProperty; + } + } +} + +QDesignerPropertySheet::~QDesignerPropertySheet() +{ + if (d->m_fwb) + d->m_fwb->removeReloadablePropertySheet(this); + delete d; +} + +QObject *QDesignerPropertySheet::object() const +{ + return d->m_object; +} + +bool QDesignerPropertySheet::dynamicPropertiesAllowed() const +{ + return true; +} + +bool QDesignerPropertySheet::canAddDynamicProperty(const QString &propName) const +{ + // used internally + if (propName == QLatin1String("database") || + propName == QLatin1String("buttonGroupId")) + return false; + const int index = d->m_meta->indexOfProperty(propName); + if (index != -1) + return false; // property already exists and is not a dynamic one + if (d->m_addIndex.contains(propName)) { + const int idx = d->m_addIndex.value(propName); + if (isVisible(idx)) + return false; // dynamic property already exists + else + return true; + } + if (!QDesignerPropertySheet::internalDynamicPropertiesEnabled() && propName.startsWith(QLatin1String("_q_"))) + return false; + return true; +} + +int QDesignerPropertySheet::addDynamicProperty(const QString &propName, const QVariant &value) +{ + typedef QDesignerPropertySheetPrivate::Info Info; + if (!value.isValid()) + return -1; // property has invalid type + if (!canAddDynamicProperty(propName)) + return -1; + + QVariant v = value; + if (value.type() == QVariant::Icon) + v = QVariant::fromValue(qdesigner_internal::PropertySheetIconValue()); + else if (value.type() == QVariant::Pixmap) + v = QVariant::fromValue(qdesigner_internal::PropertySheetPixmapValue()); + else if (value.type() == QVariant::String) + v = QVariant::fromValue(qdesigner_internal::PropertySheetStringValue(value.toString())); + else if (value.type() == QVariant::KeySequence) { + const QKeySequence keySequence = qvariant_cast(value); + v = QVariant::fromValue(qdesigner_internal::PropertySheetKeySequenceValue(keySequence)); + } + + if (d->m_addIndex.contains(propName)) { + const int idx = d->m_addIndex.value(propName); + // have to be invisible, this was checked in canAddDynamicProperty() method + setVisible(idx, true); + d->m_addProperties.insert(idx, v); + setChanged(idx, false); + const int index = d->m_meta->indexOfProperty(propName); + Info &info = d->ensureInfo(index); + info.defaultValue = value; + info.kind = QDesignerPropertySheetPrivate::DynamicProperty; + if (value.type() == QVariant::Icon || value.type() == QVariant::Pixmap) + d->addResourceProperty(idx, value.type()); + else if (value.type() == QVariant::String) + d->addStringProperty(idx); + else if (value.type() == QVariant::KeySequence) + d->addKeySequenceProperty(idx); + return idx; + } + + const int index = count(); + d->m_addIndex.insert(propName, index); + d->m_addProperties.insert(index, v); + Info &info = d->ensureInfo(index); + info.visible = true; + info.changed = false; + info.defaultValue = value; + info.kind = QDesignerPropertySheetPrivate::DynamicProperty; + setPropertyGroup(index, tr("Dynamic Properties")); + if (value.type() == QVariant::Icon || value.type() == QVariant::Pixmap) + d->addResourceProperty(index, value.type()); + else if (value.type() == QVariant::String) + d->addStringProperty(index); + else if (value.type() == QVariant::KeySequence) + d->addKeySequenceProperty(index); + return index; +} + +bool QDesignerPropertySheet::removeDynamicProperty(int index) +{ + if (!d->m_addIndex.contains(propertyName(index))) + return false; + + setVisible(index, false); + return true; +} + +bool QDesignerPropertySheet::isDynamic(int index) const +{ + if (!d->m_addProperties.contains(index)) + return false; + + switch (propertyType(index)) { + case PropertyBuddy: + if (d->m_objectType == ObjectLabel) + return false; + break; + case PropertyLayoutLeftMargin: + case PropertyLayoutTopMargin: + case PropertyLayoutRightMargin: + case PropertyLayoutBottomMargin: + case PropertyLayoutSpacing: + case PropertyLayoutHorizontalSpacing: + case PropertyLayoutVerticalSpacing: + case PropertyLayoutObjectName: + case PropertyLayoutSizeConstraint: + case PropertyLayoutFieldGrowthPolicy: + case PropertyLayoutRowWrapPolicy: + case PropertyLayoutLabelAlignment: + case PropertyLayoutFormAlignment: + case PropertyLayoutBoxStretch: + case PropertyLayoutGridRowStretch: + case PropertyLayoutGridColumnStretch: + case PropertyLayoutGridRowMinimumHeight: + case PropertyLayoutGridColumnMinimumWidth: + if (d->m_object->isWidgetType() && d->m_canHaveLayoutAttributes) + return false; + default: + break; + } + return true; +} + +bool QDesignerPropertySheet::isDynamicProperty(int index) const +{ + // Do not complain here, as an invalid index might be encountered + // if someone implements a property sheet only, omitting the dynamic sheet. + if (index < 0 || index >= count()) + return false; + return d->m_info.value(index).kind == QDesignerPropertySheetPrivate::DynamicProperty; +} + +bool QDesignerPropertySheet::isDefaultDynamicProperty(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return false; + return d->m_info.value(index).kind == QDesignerPropertySheetPrivate::DefaultDynamicProperty; +} + +bool QDesignerPropertySheet::isResourceProperty(int index) const +{ + return d->isResourceProperty(index); +} + +QVariant QDesignerPropertySheet::defaultResourceProperty(int index) const +{ + return d->defaultResourceProperty(index); +} + +qdesigner_internal::DesignerPixmapCache *QDesignerPropertySheet::pixmapCache() const +{ + return d->m_pixmapCache; +} + +void QDesignerPropertySheet::setPixmapCache(qdesigner_internal::DesignerPixmapCache *cache) +{ + d->m_pixmapCache = cache; +} + +qdesigner_internal::DesignerIconCache *QDesignerPropertySheet::iconCache() const +{ + return d->m_iconCache; +} + +void QDesignerPropertySheet::setIconCache(qdesigner_internal::DesignerIconCache *cache) +{ + d->m_iconCache = cache; +} + +int QDesignerPropertySheet::createFakeProperty(const QString &propertyName, const QVariant &value) +{ + typedef QDesignerPropertySheetPrivate::Info Info; + // fake properties + const int index = d->m_meta->indexOfProperty(propertyName); + if (index != -1) { + if (!(d->m_meta->property(index)->attributes() & QDesignerMetaPropertyInterface::DesignableAttribute)) + return -1; + Info &info = d->ensureInfo(index); + info.visible = false; + info.kind = QDesignerPropertySheetPrivate::FakeProperty; + QVariant v = value.isValid() ? value : metaProperty(index); + if (v.type() == QVariant::String) + v = QVariant::fromValue(qdesigner_internal::PropertySheetStringValue()); + if (v.type() == QVariant::KeySequence) + v = QVariant::fromValue(qdesigner_internal::PropertySheetKeySequenceValue()); + d->m_fakeProperties.insert(index, v); + return index; + } + if (!value.isValid()) + return -1; + + const int newIndex = count(); + d->m_addIndex.insert(propertyName, newIndex); + d->m_addProperties.insert(newIndex, value); + Info &info = d->ensureInfo(newIndex); + info.propertyType = propertyTypeFromName(propertyName); + info.kind = QDesignerPropertySheetPrivate::FakeProperty; + return newIndex; +} + +bool QDesignerPropertySheet::isAdditionalProperty(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return false; + return d->m_addProperties.contains(index); +} + +bool QDesignerPropertySheet::isFakeProperty(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return false; + // additional properties must be fake + return (d->m_fakeProperties.contains(index) || isAdditionalProperty(index)); +} + +int QDesignerPropertySheet::count() const +{ + return d->count(); +} + +int QDesignerPropertySheet::indexOf(const QString &name) const +{ + int index = d->m_meta->indexOfProperty(name); + + if (index == -1) + index = d->m_addIndex.value(name, -1); + + return index; +} + +QDesignerPropertySheet::PropertyType QDesignerPropertySheet::propertyType(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return PropertyNone; + return d->propertyType(index); +} + +QDesignerPropertySheet::ObjectType QDesignerPropertySheet::objectType() const +{ + return d->m_objectType; +} + +QString QDesignerPropertySheet::propertyName(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return QString(); + if (isAdditionalProperty(index)) + return d->m_addIndex.key(index); + + return d->m_meta->property(index)->name(); +} + +QString QDesignerPropertySheet::propertyGroup(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return QString(); + const QString g = d->m_info.value(index).group; + + if (!g.isEmpty()) + return g; + + if (propertyType(index) == PropertyAccessibility) + return QString::fromUtf8("Accessibility"); + + if (isAdditionalProperty(index)) + return d->m_meta->className(); + + return g; +} + +void QDesignerPropertySheet::setPropertyGroup(int index, const QString &group) +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return; + d->ensureInfo(index).group = group; +} + +QVariant QDesignerPropertySheet::property(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return QVariant(); + if (isAdditionalProperty(index)) { + if (isFakeLayoutProperty(index)) { + QDesignerPropertySheetExtension *layoutPropertySheet; + if (d->layout(&layoutPropertySheet) && layoutPropertySheet) { + const QString newPropName = d->transformLayoutPropertyName(index); + if (!newPropName.isEmpty()) { + const int newIndex = layoutPropertySheet->indexOf(newPropName); + if (newIndex != -1) + return layoutPropertySheet->property(newIndex); + return QVariant(); + } + } + } + return d->m_addProperties.value(index); + } + + if (isFakeProperty(index)) { + return d->m_fakeProperties.value(index); + } + + if (d->isResourceProperty(index)) + return d->resourceProperty(index); + + if (d->isStringProperty(index)) { + QString strValue = metaProperty(index).toString(); + qdesigner_internal::PropertySheetStringValue value = d->stringProperty(index); + if (strValue != value.value()) { + value.setValue(strValue); + d->setStringProperty(index, value); // cache it + } + return QVariant::fromValue(value); + } + + if (d->isKeySequenceProperty(index)) { + QKeySequence keyValue = qvariant_cast(metaProperty(index)); + qdesigner_internal::PropertySheetKeySequenceValue value = d->keySequenceProperty(index); + if (keyValue != value.value()) { + value.setValue(keyValue); + d->setKeySequenceProperty(index, value); // cache it + } + return QVariant::fromValue(value); + } + + return metaProperty(index); +} + +QVariant QDesignerPropertySheet::metaProperty(int index) const +{ + Q_ASSERT(!isFakeProperty(index)); + + const QDesignerMetaPropertyInterface *p = d->m_meta->property(index); + QVariant v = p->read(d->m_object); + switch (p->kind()) { + case QDesignerMetaPropertyInterface::FlagKind: { + qdesigner_internal::PropertySheetFlagValue psflags = qdesigner_internal::PropertySheetFlagValue(v.toInt(), designerMetaFlagsFor(p->enumerator())); + v.setValue(psflags); + } + break; + case QDesignerMetaPropertyInterface::EnumKind: { + qdesigner_internal::PropertySheetEnumValue pse = qdesigner_internal::PropertySheetEnumValue(v.toInt(), designerMetaEnumFor(p->enumerator())); + v.setValue(pse); + } + break; + case QDesignerMetaPropertyInterface::OtherKind: + break; + } + return v; +} + +QVariant QDesignerPropertySheet::resolvePropertyValue(int index, const QVariant &value) const +{ + if (value.canConvert()) + return qvariant_cast(value).value; + + if (value.canConvert()) + return qvariant_cast(value).value; + + if (value.canConvert()) + return qvariant_cast(value).value(); + + if (value.canConvert()) + return qvariant_cast(value).value(); + + if (value.canConvert()) { + const QString path = qvariant_cast(value).path(); + if (path.isEmpty()) + return defaultResourceProperty(index); + if (d->m_pixmapCache) { + return d->m_pixmapCache->pixmap(qvariant_cast(value)); + } + } + + if (value.canConvert()) { + const unsigned mask = qvariant_cast(value).mask(); + if (mask == 0) + return defaultResourceProperty(index); + if (d->m_iconCache) + return d->m_iconCache->icon(qvariant_cast(value)); + } + + return value; +} + +void QDesignerPropertySheet::setFakeProperty(int index, const QVariant &value) +{ + Q_ASSERT(isFakeProperty(index)); + + QVariant &v = d->m_fakeProperties[index]; + + // set resource properties also (if we are going to have fake resource properties) + if (value.canConvert() || value.canConvert()) { + v = value; + } else if (v.canConvert()) { + qdesigner_internal::PropertySheetFlagValue f = qvariant_cast(v); + f.value = value.toInt(); + v.setValue(f); + Q_ASSERT(value.type() == QVariant::Int); + } else if (v.canConvert()) { + qdesigner_internal::PropertySheetEnumValue e = qvariant_cast(v); + e.value = value.toInt(); + v.setValue(e); + Q_ASSERT(value.type() == QVariant::Int); + } else { + v = value; + } +} + +void QDesignerPropertySheet::clearFakeProperties() +{ + d->m_fakeProperties.clear(); +} + +// Buddy needs to be byte array, else uic won't work +static QVariant toByteArray(const QVariant &value) { + if (value.type() == QVariant::ByteArray) + return value; + const QByteArray ba = value.toString().toUtf8(); + return QVariant(ba); +} + +void QDesignerPropertySheet::setProperty(int index, const QVariant &value) +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return; + if (isAdditionalProperty(index)) { + if (d->m_objectType == ObjectLabel && propertyType(index) == PropertyBuddy) { + QFormBuilderExtra::applyBuddy(value.toString(), QFormBuilderExtra::BuddyApplyVisibleOnly, qobject_cast(d->m_object)); + d->m_addProperties[index] = toByteArray(value); + return; + } + + if (isFakeLayoutProperty(index)) { + QDesignerPropertySheetExtension *layoutPropertySheet; + if (d->layout(&layoutPropertySheet) && layoutPropertySheet) { + const QString newPropName = d->transformLayoutPropertyName(index); + if (!newPropName.isEmpty()) { + const int newIndex = layoutPropertySheet->indexOf(newPropName); + if (newIndex != -1) + layoutPropertySheet->setProperty(newIndex, value); + } + } + } + + if (isDynamicProperty(index) || isDefaultDynamicProperty(index)) { + if (d->isResourceProperty(index)) + d->setResourceProperty(index, value); + if (d->isStringProperty(index)) + d->setStringProperty(index, qvariant_cast(value)); + if (d->isKeySequenceProperty(index)) + d->setKeySequenceProperty(index, qvariant_cast(value)); + d->m_object->setProperty(propertyName(index).toUtf8(), resolvePropertyValue(index, value)); + if (d->m_object->isWidgetType()) { + QWidget *w = qobject_cast(d->m_object); + w->setStyleSheet(w->styleSheet()); + } + } + d->m_addProperties[index] = value; + } else if (isFakeProperty(index)) { + setFakeProperty(index, value); + } else { + if (d->isResourceProperty(index)) + d->setResourceProperty(index, value); + if (d->isStringProperty(index)) + d->setStringProperty(index, qvariant_cast(value)); + if (d->isKeySequenceProperty(index)) + d->setKeySequenceProperty(index, qvariant_cast(value)); + const QDesignerMetaPropertyInterface *p = d->m_meta->property(index); + p->write(d->m_object, resolvePropertyValue(index, value)); + if (qobject_cast(d->m_object) && propertyType(index) == PropertyCheckable) { + const int idx = indexOf(QLatin1String("focusPolicy")); + if (!isChanged(idx)) { + qdesigner_internal::PropertySheetEnumValue e = qvariant_cast(property(idx)); + if (value.toBool()) { + const QDesignerMetaPropertyInterface *p = d->m_meta->property(idx); + p->write(d->m_object, Qt::NoFocus); + e.value = Qt::StrongFocus; + QVariant v; + v.setValue(e); + setFakeProperty(idx, v); + } else { + e.value = Qt::NoFocus; + QVariant v; + v.setValue(e); + setFakeProperty(idx, v); + } + } + } + } +} + +bool QDesignerPropertySheet::hasReset(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return false; + if (isAdditionalProperty(index)) + return d->m_info.value(index).reset; + return true; +} + +bool QDesignerPropertySheet::reset(int index) +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return false; + if (d->isStringProperty(index)) { + qdesigner_internal::PropertySheetStringValue value; + // Main container: Reset to stored class name as not to change the file names generated by uic. + if (propertyName(index) == QLatin1String("objectName")) { + const QVariant classNameDefaultV = d->m_object->property("_q_classname"); + if (classNameDefaultV.isValid()) + value.setValue(classNameDefaultV.toString()); + } + setProperty(index, QVariant::fromValue(value)); + return true; + } + if (d->isKeySequenceProperty(index)) + setProperty(index, QVariant::fromValue(qdesigner_internal::PropertySheetKeySequenceValue())); + if (d->isResourceProperty(index)) { + setProperty(index, d->emptyResourceProperty(index)); + return true; + } else if (isDynamic(index)) { + const QString propName = propertyName(index); + const QVariant oldValue = d->m_addProperties.value(index); + const QVariant defaultValue = d->m_info.value(index).defaultValue; + QVariant newValue = defaultValue; + if (d->isStringProperty(index)) { + newValue = QVariant::fromValue(qdesigner_internal::PropertySheetStringValue(newValue.toString())); + } else if (d->isKeySequenceProperty(index)) { + const QKeySequence keySequence = qvariant_cast(newValue); + newValue = QVariant::fromValue(qdesigner_internal::PropertySheetKeySequenceValue(keySequence)); + } + if (oldValue == newValue) + return true; + d->m_object->setProperty(propName.toUtf8(), defaultValue); + d->m_addProperties[index] = newValue; + return true; + } else if (!d->m_info.value(index).defaultValue.isNull()) { + setProperty(index, d->m_info.value(index).defaultValue); + return true; + } + if (isAdditionalProperty(index)) { + const PropertyType pType = propertyType(index); + if (d->m_objectType == ObjectLabel && pType == PropertyBuddy) { + setProperty(index, QVariant(QByteArray())); + return true; + } + if (isFakeLayoutProperty(index)) { + // special properties + switch (pType) { + case PropertyLayoutObjectName: + setProperty(index, QString()); + return true; + case PropertyLayoutSizeConstraint: + setProperty(index, QVariant(QLayout::SetDefaultConstraint)); + return true; + case PropertyLayoutBoxStretch: + case PropertyLayoutGridRowStretch: + case PropertyLayoutGridColumnStretch: + case PropertyLayoutGridRowMinimumHeight: + case PropertyLayoutGridColumnMinimumWidth: + case PropertyLayoutFieldGrowthPolicy: + case PropertyLayoutRowWrapPolicy: + case PropertyLayoutLabelAlignment: + case PropertyLayoutFormAlignment: { + QDesignerPropertySheetExtension *layoutPropertySheet; + if (d->layout(&layoutPropertySheet) && layoutPropertySheet) + return layoutPropertySheet->reset(layoutPropertySheet->indexOf(d->transformLayoutPropertyName(index))); + } + break; + default: + break; + } + // special margins + int value = -1; + switch (d->m_objectType) { + case ObjectQ3GroupBox: { + const QWidget *w = qobject_cast(d->m_object); + switch (pType) { + case PropertyLayoutLeftMargin: + value = w->style()->pixelMetric(QStyle::PM_LayoutLeftMargin); + break; + case PropertyLayoutTopMargin: + value = w->style()->pixelMetric(QStyle::PM_LayoutTopMargin); + break; + case PropertyLayoutRightMargin: + value = w->style()->pixelMetric(QStyle::PM_LayoutRightMargin); + break; + case PropertyLayoutBottomMargin: + value = w->style()->pixelMetric(QStyle::PM_LayoutBottomMargin); + break; + case PropertyLayoutSpacing: + case PropertyLayoutHorizontalSpacing: + case PropertyLayoutVerticalSpacing: + value = -1; + break; + default: + break; + } + } + break; + case ObjectLayoutWidget: + if (pType == PropertyLayoutLeftMargin || + pType == PropertyLayoutTopMargin || + pType == PropertyLayoutRightMargin || + pType == PropertyLayoutBottomMargin) + value = 0; + break; + default: + break; + } + setProperty(index, value); + return true; + } + return false; + } else if (isFakeProperty(index)) { + const QDesignerMetaPropertyInterface *p = d->m_meta->property(index); + const bool result = p->reset(d->m_object); + d->m_fakeProperties[index] = p->read(d->m_object); + return result; + } else if (propertyType(index) == PropertyGeometry && d->m_object->isWidgetType()) { + if (QWidget *w = qobject_cast(d->m_object)) { + QWidget *widget = w; + if (qdesigner_internal::Utils::isCentralWidget(d->m_fwb, widget) && d->m_fwb->parentWidget()) + widget = d->m_fwb->parentWidget(); + + if (widget != w && widget->parentWidget()) { + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + widget->parentWidget()->adjustSize(); + } + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + widget->adjustSize(); + return true; + } + } + // ### TODO: reset for fake properties. + + const QDesignerMetaPropertyInterface *p = d->m_meta->property(index); + return p->reset(d->m_object); +} + +bool QDesignerPropertySheet::isChanged(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return false; + if (isAdditionalProperty(index)) { + if (isFakeLayoutProperty(index)) { + QDesignerPropertySheetExtension *layoutPropertySheet; + if (d->layout(&layoutPropertySheet) && layoutPropertySheet) { + const QString newPropName = d->transformLayoutPropertyName(index); + if (!newPropName.isEmpty()) { + const int newIndex = layoutPropertySheet->indexOf(newPropName); + if (newIndex != -1) + return layoutPropertySheet->isChanged(newIndex); + return false; + } + } + } + } + return d->m_info.value(index).changed; +} + +void QDesignerPropertySheet::setChanged(int index, bool changed) +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return; + if (isAdditionalProperty(index)) { + if (isFakeLayoutProperty(index)) { + QDesignerPropertySheetExtension *layoutPropertySheet; + if (d->layout(&layoutPropertySheet) && layoutPropertySheet) { + const QString newPropName = d->transformLayoutPropertyName(index); + if (!newPropName.isEmpty()) { + const int newIndex = layoutPropertySheet->indexOf(newPropName); + if (newIndex != -1) + layoutPropertySheet->setChanged(newIndex, changed); + } + } + } + } + if (d->isReloadableProperty(index)) { + if (d->m_fwb) { + if (changed) + d->m_fwb->addReloadableProperty(this, index); + else + d->m_fwb->removeReloadableProperty(this, index); + } + } + d->ensureInfo(index).changed = changed; +} + +bool QDesignerPropertySheet::isFakeLayoutProperty(int index) const +{ + if (!isAdditionalProperty(index)) + return false; + + switch (propertyType(index)) { + case PropertyLayoutObjectName: + case PropertyLayoutSizeConstraint: + return true; + case PropertyLayoutLeftMargin: + case PropertyLayoutTopMargin: + case PropertyLayoutRightMargin: + case PropertyLayoutBottomMargin: + case PropertyLayoutSpacing: + case PropertyLayoutHorizontalSpacing: + case PropertyLayoutVerticalSpacing: + case PropertyLayoutFieldGrowthPolicy: + case PropertyLayoutRowWrapPolicy: + case PropertyLayoutLabelAlignment: + case PropertyLayoutFormAlignment: + case PropertyLayoutBoxStretch: + case PropertyLayoutGridRowStretch: + case PropertyLayoutGridColumnStretch: + case PropertyLayoutGridRowMinimumHeight: + case PropertyLayoutGridColumnMinimumWidth: + return d->m_canHaveLayoutAttributes; + default: + break; + } + return false; +} + +// Determine the "designable" state of a property. Properties, which have +// a per-object boolean test function that returns false are shown in +// disabled state ("checked" depending on "checkable", etc.) +// Properties, which are generally not designable independent +// of the object are not shown at all. +enum DesignableState { PropertyIsDesignable, + // Object has a Designable test function that returns false. + PropertyOfObjectNotDesignable, + PropertyNotDesignable }; + +static inline DesignableState designableState(const QDesignerMetaPropertyInterface *p, const QObject *object) +{ + if (p->attributes(object) & QDesignerMetaPropertyInterface::DesignableAttribute) + return PropertyIsDesignable; + return (p->attributes() & QDesignerMetaPropertyInterface::DesignableAttribute) ? + PropertyOfObjectNotDesignable : PropertyNotDesignable; +} + +bool QDesignerPropertySheet::isVisible(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return false; + + const PropertyType type = propertyType(index); + if (isAdditionalProperty(index)) { + if (isFakeLayoutProperty(index) && d->m_object->isWidgetType()) { + const QLayout *currentLayout = d->layout(); + if (!currentLayout) + return false; + const int visibleMask = qdesigner_internal::LayoutProperties::visibleProperties(currentLayout); + switch (type) { + case PropertyLayoutSpacing: + return visibleMask & qdesigner_internal::LayoutProperties::SpacingProperty; + case PropertyLayoutHorizontalSpacing: + case PropertyLayoutVerticalSpacing: + return visibleMask & qdesigner_internal::LayoutProperties::HorizSpacingProperty; + case PropertyLayoutFieldGrowthPolicy: + return visibleMask & qdesigner_internal::LayoutProperties::FieldGrowthPolicyProperty; + case PropertyLayoutRowWrapPolicy: + return visibleMask & qdesigner_internal::LayoutProperties::RowWrapPolicyProperty; + case PropertyLayoutLabelAlignment: + return visibleMask & qdesigner_internal::LayoutProperties::LabelAlignmentProperty; + case PropertyLayoutFormAlignment: + return visibleMask & qdesigner_internal::LayoutProperties::FormAlignmentProperty; + case PropertyLayoutBoxStretch: + return visibleMask & qdesigner_internal::LayoutProperties::BoxStretchProperty; + case PropertyLayoutGridRowStretch: + return visibleMask & qdesigner_internal::LayoutProperties::GridRowStretchProperty; + case PropertyLayoutGridColumnStretch: + return visibleMask & qdesigner_internal::LayoutProperties::GridColumnStretchProperty; + case PropertyLayoutGridRowMinimumHeight: + return visibleMask & qdesigner_internal::LayoutProperties::GridRowMinimumHeightProperty; + case PropertyLayoutGridColumnMinimumWidth: + return visibleMask & qdesigner_internal::LayoutProperties::GridColumnMinimumWidthProperty; + default: + break; + } + return true; + } + return d->m_info.value(index).visible; + } + + if (isFakeProperty(index)) { + switch (type) { + case PropertyWindowModality: // Hidden for child widgets + case PropertyWindowOpacity: + return d->m_info.value(index).visible; + default: + break; + } + return true; + } + + const bool visible = d->m_info.value(index).visible; + switch (type) { + case PropertyWindowTitle: + case PropertyWindowIcon: + case PropertyWindowFilePath: + case PropertyWindowOpacity: + case PropertyWindowIconText: + case PropertyWindowModified: + return visible; + default: + if (visible) + return true; + break; + } + + const QDesignerMetaPropertyInterface *p = d->m_meta->property(index); + if (!(p->accessFlags() & QDesignerMetaPropertyInterface::WriteAccess)) + return false; + + // Enabled handling: Hide only statically not designable properties + return designableState(p, d->m_object) != PropertyNotDesignable; +} + +void QDesignerPropertySheet::setVisible(int index, bool visible) +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return; + d->ensureInfo(index).visible = visible; +} + +bool QDesignerPropertySheet::isEnabled(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return false; + if (isAdditionalProperty(index)) + return true; + + if (isFakeProperty(index)) + return true; + + // Grey out geometry of laid-out widgets (including splitter) + if (propertyType(index) == PropertyGeometry && d->m_object->isWidgetType()) { + bool isManaged; + const qdesigner_internal::LayoutInfo::Type lt = qdesigner_internal::LayoutInfo::laidoutWidgetType(d->m_core, qobject_cast(d->m_object), &isManaged); + return !isManaged || lt == qdesigner_internal::LayoutInfo::NoLayout; + } + + if (d->m_info.value(index).visible == true) // Sun CC 5.5 oddity, wants true + return true; + + // Enable setting of properties for statically non-designable properties + // as this might be done via TaskMenu/Cursor::setProperty. Note that those + // properties are not visible. + const QDesignerMetaPropertyInterface *p = d->m_meta->property(index); + return (p->accessFlags() & QDesignerMetaPropertyInterface::WriteAccess) && + designableState(p, d->m_object) != PropertyOfObjectNotDesignable; +} + +bool QDesignerPropertySheet::isAttribute(int index) const +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return false; + if (isAdditionalProperty(index)) + return d->m_info.value(index).attribute; + + if (isFakeProperty(index)) + return false; + + return d->m_info.value(index).attribute; +} + +void QDesignerPropertySheet::setAttribute(int index, bool attribute) +{ + if (d->invalidIndex(Q_FUNC_INFO, index)) + return; + d->ensureInfo(index).attribute = attribute; +} + +QDesignerFormEditorInterface *QDesignerPropertySheet::core() const +{ + return d->m_core; +} + +bool QDesignerPropertySheet::internalDynamicPropertiesEnabled() +{ + return QDesignerPropertySheetPrivate::m_internalDynamicPropertiesEnabled; +} + +void QDesignerPropertySheet::setInternalDynamicPropertiesEnabled(bool v) +{ + QDesignerPropertySheetPrivate::m_internalDynamicPropertiesEnabled = v; +} + +// ---------- QDesignerAbstractPropertySheetFactory + +struct QDesignerAbstractPropertySheetFactory::PropertySheetFactoryPrivate { + PropertySheetFactoryPrivate(); + const QString m_propertySheetId; + const QString m_dynamicPropertySheetId; + + typedef QMap ExtensionMap; + ExtensionMap m_extensions; + typedef QHash ExtendedSet; + ExtendedSet m_extended; +}; + +QDesignerAbstractPropertySheetFactory::PropertySheetFactoryPrivate::PropertySheetFactoryPrivate() : + m_propertySheetId(Q_TYPEID(QDesignerPropertySheetExtension)), + m_dynamicPropertySheetId(Q_TYPEID(QDesignerDynamicPropertySheetExtension)) +{ +} + +// ---------- QDesignerAbstractPropertySheetFactory + + +QDesignerAbstractPropertySheetFactory::QDesignerAbstractPropertySheetFactory(QExtensionManager *parent) : + QExtensionFactory(parent), + m_impl(new PropertySheetFactoryPrivate) +{ +} + +QDesignerAbstractPropertySheetFactory::~QDesignerAbstractPropertySheetFactory() +{ + delete m_impl; +} + +QObject *QDesignerAbstractPropertySheetFactory::extension(QObject *object, const QString &iid) const +{ + typedef PropertySheetFactoryPrivate::ExtensionMap ExtensionMap; + if (!object) + return 0; + + if (iid != m_impl->m_propertySheetId && iid != m_impl->m_dynamicPropertySheetId) + return 0; + + ExtensionMap::iterator it = m_impl->m_extensions.find(object); + if (it == m_impl->m_extensions.end()) { + if (QObject *ext = createPropertySheet(object, const_cast(this))) { + connect(ext, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*))); + it = m_impl->m_extensions.insert(object, ext); + } + } + + if (!m_impl->m_extended.contains(object)) { + connect(object, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*))); + m_impl->m_extended.insert(object, true); + } + + if (it == m_impl->m_extensions.end()) + return 0; + + return it.value(); +} + +void QDesignerAbstractPropertySheetFactory::objectDestroyed(QObject *object) +{ + QMutableMapIterator it(m_impl->m_extensions); + while (it.hasNext()) { + it.next(); + + QObject *o = it.key(); + if (o == object || object == it.value()) { + it.remove(); + } + } + + m_impl->m_extended.remove(object); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_propertysheet_p.h b/src/designer/src/lib/shared/qdesigner_propertysheet_p.h new file mode 100644 index 000000000..67d195b65 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_propertysheet_p.h @@ -0,0 +1,266 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_PROPERTYSHEET_H +#define QDESIGNER_PROPERTYSHEET_H + +#include "shared_global_p.h" +#include "dynamicpropertysheet.h" +#include +#include +#include + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QLayout; +class QDesignerFormEditorInterface; +class QDesignerPropertySheetPrivate; + +namespace qdesigner_internal +{ + class DesignerPixmapCache; + class DesignerIconCache; + class FormWindowBase; +} + +class QDESIGNER_SHARED_EXPORT QDesignerPropertySheet: public QObject, public QDesignerPropertySheetExtension, public QDesignerDynamicPropertySheetExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerPropertySheetExtension QDesignerDynamicPropertySheetExtension) +public: + explicit QDesignerPropertySheet(QObject *object, QObject *parent = 0); + virtual ~QDesignerPropertySheet(); + + virtual int indexOf(const QString &name) const; + + virtual int count() const; + virtual QString propertyName(int index) const; + + virtual QString propertyGroup(int index) const; + virtual void setPropertyGroup(int index, const QString &group); + + virtual bool hasReset(int index) const; + virtual bool reset(int index); + + virtual bool isAttribute(int index) const; + virtual void setAttribute(int index, bool b); + + virtual bool isVisible(int index) const; + virtual void setVisible(int index, bool b); + + virtual QVariant property(int index) const; + virtual void setProperty(int index, const QVariant &value); + + virtual bool isChanged(int index) const; + + virtual void setChanged(int index, bool changed); + + virtual bool dynamicPropertiesAllowed() const; + virtual int addDynamicProperty(const QString &propertyName, const QVariant &value); + virtual bool removeDynamicProperty(int index); + virtual bool isDynamicProperty(int index) const; + virtual bool canAddDynamicProperty(const QString &propertyName) const; + + bool isDefaultDynamicProperty(int index) const; + + bool isResourceProperty(int index) const; + QVariant defaultResourceProperty(int index) const; + + qdesigner_internal::DesignerPixmapCache *pixmapCache() const; + void setPixmapCache(qdesigner_internal::DesignerPixmapCache *cache); + qdesigner_internal::DesignerIconCache *iconCache() const; + void setIconCache(qdesigner_internal::DesignerIconCache *cache); + int createFakeProperty(const QString &propertyName, const QVariant &value = QVariant()); + + virtual bool isEnabled(int index) const; + QObject *object() const; + + static bool internalDynamicPropertiesEnabled(); + static void setInternalDynamicPropertiesEnabled(bool v); + +protected: + bool isAdditionalProperty(int index) const; + bool isFakeProperty(int index) const; + QVariant resolvePropertyValue(int index, const QVariant &value) const; + QVariant metaProperty(int index) const; + void setFakeProperty(int index, const QVariant &value); + void clearFakeProperties(); + + bool isFakeLayoutProperty(int index) const; + bool isDynamic(int index) const; + qdesigner_internal::FormWindowBase *formWindowBase() const; + QDesignerFormEditorInterface *core() const; + +public: + enum PropertyType { PropertyNone, + PropertyLayoutObjectName, + PropertyLayoutLeftMargin, + PropertyLayoutTopMargin, + PropertyLayoutRightMargin, + PropertyLayoutBottomMargin, + PropertyLayoutSpacing, + PropertyLayoutHorizontalSpacing, + PropertyLayoutVerticalSpacing, + PropertyLayoutSizeConstraint, + PropertyLayoutFieldGrowthPolicy, + PropertyLayoutRowWrapPolicy, + PropertyLayoutLabelAlignment, + PropertyLayoutFormAlignment, + PropertyLayoutBoxStretch, + PropertyLayoutGridRowStretch, + PropertyLayoutGridColumnStretch, + PropertyLayoutGridRowMinimumHeight, + PropertyLayoutGridColumnMinimumWidth, + PropertyBuddy, + PropertyAccessibility, + PropertyGeometry, + PropertyCheckable, + PropertyWindowTitle, + PropertyWindowIcon, + PropertyWindowFilePath, + PropertyWindowOpacity, + PropertyWindowIconText, + PropertyWindowModality, + PropertyWindowModified, + PropertyStyleSheet, + PropertyText + }; + + enum ObjectType { ObjectNone, ObjectLabel, ObjectLayout, ObjectLayoutWidget, ObjectQ3GroupBox }; + + static ObjectType objectTypeFromObject(const QObject *o); + static PropertyType propertyTypeFromName(const QString &name); + +protected: + PropertyType propertyType(int index) const; + ObjectType objectType() const; + +private: + QDesignerPropertySheetPrivate *d; +}; + +/* Abstract base class for factories that register a property sheet that implements + * both QDesignerPropertySheetExtension and QDesignerDynamicPropertySheetExtension + * by multiple inheritance. The factory maintains ownership of + * the extension and returns it for both id's. */ + +class QDESIGNER_SHARED_EXPORT QDesignerAbstractPropertySheetFactory: public QExtensionFactory +{ + Q_OBJECT + Q_INTERFACES(QAbstractExtensionFactory) +public: + explicit QDesignerAbstractPropertySheetFactory(QExtensionManager *parent = 0); + virtual ~QDesignerAbstractPropertySheetFactory(); + + QObject *extension(QObject *object, const QString &iid) const; + +private slots: + void objectDestroyed(QObject *object); + +private: + virtual QObject *createPropertySheet(QObject *qObject, QObject *parent) const = 0; + + struct PropertySheetFactoryPrivate; + PropertySheetFactoryPrivate *m_impl; +}; + +/* Convenience factory template for property sheets that implement + * QDesignerPropertySheetExtension and QDesignerDynamicPropertySheetExtension + * by multiple inheritance. */ + +template +class QDesignerPropertySheetFactory : public QDesignerAbstractPropertySheetFactory { +public: + explicit QDesignerPropertySheetFactory(QExtensionManager *parent = 0); + + static void registerExtension(QExtensionManager *mgr); + +private: + // Does a qobject_cast on the object. + virtual QObject *createPropertySheet(QObject *qObject, QObject *parent) const; +}; + +template +QDesignerPropertySheetFactory::QDesignerPropertySheetFactory(QExtensionManager *parent) : + QDesignerAbstractPropertySheetFactory(parent) +{ +} + +template +QObject *QDesignerPropertySheetFactory::createPropertySheet(QObject *qObject, QObject *parent) const +{ + Object *object = qobject_cast(qObject); + if (!object) + return 0; + return new PropertySheet(object, parent); +} + +template +void QDesignerPropertySheetFactory::registerExtension(QExtensionManager *mgr) +{ + QDesignerPropertySheetFactory *factory = new QDesignerPropertySheetFactory(mgr); + mgr->registerExtensions(factory, Q_TYPEID(QDesignerPropertySheetExtension)); + mgr->registerExtensions(factory, Q_TYPEID(QDesignerDynamicPropertySheetExtension)); +} + + +// Standard property sheet +typedef QDesignerPropertySheetFactory QDesignerDefaultPropertySheetFactory; + +QT_END_NAMESPACE + +#endif // QDESIGNER_PROPERTYSHEET_H diff --git a/src/designer/src/lib/shared/qdesigner_qsettings.cpp b/src/designer/src/lib/shared/qdesigner_qsettings.cpp new file mode 100644 index 000000000..65c78362d --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_qsettings.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_qsettings_p.h" + +#include +#include +#include +#include +#include + +/*! + \class QDesignerSettingsSimple + + \brief Implements QDesignerSettingsInterface by calls to QSettings + */ + +QDesignerQSettings::QDesignerQSettings() : + m_settings(qApp->organizationName(), settingsApplicationName()) +{ +} + +QString QDesignerQSettings::settingsApplicationName() +{ + return qApp->applicationName(); +} + +void QDesignerQSettings::beginGroup(const QString &prefix) +{ + m_settings.beginGroup(prefix); +} + +void QDesignerQSettings::endGroup() +{ + m_settings.endGroup(); +} + +bool QDesignerQSettings::contains(const QString &key) const +{ + return m_settings.contains(key); +} + +void QDesignerQSettings::setValue(const QString &key, const QVariant &value) +{ + m_settings.setValue(key, value); +} + +QVariant QDesignerQSettings::value(const QString &key, const QVariant &defaultValue) const +{ + return m_settings.value(key, defaultValue); +} + +void QDesignerQSettings::remove(const QString &key) +{ + m_settings.remove(key); +} diff --git a/src/designer/src/lib/shared/qdesigner_qsettings_p.h b/src/designer/src/lib/shared/qdesigner_qsettings_p.h new file mode 100644 index 000000000..e0586cc65 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_qsettings_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_QSETTINGS_H +#define QDESIGNER_QSETTINGS_H + +#include "abstractsettings_p.h" +#include "shared_global_p.h" + +#include + +QT_BEGIN_NAMESPACE + +// Implements QDesignerSettingsInterface by calls to QSettings +class QDESIGNER_SHARED_EXPORT QDesignerQSettings : public QDesignerSettingsInterface +{ +public: + QDesignerQSettings(); + + virtual void beginGroup(const QString &prefix); + virtual void endGroup(); + + virtual bool contains(const QString &key) const; + virtual void setValue(const QString &key, const QVariant &value); + virtual QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const; + virtual void remove(const QString &key); + + // The application name to be used for settings. Allows for including + // the Qt version to prevent settings of different Qt versions from + // interfering. + static QString settingsApplicationName(); + +private: + QSettings m_settings; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_QSETTINGS_H diff --git a/src/designer/src/lib/shared/qdesigner_stackedbox.cpp b/src/designer/src/lib/shared/qdesigner_stackedbox.cpp new file mode 100644 index 000000000..0206e9709 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_stackedbox.cpp @@ -0,0 +1,399 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_stackedbox_p.h" +#include "qdesigner_command_p.h" +#include "qdesigner_propertycommand_p.h" +#include "orderdialog_p.h" +#include "promotiontaskmenu_p.h" +#include "widgetfactory_p.h" + +#include + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static QToolButton *createToolButton(QWidget *parent, Qt::ArrowType at, const QString &name) { + QToolButton *rc = new QToolButton(); + rc->setAttribute(Qt::WA_NoChildEventsForParent, true); + rc->setParent(parent); + rc->setObjectName(name); + rc->setArrowType(at); + rc->setAutoRaise(true); + rc->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + rc->setFixedSize(QSize(15, 15)); + return rc; +} + +// --------------- QStackedWidgetPreviewEventFilter +QStackedWidgetPreviewEventFilter::QStackedWidgetPreviewEventFilter(QStackedWidget *parent) : + QObject(parent), + m_buttonToolTipEnabled(false), // Not on preview + m_stackedWidget(parent), + m_prev(createToolButton(m_stackedWidget, Qt::LeftArrow, QLatin1String("__qt__passive_prev"))), + m_next(createToolButton(m_stackedWidget, Qt::RightArrow, QLatin1String("__qt__passive_next"))) +{ + connect(m_prev, SIGNAL(clicked()), this, SLOT(prevPage())); + connect(m_next, SIGNAL(clicked()), this, SLOT(nextPage())); + + updateButtons(); + m_stackedWidget->installEventFilter(this); + m_prev->installEventFilter(this); + m_next->installEventFilter(this); +} + +void QStackedWidgetPreviewEventFilter::install(QStackedWidget *stackedWidget) +{ + new QStackedWidgetPreviewEventFilter(stackedWidget); +} + +void QStackedWidgetPreviewEventFilter::updateButtons() +{ + m_prev->move(m_stackedWidget->width() - 31, 1); + m_prev->show(); + m_prev->raise(); + + m_next->move(m_stackedWidget->width() - 16, 1); + m_next->show(); + m_next->raise(); +} + +void QStackedWidgetPreviewEventFilter::prevPage() +{ + if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(stackedWidget())) { + fw->clearSelection(); + fw->selectWidget(stackedWidget(), true); + } + const int count = m_stackedWidget->count(); + if (count > 1) { + int newIndex = m_stackedWidget->currentIndex() - 1; + if (newIndex < 0) + newIndex = count - 1; + gotoPage(newIndex); + } +} + +void QStackedWidgetPreviewEventFilter::nextPage() +{ + if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(stackedWidget())) { + fw->clearSelection(); + fw->selectWidget(stackedWidget(), true); + } + const int count = m_stackedWidget->count(); + if (count > 1) + gotoPage((m_stackedWidget->currentIndex() + 1) % count); +} + +bool QStackedWidgetPreviewEventFilter::eventFilter(QObject *watched, QEvent *event) +{ + if (watched->isWidgetType()) { + if (watched == m_stackedWidget) { + switch (event->type()) { + case QEvent::LayoutRequest: + updateButtons(); + break; + case QEvent::ChildAdded: + case QEvent::ChildRemoved: + case QEvent::Resize: + case QEvent::Show: + updateButtons(); + break; + default: + break; + } + } + if (m_buttonToolTipEnabled && (watched == m_next || watched == m_prev)) { + switch (event->type()) { + case QEvent::ToolTip: + updateButtonToolTip(watched); // Tooltip includes page number, so, refresh on demand + break; + default: + break; + } + } + } + return QObject::eventFilter(watched, event); +} + +void QStackedWidgetPreviewEventFilter::gotoPage(int page) +{ + m_stackedWidget->setCurrentIndex(page); + updateButtons(); +} + +static inline QString stackedClassName(QStackedWidget *w) +{ + if (const QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(w)) + return qdesigner_internal::WidgetFactory::classNameOf(fw->core(), w); + return QLatin1String("Stacked widget"); +} + +void QStackedWidgetPreviewEventFilter::updateButtonToolTip(QObject *o) +{ + QString className = QLatin1String("Stacked widget"); + if (const QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(m_stackedWidget)) + className = qdesigner_internal::WidgetFactory::classNameOf(fw->core(), m_stackedWidget); + if (o == m_prev) { + const QString msg = tr("Go to previous page of %1 '%2' (%3/%4).").arg(stackedClassName(m_stackedWidget)).arg(m_stackedWidget->objectName()).arg(m_stackedWidget->currentIndex() + 1).arg(m_stackedWidget->count()); + m_prev->setToolTip(msg); + } else { + if (o == m_next) { + const QString msg = tr("Go to next page of %1 '%2' (%3/%4).").arg(stackedClassName(m_stackedWidget)).arg(m_stackedWidget->objectName()).arg(m_stackedWidget->currentIndex() + 1).arg(m_stackedWidget->count()); + m_next->setToolTip(msg); + } + } +} + +// --------------- QStackedWidgetEventFilter +QStackedWidgetEventFilter::QStackedWidgetEventFilter(QStackedWidget *parent) : + QStackedWidgetPreviewEventFilter(parent), + m_actionPreviousPage(new QAction(tr("Previous Page"), this)), + m_actionNextPage(new QAction(tr("Next Page"), this)), + m_actionDeletePage(new QAction(tr("Delete"), this)), + m_actionInsertPage(new QAction(tr("Before Current Page"), this)), + m_actionInsertPageAfter(new QAction(tr("After Current Page"), this)), + m_actionChangePageOrder(new QAction(tr("Change Page Order..."), this)), + m_pagePromotionTaskMenu(new qdesigner_internal::PromotionTaskMenu(0, qdesigner_internal::PromotionTaskMenu::ModeSingleWidget, this)) +{ + setButtonToolTipEnabled(true); + connect(m_actionPreviousPage, SIGNAL(triggered()), this, SLOT(prevPage())); + connect(m_actionNextPage, SIGNAL(triggered()), this, SLOT(nextPage())); + connect(m_actionDeletePage, SIGNAL(triggered()), this, SLOT(removeCurrentPage())); + connect(m_actionInsertPage, SIGNAL(triggered()), this, SLOT(addPage())); + connect(m_actionInsertPageAfter, SIGNAL(triggered()), this, SLOT(addPageAfter())); + connect(m_actionChangePageOrder, SIGNAL(triggered()), this, SLOT(changeOrder())); +} + +void QStackedWidgetEventFilter::install(QStackedWidget *stackedWidget) +{ + new QStackedWidgetEventFilter(stackedWidget); +} + +QStackedWidgetEventFilter *QStackedWidgetEventFilter::eventFilterOf(const QStackedWidget *stackedWidget) +{ + // Look for 1st order children only..otherwise, we might get filters of nested widgets + const QObjectList children = stackedWidget->children(); + const QObjectList::const_iterator cend = children.constEnd(); + for (QObjectList::const_iterator it = children.constBegin(); it != cend; ++it) { + QObject *o = *it; + if (!o->isWidgetType()) + if (QStackedWidgetEventFilter *ef = qobject_cast(o)) + return ef; + } + return 0; +} + +QMenu *QStackedWidgetEventFilter::addStackedWidgetContextMenuActions(const QStackedWidget *stackedWidget, QMenu *popup) +{ + QStackedWidgetEventFilter *filter = eventFilterOf(stackedWidget); + if (!filter) + return 0; + return filter->addContextMenuActions(popup); +} + +void QStackedWidgetEventFilter::removeCurrentPage() +{ + if (stackedWidget()->currentIndex() == -1) + return; + + if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(stackedWidget())) { + qdesigner_internal::DeleteStackedWidgetPageCommand *cmd = new qdesigner_internal::DeleteStackedWidgetPageCommand(fw); + cmd->init(stackedWidget()); + fw->commandHistory()->push(cmd); + } +} + +void QStackedWidgetEventFilter::changeOrder() +{ + QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(stackedWidget()); + + if (!fw) + return; + + const QWidgetList oldPages = qdesigner_internal::OrderDialog::pagesOfContainer(fw->core(), stackedWidget()); + const int pageCount = oldPages.size(); + if (pageCount < 2) + return; + + qdesigner_internal::OrderDialog dlg(fw); + dlg.setPageList(oldPages); + if (dlg.exec() == QDialog::Rejected) + return; + + const QWidgetList newPages = dlg.pageList(); + if (newPages == oldPages) + return; + + fw->beginCommand(tr("Change Page Order")); + for(int i=0; i < pageCount; ++i) { + if (newPages.at(i) == stackedWidget()->widget(i)) + continue; + qdesigner_internal::MoveStackedWidgetCommand *cmd = new qdesigner_internal::MoveStackedWidgetCommand(fw); + cmd->init(stackedWidget(), newPages.at(i), i); + fw->commandHistory()->push(cmd); + } + fw->endCommand(); +} + +void QStackedWidgetEventFilter::addPage() +{ + if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(stackedWidget())) { + qdesigner_internal::AddStackedWidgetPageCommand *cmd = new qdesigner_internal::AddStackedWidgetPageCommand(fw); + cmd->init(stackedWidget(), qdesigner_internal::AddStackedWidgetPageCommand::InsertBefore); + fw->commandHistory()->push(cmd); + } +} + +void QStackedWidgetEventFilter::addPageAfter() +{ + if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(stackedWidget())) { + qdesigner_internal::AddStackedWidgetPageCommand *cmd = new qdesigner_internal::AddStackedWidgetPageCommand(fw); + cmd->init(stackedWidget(), qdesigner_internal::AddStackedWidgetPageCommand::InsertAfter); + fw->commandHistory()->push(cmd); + } +} + +void QStackedWidgetEventFilter::gotoPage(int page) { + // Are we on a form or in a preview? + if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(stackedWidget())) { + qdesigner_internal::SetPropertyCommand *cmd = new qdesigner_internal::SetPropertyCommand(fw); + cmd->init(stackedWidget(), QLatin1String("currentIndex"), page); + fw->commandHistory()->push(cmd); + fw->emitSelectionChanged(); // Magically prevent an endless loop triggered by auto-repeat. + updateButtons(); + } else { + QStackedWidgetPreviewEventFilter::gotoPage(page); + } +} + +QMenu *QStackedWidgetEventFilter::addContextMenuActions(QMenu *popup) +{ + QMenu *pageMenu = 0; + const int count = stackedWidget()->count(); + const bool hasSeveralPages = count > 1; + m_actionDeletePage->setEnabled(count); + if (count) { + const QString pageSubMenuLabel = tr("Page %1 of %2").arg(stackedWidget()->currentIndex() + 1).arg(count); + pageMenu = popup->addMenu(pageSubMenuLabel); + pageMenu->addAction(m_actionDeletePage); + // Set up promotion menu for current widget. + if (QWidget *page = stackedWidget()->currentWidget ()) { + m_pagePromotionTaskMenu->setWidget(page); + m_pagePromotionTaskMenu->addActions(QDesignerFormWindowInterface::findFormWindow(stackedWidget()), + qdesigner_internal::PromotionTaskMenu::SuppressGlobalEdit, + pageMenu); + } + QMenu *insertPageMenu = popup->addMenu(tr("Insert Page")); + insertPageMenu->addAction(m_actionInsertPageAfter); + insertPageMenu->addAction(m_actionInsertPage); + } else { + QAction *insertPageAction = popup->addAction(tr("Insert Page")); + connect(insertPageAction, SIGNAL(triggered()), this, SLOT(addPage())); + } + popup->addAction(m_actionNextPage); + m_actionNextPage->setEnabled(hasSeveralPages); + popup->addAction(m_actionPreviousPage); + m_actionPreviousPage->setEnabled(hasSeveralPages); + popup->addAction(m_actionChangePageOrder); + m_actionChangePageOrder->setEnabled(hasSeveralPages); + popup->addSeparator(); + return pageMenu; +} + +// -------- QStackedWidgetPropertySheet + +static const char *pagePropertyName = "currentPageName"; + +QStackedWidgetPropertySheet::QStackedWidgetPropertySheet(QStackedWidget *object, QObject *parent) : + QDesignerPropertySheet(object, parent), + m_stackedWidget(object) +{ + createFakeProperty(QLatin1String(pagePropertyName), QString()); +} + +bool QStackedWidgetPropertySheet::isEnabled(int index) const +{ + if (propertyName(index) != QLatin1String(pagePropertyName)) + return QDesignerPropertySheet::isEnabled(index); + return m_stackedWidget->currentWidget() != 0; +} + +void QStackedWidgetPropertySheet::setProperty(int index, const QVariant &value) +{ + if (propertyName(index) == QLatin1String(pagePropertyName)) { + if (QWidget *w = m_stackedWidget->currentWidget()) + w->setObjectName(value.toString()); + } else { + QDesignerPropertySheet::setProperty(index, value); + } +} + +QVariant QStackedWidgetPropertySheet::property(int index) const +{ + if (propertyName(index) == QLatin1String(pagePropertyName)) { + if (const QWidget *w = m_stackedWidget->currentWidget()) + return w->objectName(); + return QString(); + } + return QDesignerPropertySheet::property(index); +} + +bool QStackedWidgetPropertySheet::reset(int index) +{ + if (propertyName(index) == QLatin1String(pagePropertyName)) { + setProperty(index, QString()); + return true; + } + return QDesignerPropertySheet::reset(index); +} + +bool QStackedWidgetPropertySheet::checkProperty(const QString &propertyName) +{ + return propertyName != QLatin1String(pagePropertyName); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_stackedbox_p.h b/src/designer/src/lib/shared/qdesigner_stackedbox_p.h new file mode 100644 index 000000000..d4b6db449 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_stackedbox_p.h @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_STACKEDBOX_H +#define QDESIGNER_STACKEDBOX_H + +#include "shared_global_p.h" +#include "qdesigner_propertysheet_p.h" + +QT_BEGIN_NAMESPACE + +class QStackedWidget; +class QWidget; +class QAction; +class QMenu; +class QToolButton; + +namespace qdesigner_internal { + class PromotionTaskMenu; +} + +// Event filter to be installed on a QStackedWidget in preview mode. +// Create two buttons to switch pages. + +class QDESIGNER_SHARED_EXPORT QStackedWidgetPreviewEventFilter : public QObject +{ + Q_OBJECT +public: + explicit QStackedWidgetPreviewEventFilter(QStackedWidget *parent); + + // Install helper on QStackedWidget + static void install(QStackedWidget *stackedWidget); + bool eventFilter(QObject *watched, QEvent *event); + + void setButtonToolTipEnabled(bool v) { m_buttonToolTipEnabled = v; } + bool buttonToolTipEnabled() const { return m_buttonToolTipEnabled; } + +public slots: + void updateButtons(); + void prevPage(); + void nextPage(); + +protected: + QStackedWidget *stackedWidget() const { return m_stackedWidget; } + virtual void gotoPage(int page); + +private: + void updateButtonToolTip(QObject *o); + + bool m_buttonToolTipEnabled; + QStackedWidget *m_stackedWidget; + QToolButton *m_prev; + QToolButton *m_next; +}; + +// Event filter to be installed on a QStackedWidget in editing mode. +// In addition to the browse buttons, handles context menu and everything + +class QDESIGNER_SHARED_EXPORT QStackedWidgetEventFilter : public QStackedWidgetPreviewEventFilter +{ + Q_OBJECT +public: + explicit QStackedWidgetEventFilter(QStackedWidget *parent); + + // Install helper on QStackedWidget + static void install(QStackedWidget *stackedWidget); + static QStackedWidgetEventFilter *eventFilterOf(const QStackedWidget *stackedWidget); + // Convenience to add a menu on a tackedWidget + static QMenu *addStackedWidgetContextMenuActions(const QStackedWidget *stackedWidget, QMenu *popup); + + // Add context menu and return page submenu or 0. + QMenu *addContextMenuActions(QMenu *popup); + +private slots: + void removeCurrentPage(); + void addPage(); + void addPageAfter(); + void changeOrder(); + +protected: + virtual void gotoPage(int page); + +private: + QAction *m_actionPreviousPage; + QAction *m_actionNextPage; + QAction *m_actionDeletePage; + QAction *m_actionInsertPage; + QAction *m_actionInsertPageAfter; + QAction *m_actionChangePageOrder; + qdesigner_internal::PromotionTaskMenu* m_pagePromotionTaskMenu; +}; + +// PropertySheet to handle the "currentPageName" property +class QDESIGNER_SHARED_EXPORT QStackedWidgetPropertySheet : public QDesignerPropertySheet { +public: + explicit QStackedWidgetPropertySheet(QStackedWidget *object, QObject *parent = 0); + + virtual void setProperty(int index, const QVariant &value); + virtual QVariant property(int index) const; + virtual bool reset(int index); + virtual bool isEnabled(int index) const; + + // Check whether the property is to be saved. Returns false for the page + // properties (as the property sheet has no concept of 'stored') + static bool checkProperty(const QString &propertyName); + +private: + QStackedWidget *m_stackedWidget; +}; + +typedef QDesignerPropertySheetFactory QStackedWidgetPropertySheetFactory; + +QT_END_NAMESPACE + +#endif // QDESIGNER_STACKEDBOX_H diff --git a/src/designer/src/lib/shared/qdesigner_tabwidget.cpp b/src/designer/src/lib/shared/qdesigner_tabwidget.cpp new file mode 100644 index 000000000..6110deaba --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_tabwidget.cpp @@ -0,0 +1,572 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_tabwidget_p.h" +#include "qdesigner_command_p.h" +#include "qdesigner_propertycommand_p.h" +#include "promotiontaskmenu_p.h" +#include "formwindowbase_p.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { +// Store tab widget as drag source +class MyMimeData : public QMimeData +{ + Q_OBJECT +public: + MyMimeData(const QTabWidget *tab) : m_tab(tab) {} + static bool fromMyTab(const QMimeData *mimeData, const QTabWidget *tab) { + if (!mimeData) + return false; + const MyMimeData *m = qobject_cast(mimeData); + return m && m->m_tab == tab; + } +private: + const QTabWidget *m_tab; +}; + +} // namespace qdesigner_internal + +// ------------- QTabWidgetEventFilter + +QTabWidgetEventFilter::QTabWidgetEventFilter(QTabWidget *parent) : + QObject(parent), + m_tabWidget(parent), + m_dropIndicator(0), + m_dragPage(0), + m_mousePressed(false), + m_actionDeletePage(new QAction(tr("Delete"), this)), + m_actionInsertPage(new QAction(tr("Before Current Page"), this)), + m_actionInsertPageAfter(new QAction(tr("After Current Page"), this)), + m_pagePromotionTaskMenu(new qdesigner_internal::PromotionTaskMenu(0, qdesigner_internal::PromotionTaskMenu::ModeSingleWidget, this)) +{ + tabBar()->setAcceptDrops(true); + tabBar()->installEventFilter(this); + + connect(m_actionInsertPage, SIGNAL(triggered()), this, SLOT(addPage())); + connect(m_actionInsertPageAfter, SIGNAL(triggered()), this, SLOT(addPageAfter())); + connect(m_actionDeletePage, SIGNAL(triggered()), this, SLOT(removeCurrentPage())); +} + +QTabWidgetEventFilter::~QTabWidgetEventFilter() +{ +} + +void QTabWidgetEventFilter::install(QTabWidget *tabWidget) +{ + new QTabWidgetEventFilter(tabWidget); +} + +QTabWidgetEventFilter *QTabWidgetEventFilter::eventFilterOf(const QTabWidget *tabWidget) +{ + // Look for 1st order children only..otherwise, we might get filters of nested tab widgets + const QObjectList children = tabWidget->children(); + const QObjectList::const_iterator cend = children.constEnd(); + for (QObjectList::const_iterator it = children.constBegin(); it != cend; ++it) { + QObject *o = *it; + if (!o->isWidgetType()) + if (QTabWidgetEventFilter *ef = qobject_cast(o)) + return ef; + } + return 0; +} + +QMenu *QTabWidgetEventFilter::addTabWidgetContextMenuActions(const QTabWidget *tabWidget, QMenu *popup) +{ + QTabWidgetEventFilter *filter = eventFilterOf(tabWidget); + if (!filter) + return 0; + return filter->addContextMenuActions(popup); +} + +QTabBar *QTabWidgetEventFilter::tabBar() const +{ + // QTabWidget::tabBar() accessor is protected, grmbl... + if (!m_cachedTabBar) { + const QList tabBars = m_tabWidget->findChildren(); + Q_ASSERT(tabBars.size() == 1); + m_cachedTabBar = tabBars.front(); + } + return m_cachedTabBar; + +} + +static bool canMove(const QPoint &pressPoint, const QMouseEvent *e) +{ + const QPoint pt = pressPoint - e->pos(); + return pt.manhattanLength() > QApplication::startDragDistance(); +} + +bool QTabWidgetEventFilter::eventFilter(QObject *o, QEvent *e) +{ + const QEvent::Type type = e->type(); + // Do not try to locate tab bar and form window, etc. for uninteresting events and + // avoid asserts about missing tab bars when being destroyed + switch (type) { + case QEvent::MouseButtonDblClick: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: + case QEvent::DragLeave: + case QEvent::DragEnter: + case QEvent::DragMove: + case QEvent::Drop: + break; + default: + return false; + } + + if (o != tabBar()) + return false; + + QDesignerFormWindowInterface *fw = formWindow(); + if (!fw) + return false; + + switch (type) { + case QEvent::MouseButtonDblClick: + break; + case QEvent::MouseButtonPress: { + QMouseEvent *mev = static_cast(e); + if (QDesignerFormWindowInterface *fw = formWindow()) { + fw->clearSelection(); + fw->selectWidget(m_tabWidget, true); + } + if (mev->button() & Qt::LeftButton) { + m_mousePressed = true; + m_pressPoint = mev->pos(); + + QTabBar *tabbar = tabBar(); + const int count = tabbar->count(); + for (int i = 0; i < count; ++i) { + if (tabbar->tabRect(i).contains(m_pressPoint)) { + if (i != tabbar->currentIndex()) { + qdesigner_internal::SetPropertyCommand *cmd = new qdesigner_internal::SetPropertyCommand(fw); + cmd->init(m_tabWidget, QLatin1String("currentIndex"), i); + fw->commandHistory()->push(cmd); + } + break; + } + } + } + } break; + + case QEvent::MouseButtonRelease: + m_mousePressed = false; + break; + + case QEvent::MouseMove: { + QMouseEvent *mouseEvent = static_cast(e); + if (m_mousePressed && canMove(m_pressPoint, mouseEvent)) { + const int index = m_tabWidget->currentIndex(); + if (index == -1) + break; + + m_mousePressed = false; + QDrag *drg = new QDrag(m_tabWidget); + drg->setMimeData(new qdesigner_internal::MyMimeData(m_tabWidget)); + + m_dragIndex = index; + m_dragPage = m_tabWidget->currentWidget(); + m_dragLabel = m_tabWidget->tabText(index); + m_dragIcon = m_tabWidget->tabIcon(index); + if (m_dragIcon.isNull()) { + QLabel *label = new QLabel(m_dragLabel); + label->adjustSize(); + drg->setPixmap(QPixmap::grabWidget(label)); + label->deleteLater(); + } else { + drg->setPixmap(m_dragIcon.pixmap(22, 22)); + } + + m_tabWidget->removeTab(m_dragIndex); + + const Qt::DropActions dropAction = drg->start(Qt::MoveAction); + + if (dropAction == Qt::IgnoreAction) { + // abort + m_tabWidget->insertTab(m_dragIndex, m_dragPage, m_dragIcon, m_dragLabel); + m_tabWidget->setCurrentIndex(m_dragIndex); + } + + if (m_dropIndicator) + m_dropIndicator->hide(); + } + } break; + + case QEvent::DragLeave: { + if (m_dropIndicator) + m_dropIndicator->hide(); + } break; + + case QEvent::DragEnter: + case QEvent::DragMove: { + QDragMoveEvent *de = static_cast(e); + if (!qdesigner_internal::MyMimeData::fromMyTab(de->mimeData(), m_tabWidget)) + return false; + + if (de->proposedAction() == Qt::MoveAction) + de->acceptProposedAction(); + else { + de->setDropAction(Qt::MoveAction); + de->accept(); + } + + QRect rect; + const int index = pageFromPosition(de->pos(), rect); + + if (!m_dropIndicator) { + m_dropIndicator = new QWidget(m_tabWidget); + QPalette p = m_dropIndicator->palette(); + p.setColor(m_tabWidget->backgroundRole(), Qt::red); + m_dropIndicator->setPalette(p); + } + + QPoint pos; + if (index == m_tabWidget->count()) + pos = tabBar()->mapToParent(QPoint(rect.x() + rect.width(), rect.y())); + else + pos = tabBar()->mapToParent(QPoint(rect.x(), rect.y())); + + m_dropIndicator->setGeometry(pos.x(), pos.y() , 3, rect.height()); + m_dropIndicator->show(); + } break; + + case QEvent::Drop: { + QDropEvent *de = static_cast(e); + if (!qdesigner_internal::MyMimeData::fromMyTab(de->mimeData(), m_tabWidget)) + return false; + de->acceptProposedAction(); + de->accept(); + + QRect rect; + const int newIndex = pageFromPosition(de->pos(), rect); + + qdesigner_internal::MoveTabPageCommand *cmd = new qdesigner_internal::MoveTabPageCommand(fw); + m_tabWidget->insertTab(m_dragIndex, m_dragPage, m_dragIcon, m_dragLabel); + cmd->init(m_tabWidget, m_dragPage, m_dragIcon, m_dragLabel, m_dragIndex, newIndex); + fw->commandHistory()->push(cmd); + } break; + + default: + break; + } + + return false; +} + +void QTabWidgetEventFilter::removeCurrentPage() +{ + if (!m_tabWidget->currentWidget()) + return; + + if (QDesignerFormWindowInterface *fw = formWindow()) { + qdesigner_internal::DeleteTabPageCommand *cmd = new qdesigner_internal::DeleteTabPageCommand(fw); + cmd->init(m_tabWidget); + fw->commandHistory()->push(cmd); + } +} + +void QTabWidgetEventFilter::addPage() +{ + if (QDesignerFormWindowInterface *fw = formWindow()) { + qdesigner_internal::AddTabPageCommand *cmd = new qdesigner_internal::AddTabPageCommand(fw); + cmd->init(m_tabWidget, qdesigner_internal::AddTabPageCommand::InsertBefore); + fw->commandHistory()->push(cmd); + } +} + +void QTabWidgetEventFilter::addPageAfter() +{ + if (QDesignerFormWindowInterface *fw = formWindow()) { + qdesigner_internal::AddTabPageCommand *cmd = new qdesigner_internal::AddTabPageCommand(fw); + cmd->init(m_tabWidget, qdesigner_internal::AddTabPageCommand::InsertAfter); + fw->commandHistory()->push(cmd); + } +} + +QDesignerFormWindowInterface *QTabWidgetEventFilter::formWindow() const +{ + return QDesignerFormWindowInterface::findFormWindow(const_cast(m_tabWidget)); +} + +// Get page from mouse position. Default to new page if in right half of last page? +int QTabWidgetEventFilter::pageFromPosition(const QPoint &pos, QRect &rect) const +{ + int index = 0; + const QTabBar *tabbar = tabBar(); + const int count = m_tabWidget->count(); + for (; index < count; index++) { + const QRect rc = tabbar->tabRect(index); + if (rc.contains(pos)) { + rect = rc; + break; + } + } + + if (index == count -1) { + QRect rect2 = rect; + rect2.setLeft(rect2.left() + rect2.width() / 2); + if (rect2.contains(pos)) + index++; + } + return index; +} + +QMenu *QTabWidgetEventFilter::addContextMenuActions(QMenu *popup) +{ + QMenu *pageMenu = 0; + const int count = m_tabWidget->count(); + m_actionDeletePage->setEnabled(count); + if (count) { + const int currentIndex = m_tabWidget->currentIndex(); + const QString pageSubMenuLabel = tr("Page %1 of %2").arg(currentIndex + 1).arg(count); + pageMenu = popup->addMenu(pageSubMenuLabel); + pageMenu->addAction(m_actionDeletePage); + // Set up promotion menu for current widget. + if (QWidget *page = m_tabWidget->currentWidget ()) { + m_pagePromotionTaskMenu->setWidget(page); + m_pagePromotionTaskMenu->addActions(QDesignerFormWindowInterface::findFormWindow(m_tabWidget), + qdesigner_internal::PromotionTaskMenu::SuppressGlobalEdit, + pageMenu); + } + QMenu *insertPageMenu = popup->addMenu(tr("Insert Page")); + insertPageMenu->addAction(m_actionInsertPageAfter); + insertPageMenu->addAction(m_actionInsertPage); + } else { + QAction *insertPageAction = popup->addAction(tr("Insert Page")); + connect(insertPageAction, SIGNAL(triggered()), this, SLOT(addPage())); + } + popup->addSeparator(); + return pageMenu; +} + +// ----------- QTabWidgetPropertySheet + +static const char *currentTabTextKey = "currentTabText"; +static const char *currentTabNameKey = "currentTabName"; +static const char *currentTabIconKey = "currentTabIcon"; +static const char *currentTabToolTipKey = "currentTabToolTip"; +static const char *currentTabWhatsThisKey = "currentTabWhatsThis"; +static const char *tabMovableKey = "movable"; + +QTabWidgetPropertySheet::QTabWidgetPropertySheet(QTabWidget *object, QObject *parent) : + QDesignerPropertySheet(object, parent), + m_tabWidget(object) +{ + createFakeProperty(QLatin1String(currentTabTextKey), QVariant::fromValue(qdesigner_internal::PropertySheetStringValue())); + createFakeProperty(QLatin1String(currentTabNameKey), QString()); + createFakeProperty(QLatin1String(currentTabIconKey), QVariant::fromValue(qdesigner_internal::PropertySheetIconValue())); + if (formWindowBase()) + formWindowBase()->addReloadableProperty(this, indexOf(QLatin1String(currentTabIconKey))); + createFakeProperty(QLatin1String(currentTabToolTipKey), QVariant::fromValue(qdesigner_internal::PropertySheetStringValue())); + createFakeProperty(QLatin1String(currentTabWhatsThisKey), QVariant::fromValue(qdesigner_internal::PropertySheetStringValue())); + // Prevent the tab widget's drag and drop handling from interfering with Designer's + createFakeProperty(QLatin1String(tabMovableKey), QVariant(false)); +} + +QTabWidgetPropertySheet::TabWidgetProperty QTabWidgetPropertySheet::tabWidgetPropertyFromName(const QString &name) +{ + typedef QHash TabWidgetPropertyHash; + static TabWidgetPropertyHash tabWidgetPropertyHash; + if (tabWidgetPropertyHash.empty()) { + tabWidgetPropertyHash.insert(QLatin1String(currentTabTextKey), PropertyCurrentTabText); + tabWidgetPropertyHash.insert(QLatin1String(currentTabNameKey), PropertyCurrentTabName); + tabWidgetPropertyHash.insert(QLatin1String(currentTabIconKey), PropertyCurrentTabIcon); + tabWidgetPropertyHash.insert(QLatin1String(currentTabToolTipKey), PropertyCurrentTabToolTip); + tabWidgetPropertyHash.insert(QLatin1String(currentTabWhatsThisKey), PropertyCurrentTabWhatsThis); + } + return tabWidgetPropertyHash.value(name, PropertyTabWidgetNone); +} + +void QTabWidgetPropertySheet::setProperty(int index, const QVariant &value) +{ + const TabWidgetProperty tabWidgetProperty = tabWidgetPropertyFromName(propertyName(index)); + if (tabWidgetProperty == PropertyTabWidgetNone) { + QDesignerPropertySheet::setProperty(index, value); + return; + } + + // index-dependent + const int currentIndex = m_tabWidget->currentIndex(); + QWidget *currentWidget = m_tabWidget->currentWidget(); + if (!currentWidget) + return; + + switch (tabWidgetProperty) { + case PropertyCurrentTabText: + m_tabWidget->setTabText(currentIndex, qvariant_cast(resolvePropertyValue(index, value))); + m_pageToData[currentWidget].text = qvariant_cast(value); + break; + case PropertyCurrentTabName: + currentWidget->setObjectName(value.toString()); + break; + case PropertyCurrentTabIcon: + m_tabWidget->setTabIcon(currentIndex, qvariant_cast(resolvePropertyValue(index, value))); + m_pageToData[currentWidget].icon = qvariant_cast(value); + break; + case PropertyCurrentTabToolTip: + m_tabWidget->setTabToolTip(currentIndex, qvariant_cast(resolvePropertyValue(index, value))); + m_pageToData[currentWidget].tooltip = qvariant_cast(value); + break; + case PropertyCurrentTabWhatsThis: + m_tabWidget->setTabWhatsThis(currentIndex, qvariant_cast(resolvePropertyValue(index, value))); + m_pageToData[currentWidget].whatsthis = qvariant_cast(value); + break; + case PropertyTabWidgetNone: + break; + } +} + +bool QTabWidgetPropertySheet::isEnabled(int index) const +{ + if (tabWidgetPropertyFromName(propertyName(index)) == PropertyTabWidgetNone) + return QDesignerPropertySheet::isEnabled(index); + return m_tabWidget->currentIndex() != -1; +} + +QVariant QTabWidgetPropertySheet::property(int index) const +{ + const TabWidgetProperty tabWidgetProperty = tabWidgetPropertyFromName(propertyName(index)); + if (tabWidgetProperty == PropertyTabWidgetNone) + return QDesignerPropertySheet::property(index); + + // index-dependent + QWidget *currentWidget = m_tabWidget->currentWidget(); + if (!currentWidget) { + if (tabWidgetProperty == PropertyCurrentTabIcon) + return QVariant::fromValue(qdesigner_internal::PropertySheetIconValue()); + if (tabWidgetProperty == PropertyCurrentTabText) + return QVariant::fromValue(qdesigner_internal::PropertySheetStringValue()); + if (tabWidgetProperty == PropertyCurrentTabToolTip) + return QVariant::fromValue(qdesigner_internal::PropertySheetStringValue()); + if (tabWidgetProperty == PropertyCurrentTabWhatsThis) + return QVariant::fromValue(qdesigner_internal::PropertySheetStringValue()); + return QVariant(QString()); + } + + // index-dependent + switch (tabWidgetProperty) { + case PropertyCurrentTabText: + return QVariant::fromValue(m_pageToData.value(currentWidget).text); + case PropertyCurrentTabName: + return currentWidget->objectName(); + case PropertyCurrentTabIcon: + return QVariant::fromValue(m_pageToData.value(currentWidget).icon); + case PropertyCurrentTabToolTip: + return QVariant::fromValue(m_pageToData.value(currentWidget).tooltip); + case PropertyCurrentTabWhatsThis: + return QVariant::fromValue(m_pageToData.value(currentWidget).whatsthis); + case PropertyTabWidgetNone: + break; + } + return QVariant(); +} + +bool QTabWidgetPropertySheet::reset(int index) +{ + const TabWidgetProperty tabWidgetProperty = tabWidgetPropertyFromName(propertyName(index)); + if (tabWidgetProperty == PropertyTabWidgetNone) + return QDesignerPropertySheet::reset(index); + + // index-dependent + QWidget *currentWidget = m_tabWidget->currentWidget(); + if (!currentWidget) + return false; + + // index-dependent + switch (tabWidgetProperty) { + case PropertyCurrentTabName: + setProperty(index, QString()); + break; + case PropertyCurrentTabToolTip: + m_pageToData[currentWidget].tooltip = qdesigner_internal::PropertySheetStringValue(); + setProperty(index, QString()); + break; + case PropertyCurrentTabWhatsThis: + m_pageToData[currentWidget].whatsthis = qdesigner_internal::PropertySheetStringValue(); + setProperty(index, QString()); + break; + case PropertyCurrentTabText: + m_pageToData[currentWidget].text = qdesigner_internal::PropertySheetStringValue(); + setProperty(index, QString()); + break; + case PropertyCurrentTabIcon: + m_pageToData[currentWidget].icon = qdesigner_internal::PropertySheetIconValue(); + setProperty(index, QIcon()); + break; + case PropertyTabWidgetNone: + break; + } + return true; +} + +bool QTabWidgetPropertySheet::checkProperty(const QString &propertyName) +{ + switch (tabWidgetPropertyFromName(propertyName)) { + case PropertyCurrentTabText: + case PropertyCurrentTabName: + case PropertyCurrentTabToolTip: + case PropertyCurrentTabWhatsThis: + case PropertyCurrentTabIcon: + return false; + default: + break; + } + return true; +} + +QT_END_NAMESPACE + +#include "qdesigner_tabwidget.moc" // required for MyMimeData diff --git a/src/designer/src/lib/shared/qdesigner_tabwidget_p.h b/src/designer/src/lib/shared/qdesigner_tabwidget_p.h new file mode 100644 index 000000000..23140a600 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_tabwidget_p.h @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_TABWIDGET_H +#define QDESIGNER_TABWIDGET_H + +#include "shared_global_p.h" +#include "qdesigner_propertysheet_p.h" +#include "qdesigner_utils_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QTabWidget; +class QTabBar; +class QMenu; +class QAction; + +namespace qdesigner_internal { + class PromotionTaskMenu; +} + +class QDESIGNER_SHARED_EXPORT QTabWidgetEventFilter : public QObject +{ + Q_OBJECT +public: + explicit QTabWidgetEventFilter(QTabWidget *parent); + ~QTabWidgetEventFilter(); + + // Install helper on QTabWidget + static void install(QTabWidget *tabWidget); + static QTabWidgetEventFilter *eventFilterOf(const QTabWidget *tabWidget); + // Convenience to add a menu on a tackedWidget + static QMenu *addTabWidgetContextMenuActions(const QTabWidget *tabWidget, QMenu *popup); + + // Add context menu and return page submenu or 0. + QMenu *addContextMenuActions(QMenu *popup); + + virtual bool eventFilter(QObject *o, QEvent *e); + + QDesignerFormWindowInterface *formWindow() const; + +private slots: + void removeCurrentPage(); + void addPage(); + void addPageAfter(); + +private: + int pageFromPosition(const QPoint &pos, QRect &rect) const; + QTabBar *tabBar() const; + + QTabWidget *m_tabWidget; + mutable QPointer m_cachedTabBar; + QPoint m_pressPoint; + QWidget *m_dropIndicator; + int m_dragIndex; + QWidget *m_dragPage; + QString m_dragLabel; + QIcon m_dragIcon; + bool m_mousePressed; + QAction *m_actionDeletePage; + QAction *m_actionInsertPage; + QAction *m_actionInsertPageAfter; + qdesigner_internal::PromotionTaskMenu* m_pagePromotionTaskMenu; +}; + +// PropertySheet to handle the page properties +class QDESIGNER_SHARED_EXPORT QTabWidgetPropertySheet : public QDesignerPropertySheet { +public: + explicit QTabWidgetPropertySheet(QTabWidget *object, QObject *parent = 0); + + virtual void setProperty(int index, const QVariant &value); + virtual QVariant property(int index) const; + virtual bool reset(int index); + virtual bool isEnabled(int index) const; + + // Check whether the property is to be saved. Returns false for the page + // properties (as the property sheet has no concept of 'stored') + static bool checkProperty(const QString &propertyName); + +private: + enum TabWidgetProperty { PropertyCurrentTabText, PropertyCurrentTabName, PropertyCurrentTabIcon, + PropertyCurrentTabToolTip, PropertyCurrentTabWhatsThis, PropertyTabWidgetNone }; + + static TabWidgetProperty tabWidgetPropertyFromName(const QString &name); + QTabWidget *m_tabWidget; + struct PageData + { + qdesigner_internal::PropertySheetStringValue text; + qdesigner_internal::PropertySheetStringValue tooltip; + qdesigner_internal::PropertySheetStringValue whatsthis; + qdesigner_internal::PropertySheetIconValue icon; + }; + QMap m_pageToData; +}; + +typedef QDesignerPropertySheetFactory QTabWidgetPropertySheetFactory; + +QT_END_NAMESPACE + +#endif // QDESIGNER_TABWIDGET_H diff --git a/src/designer/src/lib/shared/qdesigner_taskmenu.cpp b/src/designer/src/lib/shared/qdesigner_taskmenu.cpp new file mode 100644 index 000000000..5a9ace4b9 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_taskmenu.cpp @@ -0,0 +1,912 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_taskmenu_p.h" +#include "qdesigner_command_p.h" +#include "qdesigner_command2_p.h" +#include "richtexteditor_p.h" +#include "plaintexteditor_p.h" +#include "stylesheeteditor_p.h" +#include "qlayout_widget_p.h" +#include "layout_p.h" +#include "spacer_widget_p.h" +#include "textpropertyeditor_p.h" +#include "promotiontaskmenu_p.h" +#include "metadatabase_p.h" +#include "scriptdialog_p.h" +#include "scriptcommand_p.h" +#include "signalslotdialog_p.h" +#include "qdesigner_membersheet_p.h" +#include "qdesigner_propertycommand_p.h" +#include "qdesigner_utils_p.h" +#include "qdesigner_objectinspector_p.h" +#include "morphmenu_p.h" +#include "qdesigner_integration_p.h" +#include "formlayoutmenu_p.h" +#include "ui_selectsignaldialog.h" +#include "widgetfactory_p.h" +#include "abstractintrospection_p.h" +#include "widgetdatabase_p.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static QMenuBar *findMenuBar(const QWidget *widget) +{ + const QList children = widget->children(); + foreach (QObject *obj, widget->children()) { + if (QMenuBar *mb = qobject_cast(obj)) { + return mb; + } + } + + return 0; +} + +static QStatusBar *findStatusBar(const QWidget *widget) +{ + const QList children = widget->children(); + foreach (QObject *obj, widget->children()) { + if (QStatusBar *sb = qobject_cast(obj)) { + return sb; + } + } + + return 0; +} + +static inline QAction *createSeparatorHelper(QObject *parent) { + QAction *rc = new QAction(parent); + rc->setSeparator(true); + return rc; +} + +static inline qdesigner_internal::QDesignerIntegration *integration(const QDesignerFormEditorInterface *core) { + return qobject_cast(core->integration()); +} + +static QString objName(const QDesignerFormEditorInterface *core, QObject *object) { + QDesignerPropertySheetExtension *sheet + = qt_extension(core->extensionManager(), object); + Q_ASSERT(sheet != 0); + + const QString objectNameProperty = QLatin1String("objectName"); + const int index = sheet->indexOf(objectNameProperty); + const qdesigner_internal::PropertySheetStringValue objectNameValue + = qvariant_cast(sheet->property(index)); + return objectNameValue.value(); +} + +enum { ApplyMinimumWidth = 0x1, ApplyMinimumHeight = 0x2, ApplyMaximumWidth = 0x4, ApplyMaximumHeight = 0x8 }; + +namespace { +// --------------- ObjectNameDialog +class ObjectNameDialog : public QDialog +{ + public: + ObjectNameDialog(QWidget *parent, const QString &oldName); + QString newObjectName() const; + + private: + qdesigner_internal::TextPropertyEditor *m_editor; +}; + +ObjectNameDialog::ObjectNameDialog(QWidget *parent, const QString &oldName) + : QDialog(parent), + m_editor( new qdesigner_internal::TextPropertyEditor(this, qdesigner_internal::TextPropertyEditor::EmbeddingNone, + qdesigner_internal::ValidationObjectName)) +{ + setWindowTitle(QCoreApplication::translate("ObjectNameDialog", "Change Object Name")); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + + QVBoxLayout *vboxLayout = new QVBoxLayout(this); + vboxLayout->addWidget(new QLabel(QCoreApplication::translate("ObjectNameDialog", "Object Name"))); + + m_editor->setText(oldName); + m_editor->selectAll(); + m_editor->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); + vboxLayout->addWidget(m_editor); + + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, + Qt::Horizontal, this); + QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok); + okButton->setDefault(true); + vboxLayout->addWidget(buttonBox); + + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); +} + +QString ObjectNameDialog::newObjectName() const +{ + return m_editor->text(); +} +} // namespace + +namespace qdesigner_internal { + +// Sub menu displaying the alignment options of a widget in a managed +// grid/box layout cell. +class LayoutAlignmentMenu { +public: + explicit LayoutAlignmentMenu(QObject *parent); + + QAction *subMenuAction() const { return m_subMenuAction; } + + void connect(QObject *receiver, const char *aSlot); + + // Set up enabled state and checked actions according to widget (managed box/grid) + bool setAlignment(const QDesignerFormEditorInterface *core, QWidget *w); + + // Return the currently checked alignment + Qt::Alignment alignment() const; + +private: + enum Actions { HorizNone, Left, HorizCenter, Right, VerticalNone, Top, VerticalCenter, Bottom }; + static QAction *createAction(const QString &text, int data, QMenu *menu, QActionGroup *ag); + + QAction *m_subMenuAction; + QActionGroup *m_horizGroup; + QActionGroup *m_verticalGroup; + QAction *m_actions[Bottom + 1]; +}; + +QAction *LayoutAlignmentMenu::createAction(const QString &text, int data, QMenu *menu, QActionGroup *ag) +{ + QAction * a = new QAction(text, 0); + a->setCheckable(true); + a->setData(QVariant(data)); + menu->addAction(a); + ag->addAction(a); + return a; +} + +LayoutAlignmentMenu::LayoutAlignmentMenu(QObject *parent) : + m_subMenuAction(new QAction(QDesignerTaskMenu::tr("Layout Alignment"), parent)), + m_horizGroup(new QActionGroup(parent)), + m_verticalGroup(new QActionGroup(parent)) +{ + m_horizGroup->setExclusive(true); + m_verticalGroup->setExclusive(true); + + QMenu *menu = new QMenu; + m_subMenuAction->setMenu(menu); + + m_actions[HorizNone] = createAction(QDesignerTaskMenu::tr("No Horizontal Alignment"), 0, menu, m_horizGroup); + m_actions[Left] = createAction(QDesignerTaskMenu::tr("Left"), Qt::AlignLeft, menu, m_horizGroup); + m_actions[HorizCenter] = createAction(QDesignerTaskMenu::tr("Center Horizontally"), Qt::AlignHCenter, menu, m_horizGroup); + m_actions[Right] = createAction(QDesignerTaskMenu::tr("Right"), Qt::AlignRight, menu, m_horizGroup); + menu->addSeparator(); + m_actions[VerticalNone] = createAction(QDesignerTaskMenu::tr("No Vertical Alignment"), 0, menu, m_verticalGroup); + m_actions[Top] = createAction(QDesignerTaskMenu::tr("Top"), Qt::AlignTop, menu, m_verticalGroup); + m_actions[VerticalCenter] = createAction(QDesignerTaskMenu::tr("Center Vertically"), Qt::AlignVCenter, menu, m_verticalGroup); + m_actions[Bottom] = createAction(QDesignerTaskMenu::tr("Bottom"), Qt::AlignBottom, menu, m_verticalGroup); +} + +void LayoutAlignmentMenu::connect(QObject *receiver, const char *aSlot) +{ + QObject::connect(m_horizGroup, SIGNAL(triggered(QAction*)), receiver, aSlot); + QObject::connect(m_verticalGroup, SIGNAL(triggered(QAction*)), receiver, aSlot); +} + +bool LayoutAlignmentMenu::setAlignment(const QDesignerFormEditorInterface *core, QWidget *w) +{ + bool enabled; + const Qt::Alignment alignment = LayoutAlignmentCommand::alignmentOf(core, w, &enabled); + if (!enabled) { + m_subMenuAction->setEnabled(false); + m_actions[HorizNone]->setChecked(true); + m_actions[VerticalNone]->setChecked(true); + return false; + } + // Get alignment + switch (alignment & Qt::AlignHorizontal_Mask) { + case Qt::AlignLeft: + m_actions[Left]->setChecked(true); + break; + case Qt::AlignHCenter: + m_actions[HorizCenter]->setChecked(true); + break; + case Qt::AlignRight: + m_actions[Right]->setChecked(true); + break; + default: + m_actions[HorizNone]->setChecked(true); + break; + } + switch (alignment & Qt::AlignVertical_Mask) { + case Qt::AlignTop: + m_actions[Top]->setChecked(true); + break; + case Qt::AlignVCenter: + m_actions[VerticalCenter]->setChecked(true); + break; + case Qt::AlignBottom: + m_actions[Bottom]->setChecked(true); + break; + default: + m_actions[VerticalNone]->setChecked(true); + break; + } + return true; +} + +Qt::Alignment LayoutAlignmentMenu::alignment() const +{ + Qt::Alignment alignment = 0; + if (const QAction *horizAction = m_horizGroup->checkedAction()) + if (const int horizAlign = horizAction->data().toInt()) + alignment |= static_cast(horizAlign); + if (const QAction *vertAction = m_verticalGroup->checkedAction()) + if (const int vertAlign = vertAction->data().toInt()) + alignment |= static_cast(vertAlign); + return alignment; +} + +// -------------- QDesignerTaskMenuPrivate +class QDesignerTaskMenuPrivate { +public: + QDesignerTaskMenuPrivate(QWidget *widget, QObject *parent); + + QDesignerTaskMenu *m_q; + QPointer m_widget; + QAction *m_separator; + QAction *m_separator2; + QAction *m_separator3; + QAction *m_separator4; + QAction *m_separator5; + QAction *m_separator6; + QAction *m_separator7; + QAction *m_changeObjectNameAction; + QAction *m_changeToolTip; + QAction *m_changeWhatsThis; + QAction *m_changeStyleSheet; + MorphMenu *m_morphMenu; + FormLayoutMenu *m_formLayoutMenu; + + QAction *m_addMenuBar; + QAction *m_addToolBar; + QAction *m_addStatusBar; + QAction *m_removeStatusBar; + QAction *m_changeScript; + QAction *m_containerFakeMethods; + QAction *m_navigateToSlot; + PromotionTaskMenu* m_promotionTaskMenu; + QActionGroup *m_sizeActionGroup; + LayoutAlignmentMenu m_layoutAlignmentMenu; + QAction *m_sizeActionsSubMenu; +}; + +QDesignerTaskMenuPrivate::QDesignerTaskMenuPrivate(QWidget *widget, QObject *parent) : + m_q(0), + m_widget(widget), + m_separator(createSeparatorHelper(parent)), + m_separator2(createSeparatorHelper(parent)), + m_separator3(createSeparatorHelper(parent)), + m_separator4(createSeparatorHelper(parent)), + m_separator5(createSeparatorHelper(parent)), + m_separator6(createSeparatorHelper(parent)), + m_separator7(createSeparatorHelper(parent)), + m_changeObjectNameAction(new QAction(QDesignerTaskMenu::tr("Change objectName..."), parent)), + m_changeToolTip(new QAction(QDesignerTaskMenu::tr("Change toolTip..."), parent)), + m_changeWhatsThis(new QAction(QDesignerTaskMenu::tr("Change whatsThis..."), parent)), + m_changeStyleSheet(new QAction(QDesignerTaskMenu::tr("Change styleSheet..."), parent)), + m_morphMenu(new MorphMenu(parent)), + m_formLayoutMenu(new FormLayoutMenu(parent)), + m_addMenuBar(new QAction(QDesignerTaskMenu::tr("Create Menu Bar"), parent)), + m_addToolBar(new QAction(QDesignerTaskMenu::tr("Add Tool Bar"), parent)), + m_addStatusBar(new QAction(QDesignerTaskMenu::tr("Create Status Bar"), parent)), + m_removeStatusBar(new QAction(QDesignerTaskMenu::tr("Remove Status Bar"), parent)), + m_changeScript(new QAction(QDesignerTaskMenu::tr("Change script..."), parent)), + m_containerFakeMethods(new QAction(QDesignerTaskMenu::tr("Change signals/slots..."), parent)), + m_navigateToSlot(new QAction(QDesignerTaskMenu::tr("Go to slot..."), parent)), + m_promotionTaskMenu(new PromotionTaskMenu(widget, PromotionTaskMenu::ModeManagedMultiSelection, parent)), + m_sizeActionGroup(new QActionGroup(parent)), + m_layoutAlignmentMenu(parent), + m_sizeActionsSubMenu(new QAction(QDesignerTaskMenu::tr("Size Constraints"), parent)) +{ + QMenu *sizeMenu = new QMenu; + m_sizeActionsSubMenu->setMenu(sizeMenu); + QAction *sizeAction = m_sizeActionGroup->addAction(QDesignerTaskMenu::tr("Set Minimum Width")); + sizeAction->setData(ApplyMinimumWidth); + sizeMenu->addAction(sizeAction); + + sizeAction = m_sizeActionGroup->addAction(QDesignerTaskMenu::tr("Set Minimum Height")); + sizeAction->setData(ApplyMinimumHeight); + sizeMenu->addAction(sizeAction); + + sizeAction = m_sizeActionGroup->addAction(QDesignerTaskMenu::tr("Set Minimum Size")); + sizeAction->setData(ApplyMinimumWidth|ApplyMinimumHeight); + sizeMenu->addAction(sizeAction); + + sizeMenu->addSeparator(); + + sizeAction = m_sizeActionGroup->addAction(QDesignerTaskMenu::tr("Set Maximum Width")); + sizeAction->setData(ApplyMaximumWidth); + sizeMenu->addAction(sizeAction); + + sizeAction = m_sizeActionGroup->addAction(QDesignerTaskMenu::tr("Set Maximum Height")); + sizeAction->setData(ApplyMaximumHeight); + sizeMenu->addAction(sizeAction); + + sizeAction = m_sizeActionGroup->addAction(QDesignerTaskMenu::tr("Set Maximum Size")); + sizeAction->setData(ApplyMaximumWidth|ApplyMaximumHeight); + sizeMenu->addAction(sizeAction); +} + +// --------- QDesignerTaskMenu +QDesignerTaskMenu::QDesignerTaskMenu(QWidget *widget, QObject *parent) : + QObject(parent), + d(new QDesignerTaskMenuPrivate(widget, parent)) +{ + d->m_q = this; + Q_ASSERT(qobject_cast(widget) == 0); + + connect(d->m_changeObjectNameAction, SIGNAL(triggered()), this, SLOT(changeObjectName())); + connect(d->m_changeToolTip, SIGNAL(triggered()), this, SLOT(changeToolTip())); + connect(d->m_changeWhatsThis, SIGNAL(triggered()), this, SLOT(changeWhatsThis())); + connect(d->m_changeStyleSheet, SIGNAL(triggered()), this, SLOT(changeStyleSheet())); + connect(d->m_addMenuBar, SIGNAL(triggered()), this, SLOT(createMenuBar())); + connect(d->m_addToolBar, SIGNAL(triggered()), this, SLOT(addToolBar())); + connect(d->m_addStatusBar, SIGNAL(triggered()), this, SLOT(createStatusBar())); + connect(d->m_removeStatusBar, SIGNAL(triggered()), this, SLOT(removeStatusBar())); + connect(d->m_changeScript, SIGNAL(triggered()), this, SLOT(changeScript())); + connect(d->m_containerFakeMethods, SIGNAL(triggered()), this, SLOT(containerFakeMethods())); + connect(d->m_navigateToSlot, SIGNAL(triggered()), this, SLOT(slotNavigateToSlot())); + connect(d->m_sizeActionGroup, SIGNAL(triggered(QAction*)), this, SLOT(applySize(QAction*))); + d->m_layoutAlignmentMenu.connect(this, SLOT(slotLayoutAlignment())); +} + +QDesignerTaskMenu::~QDesignerTaskMenu() +{ + delete d; +} + +QAction *QDesignerTaskMenu::createSeparator() +{ + return createSeparatorHelper(this); +} + +QWidget *QDesignerTaskMenu::widget() const +{ + return d->m_widget; +} + +QDesignerFormWindowInterface *QDesignerTaskMenu::formWindow() const +{ + QDesignerFormWindowInterface *result = QDesignerFormWindowInterface::findFormWindow(widget()); + Q_ASSERT(result != 0); + return result; +} + +void QDesignerTaskMenu::createMenuBar() +{ + if (QDesignerFormWindowInterface *fw = formWindow()) { + QMainWindow *mw = qobject_cast(fw->mainContainer()); + if (!mw) { + // ### warning message + return; + } + + CreateMenuBarCommand *cmd = new CreateMenuBarCommand(fw); + cmd->init(mw); + fw->commandHistory()->push(cmd); + } +} + +void QDesignerTaskMenu::addToolBar() +{ + if (QDesignerFormWindowInterface *fw = formWindow()) { + QMainWindow *mw = qobject_cast(fw->mainContainer()); + if (!mw) { + // ### warning message + return; + } + + AddToolBarCommand *cmd = new AddToolBarCommand(fw); + cmd->init(mw); + fw->commandHistory()->push(cmd); + } +} + +void QDesignerTaskMenu::createStatusBar() +{ + if (QDesignerFormWindowInterface *fw = formWindow()) { + QMainWindow *mw = qobject_cast(fw->mainContainer()); + if (!mw) { + // ### warning message + return; + } + + CreateStatusBarCommand *cmd = new CreateStatusBarCommand(fw); + cmd->init(mw); + fw->commandHistory()->push(cmd); + } +} + +void QDesignerTaskMenu::removeStatusBar() +{ + if (QDesignerFormWindowInterface *fw = formWindow()) { + QMainWindow *mw = qobject_cast(fw->mainContainer()); + if (!mw) { + // ### warning message + return; + } + + DeleteStatusBarCommand *cmd = new DeleteStatusBarCommand(fw); + cmd->init(findStatusBar(mw)); + fw->commandHistory()->push(cmd); + } +} + +QList QDesignerTaskMenu::taskActions() const +{ + QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(widget()); + Q_ASSERT(formWindow); + + const bool isMainContainer = formWindow->mainContainer() == widget(); + + QList actions; + + if (const QMainWindow *mw = qobject_cast(formWindow->mainContainer())) { + if (isMainContainer || mw->centralWidget() == widget()) { + if (!findMenuBar(mw)) { + actions.append(d->m_addMenuBar); + } + + actions.append(d->m_addToolBar); + // ### create the status bar + if (!findStatusBar(mw)) + actions.append(d->m_addStatusBar); + else + actions.append(d->m_removeStatusBar); + actions.append(d->m_separator); + } + } + actions.append(d->m_changeObjectNameAction); + d->m_morphMenu->populate(d->m_widget, formWindow, actions); + d->m_formLayoutMenu->populate(d->m_widget, formWindow, actions); + actions.append(d->m_separator2); + actions.append(d->m_changeToolTip); + actions.append(d->m_changeWhatsThis); + actions.append(d->m_changeStyleSheet); + actions.append(d->m_separator6); + actions.append(d->m_sizeActionsSubMenu); + if (d->m_layoutAlignmentMenu.setAlignment(formWindow->core(), d->m_widget)) + actions.append(d->m_layoutAlignmentMenu.subMenuAction()); + + d->m_promotionTaskMenu->setMode(formWindow->isManaged(d->m_widget) ? + PromotionTaskMenu::ModeManagedMultiSelection : PromotionTaskMenu::ModeUnmanagedMultiSelection); + d->m_promotionTaskMenu->addActions(formWindow, PromotionTaskMenu::LeadingSeparator, actions); + +#ifdef WANT_SCRIPT_OPTION + if (!isMainContainer) { + actions.append(d->m_separator4); + actions.append(d->m_changeScript); + } +#endif + if (isMainContainer && !qt_extension(formWindow->core()->extensionManager(), formWindow->core())) { + actions.append(d->m_separator5); + actions.append(d->m_containerFakeMethods); + } + + if (isSlotNavigationEnabled(formWindow->core())) { + actions.append(d->m_separator7); + actions.append(d->m_navigateToSlot); + } + + return actions; +} + +void QDesignerTaskMenu::changeObjectName() +{ + QDesignerFormWindowInterface *fw = formWindow(); + Q_ASSERT(fw != 0); + + const QString oldObjectName = objName(fw->core(), widget()); + + ObjectNameDialog dialog(fw, oldObjectName); + if (dialog.exec() == QDialog::Accepted) { + const QString newObjectName = dialog.newObjectName(); + if (!newObjectName.isEmpty() && newObjectName != oldObjectName ) { + const QString objectNameProperty = QLatin1String("objectName"); + PropertySheetStringValue objectNameValue; + objectNameValue.setValue(newObjectName); + setProperty(fw, CurrentWidgetMode, objectNameProperty, QVariant::fromValue(objectNameValue)); + } + } +} + +void QDesignerTaskMenu::changeTextProperty(const QString &propertyName, const QString &windowTitle, PropertyMode pm, Qt::TextFormat desiredFormat) +{ + QDesignerFormWindowInterface *fw = formWindow(); + if (!fw) + return; + Q_ASSERT(d->m_widget->parentWidget() != 0); + + const QDesignerPropertySheetExtension *sheet = qt_extension(fw->core()->extensionManager(), d->m_widget); + const int index = sheet->indexOf(propertyName); + if (index == -1) { + qDebug() << "** WARNING Invalid property" << propertyName << " passed to changeTextProperty!"; + return; + } + PropertySheetStringValue textValue = qvariant_cast(sheet->property(index)); + const QString oldText = textValue.value(); + // Pop up respective dialog + bool accepted = false; + QString newText; + switch (desiredFormat) { + case Qt::PlainText: { + PlainTextEditorDialog dlg(fw->core(), fw); + if (!windowTitle.isEmpty()) + dlg.setWindowTitle(windowTitle); + dlg.setDefaultFont(d->m_widget->font()); + dlg.setText(oldText); + accepted = dlg.showDialog() == QDialog::Accepted; + newText = dlg.text(); + } + break; + default: { + RichTextEditorDialog dlg(fw->core(), fw); + if (!windowTitle.isEmpty()) + dlg.setWindowTitle(windowTitle); + dlg.setDefaultFont(d->m_widget->font()); + dlg.setText(oldText); + accepted = dlg.showDialog() == QDialog::Accepted; + newText = dlg.text(desiredFormat); + } + break; + } + // change property + if (!accepted || oldText == newText) + return; + + + textValue.setValue(newText); + setProperty(fw, pm, propertyName, QVariant::fromValue(textValue)); +} + +void QDesignerTaskMenu::changeToolTip() +{ + changeTextProperty(QLatin1String("toolTip"), tr("Edit ToolTip"), MultiSelectionMode, Qt::AutoText); +} + +void QDesignerTaskMenu::changeWhatsThis() +{ + changeTextProperty(QLatin1String("whatsThis"), tr("Edit WhatsThis"), MultiSelectionMode, Qt::AutoText); +} + +void QDesignerTaskMenu::changeStyleSheet() +{ + if (QDesignerFormWindowInterface *fw = formWindow()) { + StyleSheetPropertyEditorDialog dlg(fw, fw, d->m_widget); + dlg.exec(); + } +} + +void QDesignerTaskMenu::changeScript() +{ + QDesignerFormWindowInterface *fw = formWindow(); + if (!fw) + return; + + MetaDataBase *metaDataBase = qobject_cast(fw->core()->metaDataBase()); + if (!metaDataBase) + return; + + const MetaDataBaseItem* item = metaDataBase->metaDataBaseItem(d->m_widget); + if (!item) + return; + + const QString oldScript = item->script(); + QString newScript = oldScript; + + ScriptDialog scriptDialog(fw->core()->dialogGui(), fw); + if (!scriptDialog.editScript(newScript)) + return; + + // compile list of selected objects + ScriptCommand *scriptCommand = new ScriptCommand(fw); + if (!scriptCommand->init(applicableObjects(fw, MultiSelectionMode), newScript)) { + delete scriptCommand; + return; + } + + fw->commandHistory()->push(scriptCommand); +} + +void QDesignerTaskMenu::containerFakeMethods() +{ + QDesignerFormWindowInterface *fw = formWindow(); + if (!fw) + return; + SignalSlotDialog::editMetaDataBase(fw, d->m_widget, fw); +} + +static QString declaredInClass(const QDesignerMetaObjectInterface *metaObject, const QString &member) +{ + // Find class whose superclass does not contain the method. + const QDesignerMetaObjectInterface *meta = metaObject; + + for (;;) { + const QDesignerMetaObjectInterface *tmpMeta = meta->superClass(); + if (tmpMeta == 0) + break; + if (tmpMeta->indexOfMethod(member) == -1) + break; + meta = tmpMeta; + } + return meta->className(); +} + +bool QDesignerTaskMenu::isSlotNavigationEnabled(const QDesignerFormEditorInterface *core) +{ + if (QDesignerIntegration *integr = integration(core)) + return integr->isSlotNavigationEnabled(); + return false; +} + +void QDesignerTaskMenu::slotNavigateToSlot() +{ + QDesignerFormEditorInterface *core = formWindow()->core(); + Q_ASSERT(core); + navigateToSlot(core, widget()); +} + +void QDesignerTaskMenu::navigateToSlot(QDesignerFormEditorInterface *core, + QObject *object, + const QString &defaultSignal) +{ + const QString objectName = objName(core, object); + QMap > classToSignalList; + + QDesignerIntegration *integr = integration(core); + + // "real" signals + if (const QDesignerMetaObjectInterface *metaObject = core->introspection()->metaObject(object)) { + const int methodCount = metaObject->methodCount(); + for (int i = 0; i < methodCount; ++i) { + const QDesignerMetaMethodInterface *metaMethod = metaObject->method(i); + if (metaMethod->methodType() == QDesignerMetaMethodInterface::Signal) { + const QString signature = metaMethod->signature(); + const QStringList parameterNames = metaMethod->parameterNames(); + classToSignalList[declaredInClass(metaObject, signature)][signature] = parameterNames; + } + } + } + + // fake signals + if (qdesigner_internal::MetaDataBase *metaDataBase + = qobject_cast(core->metaDataBase())) { + qdesigner_internal::MetaDataBaseItem *item = metaDataBase->metaDataBaseItem(object); + Q_ASSERT(item); + const QStringList fakeSignals = item->fakeSignals(); + foreach (const QString &fakeSignal, fakeSignals) + classToSignalList[item->customClassName()][fakeSignal] = QStringList(); + } + + if (object->isWidgetType()) { + QWidget *widget = static_cast(object); + if (WidgetDataBase *db = qobject_cast(core->widgetDataBase())) { + const QString promotedClassName = promotedCustomClassName(core, widget); + const int index = core->widgetDataBase()->indexOfClassName(promotedClassName); + if (index >= 0) { + WidgetDataBaseItem* item = static_cast(db->item(index)); + const QStringList fakeSignals = item->fakeSignals(); + foreach (const QString &fakeSignal, fakeSignals) + classToSignalList[promotedClassName][fakeSignal] = QStringList(); + } + } + } + + Ui::SelectSignalDialog dialogUi; + QDialog selectSignalDialog(0, Qt::WindowTitleHint | Qt::WindowSystemMenuHint); + dialogUi.setupUi(&selectSignalDialog); + + QMap >::const_iterator iter(classToSignalList.constBegin()); + for (; iter != classToSignalList.constEnd(); ++iter) { + const QString className = iter.key(); + QMap signalNames = iter.value(); + + QMap::const_iterator itSignal(signalNames.constBegin()); + for (; itSignal != signalNames.constEnd(); ++itSignal) { + const QString signalName = itSignal.key(); + QTreeWidgetItem *row = new QTreeWidgetItem(QStringList() << signalName << className); + row->setData(0, Qt::UserRole, itSignal.value()); + dialogUi.signalList->addTopLevelItem(row); + } + } + if (dialogUi.signalList->topLevelItemCount() == 0) { + QTreeWidgetItem *row = new QTreeWidgetItem(QStringList() << tr("no signals available")); + dialogUi.signalList->addTopLevelItem(row); + dialogUi.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + } else { + connect(dialogUi.signalList, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), + &selectSignalDialog, SLOT(accept())); + } + + if (defaultSignal.isEmpty()) { + dialogUi.signalList->setCurrentItem(dialogUi.signalList->topLevelItem(0)); + } else { + const QList items = dialogUi.signalList->findItems (defaultSignal, Qt::MatchExactly, 0); + if (!items.empty()) + dialogUi.signalList->setCurrentItem(items.front()); + } + + dialogUi.signalList->resizeColumnToContents(0); + + if (selectSignalDialog.exec() == QDialog::Accepted) { + QTreeWidgetItem *selectedItem = dialogUi.signalList->selectedItems().first(); + const QString signalSignature = selectedItem->text(0); + const QStringList parameterNames = qvariant_cast(selectedItem->data(0, Qt::UserRole)); + + // TODO: Check whether signal is connected to slot + integr->emitNavigateToSlot(objectName, signalSignature, parameterNames); + } +} + +// Add a command that takes over the value of the current geometry as +// minimum/maximum size according to the flags. +static void createSizeCommand(QDesignerFormWindowInterface *fw, QWidget *w, int flags) +{ + const QSize size = w->size(); + if (flags & (ApplyMinimumWidth|ApplyMinimumHeight)) { + QSize minimumSize = w-> minimumSize(); + if (flags & ApplyMinimumWidth) + minimumSize.setWidth(size.width()); + if (flags & ApplyMinimumHeight) + minimumSize.setHeight(size.height()); + SetPropertyCommand* cmd = new SetPropertyCommand(fw); + cmd->init(w, QLatin1String("minimumSize"), minimumSize); + fw->commandHistory()->push(cmd); + } + if (flags & (ApplyMaximumWidth|ApplyMaximumHeight)) { + QSize maximumSize = w-> maximumSize(); + if (flags & ApplyMaximumWidth) + maximumSize.setWidth(size.width()); + if (flags & ApplyMaximumHeight) + maximumSize.setHeight(size.height()); + SetPropertyCommand* cmd = new SetPropertyCommand(fw); + cmd->init(w, QLatin1String("maximumSize"), maximumSize); + fw->commandHistory()->push(cmd); + } +} + +void QDesignerTaskMenu::applySize(QAction *a) +{ + QDesignerFormWindowInterface *fw = formWindow(); + if (!fw) + return; + + const QWidgetList selection = applicableWidgets(fw, MultiSelectionMode); + if (selection.isEmpty()) + return; + + const int mask = a->data().toInt(); + const int size = selection.size(); + fw->commandHistory()->beginMacro(tr("Set size constraint on %n widget(s)", 0, size)); + for (int i = 0; i < size; i++) + createSizeCommand(fw, selection.at(i), mask); + fw->commandHistory()->endMacro(); +} + +template + static void getApplicableObjects(const QDesignerFormWindowInterface *fw, QWidget *current, + QDesignerTaskMenu::PropertyMode pm, Container *c) +{ + // Current is always first + c->push_back(current); + if (pm == QDesignerTaskMenu::CurrentWidgetMode) + return; + QDesignerObjectInspector *designerObjectInspector = qobject_cast(fw->core()->objectInspector()); + if (!designerObjectInspector) + return; // Ooops, someone plugged an old-style Object Inspector + // Add managed or unmanaged selection according to current type, make current first + Selection s; + designerObjectInspector->getSelection(s); + const QWidgetList &source = fw->isManaged(current) ? s.managed : s.unmanaged; + const QWidgetList::const_iterator cend = source.constEnd(); + for ( QWidgetList::const_iterator it = source.constBegin(); it != cend; ++it) + if (*it != current) // was first + c->push_back(*it); +} + +QObjectList QDesignerTaskMenu::applicableObjects(const QDesignerFormWindowInterface *fw, PropertyMode pm) const +{ + QObjectList rc; + getApplicableObjects(fw, d->m_widget, pm, &rc); + return rc; +} + +QWidgetList QDesignerTaskMenu::applicableWidgets(const QDesignerFormWindowInterface *fw, PropertyMode pm) const +{ + QWidgetList rc; + getApplicableObjects(fw, d->m_widget, pm, &rc); + return rc; +} + +void QDesignerTaskMenu::setProperty(QDesignerFormWindowInterface *fw, PropertyMode pm, const QString &name, const QVariant &newValue) +{ + SetPropertyCommand* setPropertyCommand = new SetPropertyCommand(fw); + if (setPropertyCommand->init(applicableObjects(fw, pm), name, newValue, d->m_widget)) { + fw->commandHistory()->push(setPropertyCommand); + } else { + delete setPropertyCommand; + qDebug() << "Unable to set property " << name << '.'; + } +} + +void QDesignerTaskMenu::slotLayoutAlignment() +{ + QDesignerFormWindowInterface *fw = formWindow(); + const Qt::Alignment newAlignment = d->m_layoutAlignmentMenu.alignment(); + LayoutAlignmentCommand *cmd = new LayoutAlignmentCommand(fw); + if (cmd->init(d->m_widget, newAlignment)) { + fw->commandHistory()->push(cmd); + } else { + delete cmd; + } +} +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_taskmenu_p.h b/src/designer/src/lib/shared/qdesigner_taskmenu_p.h new file mode 100644 index 000000000..b86ce69b1 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_taskmenu_p.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_TASKMENU_H +#define QDESIGNER_TASKMENU_H + +#include "shared_global_p.h" +#include "extensionfactory_p.h" +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QDesignerFormEditorInterface; + +class QWidget; +class QSignalMapper; + +namespace qdesigner_internal { +class QDesignerTaskMenuPrivate; + +class QDESIGNER_SHARED_EXPORT QDesignerTaskMenu: public QObject, public QDesignerTaskMenuExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerTaskMenuExtension) +public: + QDesignerTaskMenu(QWidget *widget, QObject *parent); + virtual ~QDesignerTaskMenu(); + + QWidget *widget() const; + + virtual QList taskActions() const; + + enum PropertyMode { CurrentWidgetMode, MultiSelectionMode }; + + static bool isSlotNavigationEnabled(const QDesignerFormEditorInterface *core); + static void navigateToSlot(QDesignerFormEditorInterface *core, QObject *o, + const QString &defaultSignal = QString()); + +protected: + + QDesignerFormWindowInterface *formWindow() const; + void changeTextProperty(const QString &propertyName, const QString &windowTitle, PropertyMode pm, Qt::TextFormat desiredFormat); + + QAction *createSeparator(); + + /* Retrieve the list of objects the task menu is supposed to act on. Note that a task menu can be invoked for + * an unmanaged widget [as of 4.5], in which case it must not use the cursor selection, + * but the unmanaged selection of the object inspector. */ + QObjectList applicableObjects(const QDesignerFormWindowInterface *fw, PropertyMode pm) const; + QList applicableWidgets(const QDesignerFormWindowInterface *fw, PropertyMode pm) const; + + void setProperty(QDesignerFormWindowInterface *fw, PropertyMode pm, const QString &name, const QVariant &newValue); + +private slots: + void changeObjectName(); + void changeToolTip(); + void changeWhatsThis(); + void changeStyleSheet(); + void createMenuBar(); + void addToolBar(); + void createStatusBar(); + void removeStatusBar(); + void changeScript(); + void containerFakeMethods(); + void slotNavigateToSlot(); + void applySize(QAction *a); + void slotLayoutAlignment(); + +private: + QDesignerTaskMenuPrivate *d; +}; + +typedef ExtensionFactory QDesignerTaskMenuFactory; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QDESIGNER_TASKMENU_H diff --git a/src/designer/src/lib/shared/qdesigner_toolbar.cpp b/src/designer/src/lib/shared/qdesigner_toolbar.cpp new file mode 100644 index 000000000..0fe730384 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_toolbar.cpp @@ -0,0 +1,488 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_toolbar_p.h" +#include "qdesigner_command_p.h" +#include "actionrepository_p.h" +#include "actionprovider_p.h" +#include "qdesigner_utils_p.h" +#include "qdesigner_objectinspector_p.h" +#include "promotiontaskmenu_p.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +Q_DECLARE_METATYPE(QAction*) + +QT_BEGIN_NAMESPACE + +typedef QList ActionList; + +namespace qdesigner_internal { +// ------------------- ToolBarEventFilter +void ToolBarEventFilter::install(QToolBar *tb) +{ + ToolBarEventFilter *tf = new ToolBarEventFilter(tb); + tb->installEventFilter(tf); + tb->setAcceptDrops(true); // ### fake +} + +ToolBarEventFilter::ToolBarEventFilter(QToolBar *tb) : + QObject(tb), + m_toolBar(tb), + m_promotionTaskMenu(0) +{ +} + +ToolBarEventFilter *ToolBarEventFilter::eventFilterOf(const QToolBar *tb) +{ + // Look for 1st order children only..otherwise, we might get filters of nested widgets + const QObjectList children = tb->children(); + const QObjectList::const_iterator cend = children.constEnd(); + for (QObjectList::const_iterator it = children.constBegin(); it != cend; ++it) { + QObject *o = *it; + if (!o->isWidgetType()) + if (ToolBarEventFilter *ef = qobject_cast(o)) + return ef; + } + return 0; +} + +bool ToolBarEventFilter::eventFilter (QObject *watched, QEvent *event) +{ + if (watched != m_toolBar) + return QObject::eventFilter (watched, event); + + switch (event->type()) { + case QEvent::ChildAdded: { + // Children should not interact with the mouse + const QChildEvent *ce = static_cast(event); + if (QWidget *w = qobject_cast(ce->child())) { + w->setAttribute(Qt::WA_TransparentForMouseEvents, true); + w->setFocusPolicy(Qt::NoFocus); + } + } + break; + case QEvent::ContextMenu: + return handleContextMenuEvent(static_cast(event)); + case QEvent::DragEnter: + case QEvent::DragMove: + return handleDragEnterMoveEvent(static_cast(event)); + case QEvent::DragLeave: + return handleDragLeaveEvent(static_cast(event)); + case QEvent::Drop: + return handleDropEvent(static_cast(event)); + case QEvent::MouseButtonPress: + return handleMousePressEvent(static_cast(event)); + case QEvent::MouseButtonRelease: + return handleMouseReleaseEvent(static_cast(event)); + case QEvent::MouseMove: + return handleMouseMoveEvent(static_cast(event)); + default: + break; + } + return QObject::eventFilter (watched, event); +} + +ActionList ToolBarEventFilter::contextMenuActions(const QPoint &globalPos) +{ + ActionList rc; + const int index = actionIndexAt(m_toolBar, m_toolBar->mapFromGlobal(globalPos), m_toolBar->orientation()); + const ActionList actions = m_toolBar->actions(); + QAction *action = index != -1 ?actions.at(index) : 0; + QVariant itemData; + + // Insert before + if (action && index != 0 && !action->isSeparator()) { + QAction *newSeperatorAct = new QAction(tr("Insert Separator before '%1'").arg(action->objectName()), 0); + itemData.setValue(action); + newSeperatorAct->setData(itemData); + connect(newSeperatorAct, SIGNAL(triggered()), this, SLOT(slotInsertSeparator())); + rc.push_back(newSeperatorAct); + } + + // Append separator + if (actions.empty() || !actions.back()->isSeparator()) { + QAction *newSeperatorAct = new QAction(tr("Append Separator"), 0); + itemData.setValue(static_cast(0)); + newSeperatorAct->setData(itemData); + connect(newSeperatorAct, SIGNAL(triggered()), this, SLOT(slotInsertSeparator())); + rc.push_back(newSeperatorAct); + } + // Promotion + if (!m_promotionTaskMenu) + m_promotionTaskMenu = new PromotionTaskMenu(m_toolBar, PromotionTaskMenu::ModeSingleWidget, this); + m_promotionTaskMenu->addActions(formWindow(), PromotionTaskMenu::LeadingSeparator|PromotionTaskMenu::TrailingSeparator, rc); + // Remove + if (action) { + QAction *a = new QAction(tr("Remove action '%1'").arg(action->objectName()), 0); + itemData.setValue(action); + a->setData(itemData); + connect(a, SIGNAL(triggered()), this, SLOT(slotRemoveSelectedAction())); + rc.push_back(a); + } + + QAction *remove_toolbar = new QAction(tr("Remove Toolbar '%1'").arg(m_toolBar->objectName()), 0); + connect(remove_toolbar, SIGNAL(triggered()), this, SLOT(slotRemoveToolBar())); + rc.push_back(remove_toolbar); + return rc; +} + +bool ToolBarEventFilter::handleContextMenuEvent(QContextMenuEvent * event ) +{ + event->accept(); + + const QPoint globalPos = event->globalPos(); + const ActionList al = contextMenuActions(event->globalPos()); + + QMenu menu(0); + const ActionList::const_iterator acend = al.constEnd(); + for (ActionList::const_iterator it = al.constBegin(); it != acend; ++it) + menu.addAction(*it); + menu.exec(globalPos); + return true; +} + +void ToolBarEventFilter::slotRemoveSelectedAction() +{ + QAction *action = qobject_cast(sender()); + if (!action) + return; + + QAction *a = qvariant_cast(action->data()); + Q_ASSERT(a != 0); + + QDesignerFormWindowInterface *fw = formWindow(); + Q_ASSERT(fw); + + const ActionList actions = m_toolBar->actions(); + const int pos = actions.indexOf(a); + QAction *action_before = 0; + if (pos != -1 && actions.count() > pos + 1) + action_before = actions.at(pos + 1); + + RemoveActionFromCommand *cmd = new RemoveActionFromCommand(fw); + cmd->init(m_toolBar, a, action_before); + fw->commandHistory()->push(cmd); +} + +void ToolBarEventFilter::slotRemoveToolBar() +{ + QDesignerFormWindowInterface *fw = formWindow(); + Q_ASSERT(fw); + DeleteToolBarCommand *cmd = new DeleteToolBarCommand(fw); + cmd->init(m_toolBar); + fw->commandHistory()->push(cmd); +} + +void ToolBarEventFilter::slotInsertSeparator() +{ + QDesignerFormWindowInterface *fw = formWindow(); + QAction *theSender = qobject_cast(sender()); + QAction *previous = qvariant_cast(theSender->data()); + fw->beginCommand(tr("Insert Separator")); + QAction *action = createAction(fw, QLatin1String("separator"), true); + InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw); + cmd->init(m_toolBar, action, previous); + fw->commandHistory()->push(cmd); + fw->endCommand(); +} + +QDesignerFormWindowInterface *ToolBarEventFilter::formWindow() const +{ + return QDesignerFormWindowInterface::findFormWindow(m_toolBar); +} + +QAction *ToolBarEventFilter::createAction(QDesignerFormWindowInterface *fw, const QString &objectName, bool separator) +{ + QAction *action = new QAction(fw); + fw->core()->widgetFactory()->initialize(action); + if (separator) + action->setSeparator(true); + + action->setObjectName(objectName); + fw->ensureUniqueObjectName(action); + + qdesigner_internal::AddActionCommand *cmd = new qdesigner_internal::AddActionCommand(fw); + cmd->init(action); + fw->commandHistory()->push(cmd); + + return action; +} + +void ToolBarEventFilter::adjustDragIndicator(const QPoint &pos) +{ + if (QDesignerFormWindowInterface *fw = formWindow()) { + QDesignerFormEditorInterface *core = fw->core(); + if (QDesignerActionProviderExtension *a = qt_extension(core->extensionManager(), m_toolBar)) + a->adjustIndicator(pos); + } +} + +void ToolBarEventFilter::hideDragIndicator() +{ + adjustDragIndicator(QPoint(-1, -1)); +} + +bool ToolBarEventFilter::handleMousePressEvent(QMouseEvent *event) +{ + if (event->button() != Qt::LeftButton || withinHandleArea(m_toolBar, event->pos())) + return false; + + if (QDesignerFormWindowInterface *fw = formWindow()) { + QDesignerFormEditorInterface *core = fw->core(); + // Keep selection in sync + fw->clearSelection(false); + if (QDesignerObjectInspector *oi = qobject_cast(core->objectInspector())) { + oi->clearSelection(); + oi->selectObject(m_toolBar); + } + core->propertyEditor()->setObject(m_toolBar); + } + m_startPosition = m_toolBar->mapFromGlobal(event->globalPos()); + event->accept(); + return true; +} + +bool ToolBarEventFilter::handleMouseReleaseEvent(QMouseEvent *event) +{ + if (event->button() != Qt::LeftButton || m_startPosition.isNull() || withinHandleArea(m_toolBar, event->pos())) + return false; + + // Accept the event, otherwise, form window selection will trigger + m_startPosition = QPoint(); + event->accept(); + return true; +} + +bool ToolBarEventFilter::handleMouseMoveEvent(QMouseEvent *event) +{ + if (m_startPosition.isNull() || withinHandleArea(m_toolBar, event->pos())) + return false; + + const QPoint pos = m_toolBar->mapFromGlobal(event->globalPos()); + if ((pos - m_startPosition).manhattanLength() > qApp->startDragDistance()) { + startDrag(m_startPosition, event->modifiers()); + m_startPosition = QPoint(); + event->accept(); + return true; + } + return false; +} + +bool ToolBarEventFilter::handleDragEnterMoveEvent(QDragMoveEvent *event) +{ + const ActionRepositoryMimeData *d = qobject_cast(event->mimeData()); + if (!d) + return false; + + if (d->actionList().isEmpty()) { + event->ignore(); + hideDragIndicator(); + return true; + } + + QAction *action = d->actionList().first(); + if (!action || action->menu() || m_toolBar->actions().contains(action) || !Utils::isObjectAncestorOf(formWindow()->mainContainer(), action)) { + event->ignore(); + hideDragIndicator(); + return true; + } + + d->accept(event); + adjustDragIndicator(event->pos()); + return true; +} + +bool ToolBarEventFilter::handleDragLeaveEvent(QDragLeaveEvent *) +{ + hideDragIndicator(); + return false; +} + +bool ToolBarEventFilter::handleDropEvent(QDropEvent *event) +{ + const ActionRepositoryMimeData *d = qobject_cast(event->mimeData()); + if (!d) + return false; + + if (d->actionList().isEmpty()) { + event->ignore(); + hideDragIndicator(); + return true; + } + + QAction *action = d->actionList().first(); + + const ActionList actions = m_toolBar->actions(); + if (!action || actions.contains(action)) { + event->ignore(); + hideDragIndicator(); + return true; + } + + // Try to find action to 'insert before'. Click on action or in free area, else ignore. + QAction *beforeAction = 0; + const QPoint pos = event->pos(); + const int index = actionIndexAt(m_toolBar, pos, m_toolBar->orientation()); + if (index != -1) { + beforeAction = actions.at(index); + } else { + if (!freeArea(m_toolBar).contains(pos)) { + event->ignore(); + hideDragIndicator(); + return true; + } + } + + event->acceptProposedAction(); + QDesignerFormWindowInterface *fw = formWindow(); + InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw); + cmd->init(m_toolBar, action, beforeAction); + fw->commandHistory()->push(cmd); + hideDragIndicator(); + return true; +} + +void ToolBarEventFilter::startDrag(const QPoint &pos, Qt::KeyboardModifiers modifiers) +{ + const int index = actionIndexAt(m_toolBar, pos, m_toolBar->orientation()); + if (index == - 1) + return; + + const ActionList actions = m_toolBar->actions(); + QAction *action = actions.at(index); + QDesignerFormWindowInterface *fw = formWindow(); + + const Qt::DropAction dropAction = (modifiers & Qt::ControlModifier) ? Qt::CopyAction : Qt::MoveAction; + if (dropAction == Qt::MoveAction) { + RemoveActionFromCommand *cmd = new RemoveActionFromCommand(fw); + const int nextIndex = index + 1; + QAction *nextAction = nextIndex < actions.size() ? actions.at(nextIndex) : 0; + cmd->init(m_toolBar, action, nextAction); + fw->commandHistory()->push(cmd); + } + + QDrag *drag = new QDrag(m_toolBar); + drag->setPixmap(ActionRepositoryMimeData::actionDragPixmap( action)); + drag->setMimeData(new ActionRepositoryMimeData(action, dropAction)); + + if (drag->start(dropAction) == Qt::IgnoreAction) { + hideDragIndicator(); + if (dropAction == Qt::MoveAction) { + const ActionList currentActions = m_toolBar->actions(); + QAction *previous = 0; + if (index >= 0 && index < currentActions.size()) + previous = currentActions.at(index); + InsertActionIntoCommand *cmd = new InsertActionIntoCommand(fw); + cmd->init(m_toolBar, action, previous); + fw->commandHistory()->push(cmd); + } + } +} + +QAction *ToolBarEventFilter::actionAt(const QToolBar *tb, const QPoint &pos) +{ + const int index = actionIndexAt(tb, pos, tb->orientation()); + if (index == -1) + return 0; + return tb->actions().at(index); +} + +//that's a trick to get access to the initStyleOption which is a protected member +class FriendlyToolBar : public QToolBar { +public: + friend class ToolBarEventFilter; +}; + +QRect ToolBarEventFilter::handleArea(const QToolBar *tb) +{ + QStyleOptionToolBar opt; + static_cast(tb)->initStyleOption(&opt); + return tb->style()->subElementRect(QStyle::SE_ToolBarHandle, &opt, tb); +} + +bool ToolBarEventFilter::withinHandleArea(const QToolBar *tb, const QPoint &pos) +{ + return handleArea(tb).contains(pos); +} + +// Determine the free area behind the last action. +QRect ToolBarEventFilter::freeArea(const QToolBar *tb) +{ + QRect rc = QRect(QPoint(0, 0), tb->size()); + const ActionList actionList = tb->actions(); + QRect exclusionRectangle = actionList.empty() ? handleArea(tb) : tb->actionGeometry(actionList.back()); + switch (tb->orientation()) { + case Qt::Horizontal: + switch (tb->layoutDirection()) { + case Qt::LayoutDirectionAuto: // Should never happen + case Qt::LeftToRight: + rc.setX(exclusionRectangle.right() + 1); + break; + case Qt::RightToLeft: + rc.setRight(exclusionRectangle.x()); + break; + } + break; + case Qt::Vertical: + rc.setY(exclusionRectangle.bottom() + 1); + break; + } + return rc; +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_toolbar_p.h b/src/designer/src/lib/shared/qdesigner_toolbar_p.h new file mode 100644 index 000000000..7a38ec773 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_toolbar_p.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_TOOLBAR_H +#define QDESIGNER_TOOLBAR_H + +#include "shared_global_p.h" + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QToolBar; +class QRect; +class QAction; + +namespace qdesigner_internal { + +class PromotionTaskMenu; + +// Special event filter for tool bars in designer. +// Handles drag and drop to and from. Ensures that each +// child widget is WA_TransparentForMouseEvents to enable drag and drop. + +class QDESIGNER_SHARED_EXPORT ToolBarEventFilter : public QObject { + Q_OBJECT + +public: + static void install(QToolBar *tb); + + // Find action by position. Note that QToolBar::actionAt() will + // not work as designer sets WA_TransparentForMouseEvents on its tool bar buttons + // to be able to drag them. This function will return the dummy + // sentinel action when applied to tool bars created by designer if the position matches. + static QAction *actionAt(const QToolBar *tb, const QPoint &pos); + + static bool withinHandleArea(const QToolBar *tb, const QPoint &pos); + static QRect handleArea(const QToolBar *tb); + static QRect freeArea(const QToolBar *tb); + + // Utility to create an action + static QAction *createAction(QDesignerFormWindowInterface *fw, const QString &objectName, bool separator); + + virtual bool eventFilter (QObject *watched, QEvent *event); + + // Helper for task menu extension + QList contextMenuActions(const QPoint &globalPos = QPoint(-1, -1)); + + static ToolBarEventFilter *eventFilterOf(const QToolBar *tb); + +private slots: + void slotRemoveSelectedAction(); + void slotRemoveToolBar(); + void slotInsertSeparator(); + +private: + explicit ToolBarEventFilter(QToolBar *tb); + + bool handleContextMenuEvent(QContextMenuEvent * event); + bool handleDragEnterMoveEvent(QDragMoveEvent *event); + bool handleDragLeaveEvent(QDragLeaveEvent *); + bool handleDropEvent(QDropEvent *event); + bool handleMousePressEvent(QMouseEvent *event); + bool handleMouseReleaseEvent(QMouseEvent *event); + bool handleMouseMoveEvent(QMouseEvent *event); + + QDesignerFormWindowInterface *formWindow() const; + void adjustDragIndicator(const QPoint &pos); + void hideDragIndicator(); + void startDrag(const QPoint &pos, Qt::KeyboardModifiers modifiers); + bool withinHandleArea(const QPoint &pos) const; + + QToolBar *m_toolBar; + PromotionTaskMenu *m_promotionTaskMenu; + QPoint m_startPosition; +}; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QDESIGNER_TOOLBAR_H diff --git a/src/designer/src/lib/shared/qdesigner_toolbox.cpp b/src/designer/src/lib/shared/qdesigner_toolbox.cpp new file mode 100644 index 000000000..675e98c36 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_toolbox.cpp @@ -0,0 +1,437 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_toolbox_p.h" +#include "qdesigner_command_p.h" +#include "orderdialog_p.h" +#include "promotiontaskmenu_p.h" +#include "formwindowbase_p.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +QToolBoxHelper::QToolBoxHelper(QToolBox *toolbox) : + QObject(toolbox), + m_toolbox(toolbox), + m_actionDeletePage(new QAction(tr("Delete Page"), this)), + m_actionInsertPage(new QAction(tr("Before Current Page"), this)), + m_actionInsertPageAfter(new QAction(tr("After Current Page"), this)), + m_actionChangePageOrder(new QAction(tr("Change Page Order..."), this)), + m_pagePromotionTaskMenu(new qdesigner_internal::PromotionTaskMenu(0, qdesigner_internal::PromotionTaskMenu::ModeSingleWidget, this)) +{ + connect(m_actionDeletePage, SIGNAL(triggered()), this, SLOT(removeCurrentPage())); + connect(m_actionInsertPage, SIGNAL(triggered()), this, SLOT(addPage())); + connect(m_actionInsertPageAfter, SIGNAL(triggered()), this, SLOT(addPageAfter())); + connect(m_actionChangePageOrder, SIGNAL(triggered()), this, SLOT(changeOrder())); + + m_toolbox->installEventFilter(this); +} + +void QToolBoxHelper::install(QToolBox *toolbox) +{ + new QToolBoxHelper(toolbox); +} + +bool QToolBoxHelper::eventFilter(QObject *watched, QEvent *event) +{ + switch (event->type()) { + case QEvent::ChildPolished: + // Install on the buttons + if (watched == m_toolbox) { + QChildEvent *ce = static_cast(event); + if (!qstrcmp(ce->child()->metaObject()->className(), "QToolBoxButton")) + ce->child()->installEventFilter(this); + } + break; + case QEvent::ContextMenu: + if (watched != m_toolbox) { + // An action invoked from the passive interactor (ToolBox button) might + // cause its deletion within its event handler, triggering a warning. Re-post + // the event to the toolbox. + QContextMenuEvent *current = static_cast(event); + QContextMenuEvent *copy = new QContextMenuEvent(current->reason(), current->pos(), current-> globalPos(), current->modifiers()); + QApplication::postEvent(m_toolbox, copy); + current->accept(); + return true; + } + break; + case QEvent::MouseButtonRelease: + if (watched != m_toolbox) + if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(m_toolbox)) { + fw->clearSelection(); + fw->selectWidget(m_toolbox, true); + } + break; + default: + break; + } + return QObject::eventFilter(watched, event); +} + +QToolBoxHelper *QToolBoxHelper::helperOf(const QToolBox *toolbox) +{ + // Look for 1st order children only..otherwise, we might get filters of nested widgets + const QObjectList children = toolbox->children(); + const QObjectList::const_iterator cend = children.constEnd(); + for (QObjectList::const_iterator it = children.constBegin(); it != cend; ++it) { + QObject *o = *it; + if (!o->isWidgetType()) + if (QToolBoxHelper *h = qobject_cast(o)) + return h; + } + return 0; +} + +QMenu *QToolBoxHelper::addToolBoxContextMenuActions(const QToolBox *toolbox, QMenu *popup) +{ + QToolBoxHelper *helper = helperOf(toolbox); + if (!helper) + return 0; + return helper->addContextMenuActions(popup); +} + +void QToolBoxHelper::removeCurrentPage() +{ + if (m_toolbox->currentIndex() == -1 || !m_toolbox->widget(m_toolbox->currentIndex())) + return; + + if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(m_toolbox)) { + qdesigner_internal::DeleteToolBoxPageCommand *cmd = new qdesigner_internal::DeleteToolBoxPageCommand(fw); + cmd->init(m_toolbox); + fw->commandHistory()->push(cmd); + } +} + +void QToolBoxHelper::addPage() +{ + if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(m_toolbox)) { + qdesigner_internal::AddToolBoxPageCommand *cmd = new qdesigner_internal::AddToolBoxPageCommand(fw); + cmd->init(m_toolbox, qdesigner_internal::AddToolBoxPageCommand::InsertBefore); + fw->commandHistory()->push(cmd); + } +} + +void QToolBoxHelper::changeOrder() +{ + QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(m_toolbox); + + if (!fw) + return; + + const QWidgetList oldPages = qdesigner_internal::OrderDialog::pagesOfContainer(fw->core(), m_toolbox); + const int pageCount = oldPages.size(); + if (pageCount < 2) + return; + + qdesigner_internal::OrderDialog dlg(fw); + dlg.setPageList(oldPages); + if (dlg.exec() == QDialog::Rejected) + return; + + const QWidgetList newPages = dlg.pageList(); + if (newPages == oldPages) + return; + + fw->beginCommand(tr("Change Page Order")); + for(int i=0; i < pageCount; ++i) { + if (newPages.at(i) == m_toolbox->widget(i)) + continue; + qdesigner_internal::MoveToolBoxPageCommand *cmd = new qdesigner_internal::MoveToolBoxPageCommand(fw); + cmd->init(m_toolbox, newPages.at(i), i); + fw->commandHistory()->push(cmd); + } + fw->endCommand(); +} + +void QToolBoxHelper::addPageAfter() +{ + if (QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(m_toolbox)) { + qdesigner_internal::AddToolBoxPageCommand *cmd = new qdesigner_internal::AddToolBoxPageCommand(fw); + cmd->init(m_toolbox, qdesigner_internal::AddToolBoxPageCommand::InsertAfter); + fw->commandHistory()->push(cmd); + } +} + +QPalette::ColorRole QToolBoxHelper::currentItemBackgroundRole() const +{ + const QWidget *w = m_toolbox->widget(0); + if (!w) + return QPalette::Window; + return w->backgroundRole(); +} + +void QToolBoxHelper::setCurrentItemBackgroundRole(QPalette::ColorRole role) +{ + const int count = m_toolbox->count(); + for (int i = 0; i < count; ++i) { + QWidget *w = m_toolbox->widget(i); + w->setBackgroundRole(role); + w->update(); + } +} + +QMenu *QToolBoxHelper::addContextMenuActions(QMenu *popup) const +{ + QMenu *pageMenu = 0; + const int count = m_toolbox->count(); + m_actionDeletePage->setEnabled(count > 1); + if (count) { + const QString pageSubMenuLabel = tr("Page %1 of %2").arg(m_toolbox->currentIndex() + 1).arg(count); + pageMenu = popup->addMenu(pageSubMenuLabel); + + pageMenu->addAction(m_actionDeletePage); + // Set up promotion menu for current widget. + if (QWidget *page = m_toolbox->currentWidget ()) { + m_pagePromotionTaskMenu->setWidget(page); + m_pagePromotionTaskMenu->addActions(QDesignerFormWindowInterface::findFormWindow(m_toolbox), + qdesigner_internal::PromotionTaskMenu::SuppressGlobalEdit, + pageMenu); + } + } + QMenu *insertPageMenu = popup->addMenu(tr("Insert Page")); + insertPageMenu->addAction(m_actionInsertPageAfter); + insertPageMenu->addAction(m_actionInsertPage); + if (count > 1) { + popup->addAction(m_actionChangePageOrder); + } + popup->addSeparator(); + return pageMenu; +} + +// -------- QToolBoxWidgetPropertySheet + +static const char *currentItemTextKey = "currentItemText"; +static const char *currentItemNameKey = "currentItemName"; +static const char *currentItemIconKey = "currentItemIcon"; +static const char *currentItemToolTipKey = "currentItemToolTip"; +static const char *tabSpacingKey = "tabSpacing"; + +enum { tabSpacingDefault = -1 }; + +QToolBoxWidgetPropertySheet::QToolBoxWidgetPropertySheet(QToolBox *object, QObject *parent) : + QDesignerPropertySheet(object, parent), + m_toolBox(object) +{ + createFakeProperty(QLatin1String(currentItemTextKey), QVariant::fromValue(qdesigner_internal::PropertySheetStringValue())); + createFakeProperty(QLatin1String(currentItemNameKey), QString()); + createFakeProperty(QLatin1String(currentItemIconKey), QVariant::fromValue(qdesigner_internal::PropertySheetIconValue())); + if (formWindowBase()) + formWindowBase()->addReloadableProperty(this, indexOf(QLatin1String(currentItemIconKey))); + createFakeProperty(QLatin1String(currentItemToolTipKey), QVariant::fromValue(qdesigner_internal::PropertySheetStringValue())); + createFakeProperty(QLatin1String(tabSpacingKey), QVariant(tabSpacingDefault)); +} + +QToolBoxWidgetPropertySheet::ToolBoxProperty QToolBoxWidgetPropertySheet::toolBoxPropertyFromName(const QString &name) +{ + typedef QHash ToolBoxPropertyHash; + static ToolBoxPropertyHash toolBoxPropertyHash; + if (toolBoxPropertyHash.empty()) { + toolBoxPropertyHash.insert(QLatin1String(currentItemTextKey), PropertyCurrentItemText); + toolBoxPropertyHash.insert(QLatin1String(currentItemNameKey), PropertyCurrentItemName); + toolBoxPropertyHash.insert(QLatin1String(currentItemIconKey), PropertyCurrentItemIcon); + toolBoxPropertyHash.insert(QLatin1String(currentItemToolTipKey), PropertyCurrentItemToolTip); + toolBoxPropertyHash.insert(QLatin1String(tabSpacingKey), PropertyTabSpacing); + } + return toolBoxPropertyHash.value(name, PropertyToolBoxNone); +} + +void QToolBoxWidgetPropertySheet::setProperty(int index, const QVariant &value) +{ + const ToolBoxProperty toolBoxProperty = toolBoxPropertyFromName(propertyName(index)); + // independent of index + switch (toolBoxProperty) { + case PropertyTabSpacing: + m_toolBox->layout()->setSpacing(value.toInt()); + return; + case PropertyToolBoxNone: + QDesignerPropertySheet::setProperty(index, value); + return; + default: + break; + } + // index-dependent + const int currentIndex = m_toolBox->currentIndex(); + QWidget *currentWidget = m_toolBox->currentWidget(); + if (!currentWidget) + return; + + switch (toolBoxProperty) { + case PropertyCurrentItemText: + m_toolBox->setItemText(currentIndex, qvariant_cast(resolvePropertyValue(index, value))); + m_pageToData[currentWidget].text = qvariant_cast(value); + break; + case PropertyCurrentItemName: + currentWidget->setObjectName(value.toString()); + break; + case PropertyCurrentItemIcon: + m_toolBox->setItemIcon(currentIndex, qvariant_cast(resolvePropertyValue(index, value))); + m_pageToData[currentWidget].icon = qvariant_cast(value); + break; + case PropertyCurrentItemToolTip: + m_toolBox->setItemToolTip(currentIndex, qvariant_cast(resolvePropertyValue(index, value))); + m_pageToData[currentWidget].tooltip = qvariant_cast(value); + break; + case PropertyTabSpacing: + case PropertyToolBoxNone: + break; + } +} + +bool QToolBoxWidgetPropertySheet::isEnabled(int index) const +{ + switch (toolBoxPropertyFromName(propertyName(index))) { + case PropertyToolBoxNone: // independent of index + case PropertyTabSpacing: + return QDesignerPropertySheet::isEnabled(index); + default: + break; + } + return m_toolBox->currentIndex() != -1; +} + +QVariant QToolBoxWidgetPropertySheet::property(int index) const +{ + const ToolBoxProperty toolBoxProperty = toolBoxPropertyFromName(propertyName(index)); + // independent of index + switch (toolBoxProperty) { + case PropertyTabSpacing: + return m_toolBox->layout()->spacing(); + case PropertyToolBoxNone: + return QDesignerPropertySheet::property(index); + default: + break; + } + // index-dependent + QWidget *currentWidget = m_toolBox->currentWidget(); + if (!currentWidget) { + if (toolBoxProperty == PropertyCurrentItemIcon) + return QVariant::fromValue(qdesigner_internal::PropertySheetIconValue()); + if (toolBoxProperty == PropertyCurrentItemText) + return QVariant::fromValue(qdesigner_internal::PropertySheetStringValue()); + if (toolBoxProperty == PropertyCurrentItemToolTip) + return QVariant::fromValue(qdesigner_internal::PropertySheetStringValue()); + return QVariant(QString()); + } + + // index-dependent + switch (toolBoxProperty) { + case PropertyCurrentItemText: + return QVariant::fromValue(m_pageToData.value(currentWidget).text); + case PropertyCurrentItemName: + return currentWidget->objectName(); + case PropertyCurrentItemIcon: + return QVariant::fromValue(m_pageToData.value(currentWidget).icon); + case PropertyCurrentItemToolTip: + return QVariant::fromValue(m_pageToData.value(currentWidget).tooltip); + case PropertyTabSpacing: + case PropertyToolBoxNone: + break; + } + return QVariant(); +} + +bool QToolBoxWidgetPropertySheet::reset(int index) +{ + const ToolBoxProperty toolBoxProperty = toolBoxPropertyFromName(propertyName(index)); + // independent of index + switch (toolBoxProperty) { + case PropertyTabSpacing: + setProperty(index, QVariant(tabSpacingDefault)); + return true; + case PropertyToolBoxNone: + return QDesignerPropertySheet::reset(index); + default: + break; + } + // index-dependent + QWidget *currentWidget = m_toolBox->currentWidget(); + if (!currentWidget) + return false; + + // index-dependent + switch (toolBoxProperty) { + case PropertyCurrentItemName: + setProperty(index, QString()); + break; + case PropertyCurrentItemToolTip: + m_pageToData[currentWidget].tooltip = qdesigner_internal::PropertySheetStringValue(); + setProperty(index, QString()); + break; + case PropertyCurrentItemText: + m_pageToData[currentWidget].text = qdesigner_internal::PropertySheetStringValue(); + setProperty(index, QString()); + break; + case PropertyCurrentItemIcon: + m_pageToData[currentWidget].icon = qdesigner_internal::PropertySheetIconValue(); + setProperty(index, QIcon()); + break; + case PropertyTabSpacing: + case PropertyToolBoxNone: + break; + } + return true; +} + +bool QToolBoxWidgetPropertySheet::checkProperty(const QString &propertyName) +{ + switch (toolBoxPropertyFromName(propertyName)) { + case PropertyCurrentItemText: + case PropertyCurrentItemName: + case PropertyCurrentItemToolTip: + case PropertyCurrentItemIcon: + return false; + default: + break; + } + return true; +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_toolbox_p.h b/src/designer/src/lib/shared/qdesigner_toolbox_p.h new file mode 100644 index 000000000..f9d390ed0 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_toolbox_p.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_TOOLBOX_H +#define QDESIGNER_TOOLBOX_H + +#include "shared_global_p.h" +#include "qdesigner_propertysheet_p.h" +#include "qdesigner_utils_p.h" +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + class PromotionTaskMenu; +} + +class QToolBox; + +class QAction; +class QMenu; + +class QDESIGNER_SHARED_EXPORT QToolBoxHelper : public QObject +{ + Q_OBJECT + + explicit QToolBoxHelper(QToolBox *toolbox); +public: + // Install helper on QToolBox + static void install(QToolBox *toolbox); + static QToolBoxHelper *helperOf(const QToolBox *toolbox); + // Convenience to add a menu on a toolbox + static QMenu *addToolBoxContextMenuActions(const QToolBox *toolbox, QMenu *popup); + + QPalette::ColorRole currentItemBackgroundRole() const; + void setCurrentItemBackgroundRole(QPalette::ColorRole role); + + bool eventFilter(QObject *watched, QEvent *event); + // Add context menu and return page submenu or 0. + + QMenu *addContextMenuActions(QMenu *popup) const; + +private slots: + void removeCurrentPage(); + void addPage(); + void addPageAfter(); + void changeOrder(); + +private: + QToolBox *m_toolbox; + QAction *m_actionDeletePage; + QAction *m_actionInsertPage; + QAction *m_actionInsertPageAfter; + QAction *m_actionChangePageOrder; + qdesigner_internal::PromotionTaskMenu* m_pagePromotionTaskMenu; +}; + +// PropertySheet to handle the page properties +class QDESIGNER_SHARED_EXPORT QToolBoxWidgetPropertySheet : public QDesignerPropertySheet { +public: + explicit QToolBoxWidgetPropertySheet(QToolBox *object, QObject *parent = 0); + + virtual void setProperty(int index, const QVariant &value); + virtual QVariant property(int index) const; + virtual bool reset(int index); + virtual bool isEnabled(int index) const; + + // Check whether the property is to be saved. Returns false for the page + // properties (as the property sheet has no concept of 'stored') + static bool checkProperty(const QString &propertyName); + +private: + enum ToolBoxProperty { PropertyCurrentItemText, PropertyCurrentItemName, PropertyCurrentItemIcon, + PropertyCurrentItemToolTip, PropertyTabSpacing, PropertyToolBoxNone }; + + static ToolBoxProperty toolBoxPropertyFromName(const QString &name); + QToolBox *m_toolBox; + struct PageData + { + qdesigner_internal::PropertySheetStringValue text; + qdesigner_internal::PropertySheetStringValue tooltip; + qdesigner_internal::PropertySheetIconValue icon; + }; + QMap m_pageToData; +}; + +typedef QDesignerPropertySheetFactory QToolBoxWidgetPropertySheetFactory; + +QT_END_NAMESPACE + +#endif // QDESIGNER_TOOLBOX_H diff --git a/src/designer/src/lib/shared/qdesigner_utils.cpp b/src/designer/src/lib/shared/qdesigner_utils.cpp new file mode 100644 index 000000000..1c6c8547c --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_utils.cpp @@ -0,0 +1,848 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_utils_p.h" +#include "qdesigner_propertycommand_p.h" +#include "abstractformbuilder.h" +#include "formwindowbase_p.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal +{ + QDESIGNER_SHARED_EXPORT void designerWarning(const QString &message) + { + qWarning("Designer: %s", qPrintable(message)); + } + + void reloadTreeItem(DesignerIconCache *iconCache, QTreeWidgetItem *item) + { + if (!item) + return; + + for (int c = 0; c < item->columnCount(); c++) { + const QVariant v = item->data(c, Qt::DecorationPropertyRole); + if (v.canConvert()) + item->setIcon(c, iconCache->icon(qvariant_cast(v))); + } + } + + void reloadListItem(DesignerIconCache *iconCache, QListWidgetItem *item) + { + if (!item) + return; + + const QVariant v = item->data(Qt::DecorationPropertyRole); + if (v.canConvert()) + item->setIcon(iconCache->icon(qvariant_cast(v))); + } + + void reloadTableItem(DesignerIconCache *iconCache, QTableWidgetItem *item) + { + if (!item) + return; + + const QVariant v = item->data(Qt::DecorationPropertyRole); + if (v.canConvert()) + item->setIcon(iconCache->icon(qvariant_cast(v))); + } + + void reloadIconResources(DesignerIconCache *iconCache, QObject *object) + { + if (QListWidget *listWidget = qobject_cast(object)) { + for (int i = 0; i < listWidget->count(); i++) + reloadListItem(iconCache, listWidget->item(i)); + } else if (QComboBox *comboBox = qobject_cast(object)) { + for (int i = 0; i < comboBox->count(); i++) { + const QVariant v = comboBox->itemData(i, Qt::DecorationPropertyRole); + if (v.canConvert()) { + QIcon icon = iconCache->icon(qvariant_cast(v)); + comboBox->setItemIcon(i, icon); + comboBox->setItemData(i, icon); + } + } + } else if (QTreeWidget *treeWidget = qobject_cast(object)) { + reloadTreeItem(iconCache, treeWidget->headerItem()); + QQueue itemsQueue; + for (int i = 0; i < treeWidget->topLevelItemCount(); i++) + itemsQueue.enqueue(treeWidget->topLevelItem(i)); + while (!itemsQueue.isEmpty()) { + QTreeWidgetItem *item = itemsQueue.dequeue(); + for (int i = 0; i < item->childCount(); i++) + itemsQueue.enqueue(item->child(i)); + reloadTreeItem(iconCache, item); + } + } else if (QTableWidget *tableWidget = qobject_cast(object)) { + const int columnCount = tableWidget->columnCount(); + const int rowCount = tableWidget->rowCount(); + for (int c = 0; c < columnCount; c++) + reloadTableItem(iconCache, tableWidget->horizontalHeaderItem(c)); + for (int r = 0; r < rowCount; r++) + reloadTableItem(iconCache, tableWidget->verticalHeaderItem(r)); + for (int c = 0; c < columnCount; c++) + for (int r = 0; r < rowCount; r++) + reloadTableItem(iconCache, tableWidget->item(r, c)); + } + } + + // ------------- DesignerMetaEnum + DesignerMetaEnum::DesignerMetaEnum(const QString &name, const QString &scope, const QString &separator) : + MetaEnum(name, scope, separator) + { + } + + + QString DesignerMetaEnum::toString(int value, SerializationMode sm, bool *ok) const + { + // find value + bool valueOk; + const QString item = valueToKey(value, &valueOk); + if (ok) + *ok = valueOk; + + if (!valueOk || sm == NameOnly) + return item; + + QString qualifiedItem; + appendQualifiedName(item, qualifiedItem); + return qualifiedItem; + } + + QString DesignerMetaEnum::messageToStringFailed(int value) const + { + return QCoreApplication::translate("DesignerMetaEnum", "%1 is not a valid enumeration value of '%2'.").arg(value).arg(name()); + } + + QString DesignerMetaEnum::messageParseFailed(const QString &s) const + { + return QCoreApplication::translate("DesignerMetaEnum", "'%1' could not be converted to an enumeration value of type '%2'.").arg(s).arg(name()); + } + // -------------- DesignerMetaFlags + DesignerMetaFlags::DesignerMetaFlags(const QString &name, const QString &scope, const QString &separator) : + MetaEnum(name, scope, separator) + { + } + + QStringList DesignerMetaFlags::flags(int ivalue) const + { + typedef MetaEnum::KeyToValueMap::const_iterator KeyToValueMapIterator; + QStringList rc; + const uint v = static_cast(ivalue); + const KeyToValueMapIterator cend = keyToValueMap().constEnd(); + for (KeyToValueMapIterator it = keyToValueMap().constBegin();it != cend; ++it ) { + const uint itemValue = it.value(); + // Check for equality first as flag values can be 0 or -1, too. Takes preference over a bitwise flag + if (v == itemValue) { + rc.clear(); + rc.push_back(it.key()); + return rc; + } + // Do not add 0-flags (None-flags) + if (itemValue) + if ((v & itemValue) == itemValue) + rc.push_back(it.key()); + } + return rc; + } + + + QString DesignerMetaFlags::toString(int value, SerializationMode sm) const + { + const QStringList flagIds = flags(value); + if (flagIds.empty()) + return QString(); + + const QChar delimiter = QLatin1Char('|'); + QString rc; + const QStringList::const_iterator cend = flagIds.constEnd(); + for (QStringList::const_iterator it = flagIds.constBegin(); it != cend; ++it) { + if (!rc.isEmpty()) + rc += delimiter ; + if (sm == FullyQualified) + appendQualifiedName(*it, rc); + else + rc += *it; + } + return rc; + } + + + int DesignerMetaFlags::parseFlags(const QString &s, bool *ok) const + { + if (s.isEmpty()) { + if (ok) + *ok = true; + return 0; + } + uint flags = 0; + bool valueOk = true; + QStringList keys = s.split(QString(QLatin1Char('|'))); + const QStringList::iterator cend = keys.end(); + for (QStringList::iterator it = keys.begin(); it != cend; ++it) { + const uint flagValue = keyToValue(*it, &valueOk); + if (!valueOk) { + flags = 0; + break; + } + flags |= flagValue; + } + if (ok) + *ok = valueOk; + return static_cast(flags); + } + + QString DesignerMetaFlags::messageParseFailed(const QString &s) const + { + return QCoreApplication::translate("DesignerMetaFlags", "'%1' could not be converted to a flag value of type '%2'.").arg(s).arg(name()); + } + + // ---------- PropertySheetEnumValue + + PropertySheetEnumValue::PropertySheetEnumValue(int v, const DesignerMetaEnum &me) : + value(v), + metaEnum(me) + { + } + PropertySheetEnumValue::PropertySheetEnumValue() : + value(0) + { + } + + // ---------------- PropertySheetFlagValue + PropertySheetFlagValue::PropertySheetFlagValue(int v, const DesignerMetaFlags &mf) : + value(v), + metaFlags(mf) + { + } + + PropertySheetFlagValue::PropertySheetFlagValue() : + value(0) + { + } + + // ---------------- PropertySheetPixmapValue + PropertySheetPixmapValue::PropertySheetPixmapValue(const QString &path) : m_path(path) + { + } + + PropertySheetPixmapValue::PropertySheetPixmapValue() + { + } + + PropertySheetPixmapValue::PixmapSource PropertySheetPixmapValue::getPixmapSource(QDesignerFormEditorInterface *core, const QString & path) + { + if (const QDesignerLanguageExtension *lang = qt_extension(core->extensionManager(), core)) + return lang->isLanguageResource(path) ? LanguageResourcePixmap : FilePixmap; + return path.startsWith(QLatin1Char(':')) ? ResourcePixmap : FilePixmap; + } + + int PropertySheetPixmapValue::compare(const PropertySheetPixmapValue &other) const + { + return m_path.compare(other.m_path); + } + + QString PropertySheetPixmapValue::path() const + { + return m_path; + } + + void PropertySheetPixmapValue::setPath(const QString &path) + { + if (m_path == path) + return; + m_path = path; + } + + // ---------- PropertySheetIconValue + + class PropertySheetIconValueData : public QSharedData { + public: + PropertySheetIconValue::ModeStateToPixmapMap m_paths; + QString m_theme; + }; + + PropertySheetIconValue::PropertySheetIconValue(const PropertySheetPixmapValue &pixmap) : + m_data(new PropertySheetIconValueData) + { + setPixmap(QIcon::Normal, QIcon::Off, pixmap); + } + + PropertySheetIconValue::PropertySheetIconValue() : + m_data(new PropertySheetIconValueData) + { + } + + PropertySheetIconValue::~PropertySheetIconValue() + { + } + + PropertySheetIconValue::PropertySheetIconValue(const PropertySheetIconValue &rhs) : + m_data(rhs.m_data) + { + } + + PropertySheetIconValue &PropertySheetIconValue::operator=(const PropertySheetIconValue &rhs) + { + if (this != &rhs) + m_data.operator=(rhs.m_data); + return *this; + } + + bool PropertySheetIconValue::equals(const PropertySheetIconValue &rhs) const + { + return m_data->m_theme == rhs.m_data->m_theme && m_data->m_paths == rhs.m_data->m_paths; + } + + bool PropertySheetIconValue::operator<(const PropertySheetIconValue &other) const + { + if (const int themeCmp = m_data->m_theme.compare(other.m_data->m_theme)) + return themeCmp < 0; + QMapIterator itThis(m_data->m_paths); + QMapIterator itOther(other.m_data->m_paths); + while (itThis.hasNext() && itOther.hasNext()) { + const ModeStateKey thisPair = itThis.next().key(); + const ModeStateKey otherPair = itOther.next().key(); + if (thisPair < otherPair) + return true; + else if (otherPair < thisPair) + return false; + const int crc = itThis.value().compare(itOther.value()); + if (crc < 0) + return true; + if (crc > 0) + return false; + } + if (itOther.hasNext()) + return true; + return false; + } + + bool PropertySheetIconValue::isEmpty() const + { + return m_data->m_theme.isEmpty() && m_data->m_paths.isEmpty(); + } + + QString PropertySheetIconValue::theme() const + { + return m_data->m_theme; + } + + void PropertySheetIconValue::setTheme(const QString &t) + { + m_data->m_theme = t; + } + + PropertySheetPixmapValue PropertySheetIconValue::pixmap(QIcon::Mode mode, QIcon::State state) const + { + const ModeStateKey pair = qMakePair(mode, state); + return m_data->m_paths.value(pair); + } + + void PropertySheetIconValue::setPixmap(QIcon::Mode mode, QIcon::State state, const PropertySheetPixmapValue &pixmap) + { + const ModeStateKey pair = qMakePair(mode, state); + if (pixmap.path().isEmpty()) + m_data->m_paths.remove(pair); + else + m_data->m_paths.insert(pair, pixmap); + } + + QPixmap DesignerPixmapCache::pixmap(const PropertySheetPixmapValue &value) const + { + QMap::const_iterator it = m_cache.constFind(value); + if (it != m_cache.constEnd()) + return it.value(); + + QPixmap pix = QPixmap(value.path()); + m_cache.insert(value, pix); + return pix; + } + + void DesignerPixmapCache::clear() + { + m_cache.clear(); + } + + DesignerPixmapCache::DesignerPixmapCache(QObject *parent) + : QObject(parent) + { + } + + QIcon DesignerIconCache::icon(const PropertySheetIconValue &value) const + { + typedef PropertySheetIconValue::ModeStateToPixmapMap::const_iterator ModeStateToPixmapMapConstIt; + + QMap::const_iterator it = m_cache.constFind(value); + if (it != m_cache.constEnd()) + return it.value(); + + // Match on the theme first if it is available. + if (!value.theme().isEmpty()) { + const QString theme = value.theme(); + if (QIcon::hasThemeIcon(theme)) { + const QIcon themeIcon = QIcon::fromTheme(theme); + m_cache.insert(value, themeIcon); + return themeIcon; + } + } + + QIcon icon; + const PropertySheetIconValue::ModeStateToPixmapMap &paths = value.paths(); + const ModeStateToPixmapMapConstIt cend = paths.constEnd(); + for (ModeStateToPixmapMapConstIt it = paths.constBegin(); it != cend; ++it) { + const QPair pair = it.key(); + icon.addFile(it.value().path(), QSize(), pair.first, pair.second); + } + m_cache.insert(value, icon); + return icon; + } + + void DesignerIconCache::clear() + { + m_cache.clear(); + } + + DesignerIconCache::DesignerIconCache(DesignerPixmapCache *pixmapCache, QObject *parent) + : QObject(parent), + m_pixmapCache(pixmapCache) + { + + } + + PropertySheetStringValue::PropertySheetStringValue(const QString &value, + bool translatable, const QString &disambiguation, const QString &comment) + : m_value(value), m_translatable(translatable), m_disambiguation(disambiguation), m_comment(comment) + { } + + QString PropertySheetStringValue::value() const + { + return m_value; + } + + void PropertySheetStringValue::setValue(const QString &value) + { + m_value = value; + } + + bool PropertySheetStringValue::translatable() const + { + return m_translatable; + } + + void PropertySheetStringValue::setTranslatable(bool translatable) + { + m_translatable = translatable; + } + + QString PropertySheetStringValue::disambiguation() const + { + return m_disambiguation; + } + + void PropertySheetStringValue::setDisambiguation(const QString &disambiguation) + { + m_disambiguation = disambiguation; + } + + QString PropertySheetStringValue::comment() const + { + return m_comment; + } + + void PropertySheetStringValue::setComment(const QString &comment) + { + m_comment = comment; + } + + bool PropertySheetStringValue::equals(const PropertySheetStringValue &rhs) const + { + return (m_value == rhs.m_value) && (m_translatable == rhs.m_translatable) + && (m_disambiguation == rhs.m_disambiguation) && (m_comment == rhs.m_comment); + } + + PropertySheetKeySequenceValue::PropertySheetKeySequenceValue(const QKeySequence &value, + bool translatable, const QString &disambiguation, const QString &comment) + : m_value(value), + m_standardKey(QKeySequence::UnknownKey), + m_translatable(translatable), + m_disambiguation(disambiguation), + m_comment(comment) + { } + + PropertySheetKeySequenceValue::PropertySheetKeySequenceValue(const QKeySequence::StandardKey &standardKey, + bool translatable, const QString &disambiguation, const QString &comment) + : m_value(QKeySequence(standardKey)), + m_standardKey(standardKey), + m_translatable(translatable), + m_disambiguation(disambiguation), + m_comment(comment) + { } + + QKeySequence PropertySheetKeySequenceValue::value() const + { + return m_value; + } + + void PropertySheetKeySequenceValue::setValue(const QKeySequence &value) + { + m_value = value; + m_standardKey = QKeySequence::UnknownKey; + } + + QKeySequence::StandardKey PropertySheetKeySequenceValue::standardKey() const + { + return m_standardKey; + } + + void PropertySheetKeySequenceValue::setStandardKey(const QKeySequence::StandardKey &standardKey) + { + m_value = QKeySequence(standardKey); + m_standardKey = standardKey; + } + + bool PropertySheetKeySequenceValue::isStandardKey() const + { + return m_standardKey != QKeySequence::UnknownKey; + } + + QString PropertySheetKeySequenceValue::comment() const + { + return m_comment; + } + + void PropertySheetKeySequenceValue::setComment(const QString &comment) + { + m_comment = comment; + } + + QString PropertySheetKeySequenceValue::disambiguation() const + { + return m_disambiguation; + } + + void PropertySheetKeySequenceValue::setDisambiguation(const QString &disambiguation) + { + m_disambiguation = disambiguation; + } + + bool PropertySheetKeySequenceValue::translatable() const + { + return m_translatable; + } + + void PropertySheetKeySequenceValue::setTranslatable(bool translatable) + { + m_translatable = translatable; + } + + bool PropertySheetKeySequenceValue::equals(const PropertySheetKeySequenceValue &rhs) const + { + return (m_value == rhs.m_value) && (m_standardKey == rhs.m_standardKey) + && (m_translatable == rhs.m_translatable) && (m_disambiguation == rhs.m_disambiguation) && (m_comment == rhs.m_comment); + } + + + /* IconSubPropertyMask: Assign each icon sub-property (pixmaps for the + * various states/modes and the theme) a flag bit (see QFont) so that they + * can be handled individually when assigning property values to + * multiselections in the set-property-commands (that is, do not clobber + * other subproperties when assigning just one). + * Provide back-and-forth mapping functions for the icon states. */ + + enum IconSubPropertyMask { + NormalOffIconMask = 0x01, + NormalOnIconMask = 0x02, + DisabledOffIconMask = 0x04, + DisabledOnIconMask = 0x08, + ActiveOffIconMask = 0x10, + ActiveOnIconMask = 0x20, + SelectedOffIconMask = 0x40, + SelectedOnIconMask = 0x80, + ThemeIconMask = 0x10000 + }; + + static inline uint iconStateToSubPropertyFlag(QIcon::Mode mode, QIcon::State state) + { + switch (mode) { + case QIcon::Disabled: + return state == QIcon::On ? DisabledOnIconMask : DisabledOffIconMask; + case QIcon::Active: + return state == QIcon::On ? ActiveOnIconMask : ActiveOffIconMask; + case QIcon::Selected: + return state == QIcon::On ? SelectedOnIconMask : SelectedOffIconMask; + case QIcon::Normal: + break; + } + return state == QIcon::On ? NormalOnIconMask : NormalOffIconMask; + } + + static inline QPair subPropertyFlagToIconModeState(unsigned flag) + { + switch (flag) { + case NormalOnIconMask: + return qMakePair(QIcon::Normal, QIcon::On); + case DisabledOffIconMask: + return qMakePair(QIcon::Disabled, QIcon::Off); + case DisabledOnIconMask: + return qMakePair(QIcon::Disabled, QIcon::On); + case ActiveOffIconMask: + return qMakePair(QIcon::Active, QIcon::Off); + case ActiveOnIconMask: + return qMakePair(QIcon::Active, QIcon::On); + case SelectedOffIconMask: + return qMakePair(QIcon::Selected, QIcon::Off); + case SelectedOnIconMask: + return qMakePair(QIcon::Selected, QIcon::On); + case NormalOffIconMask: + default: + break; + } + return qMakePair(QIcon::Normal, QIcon::Off); + } + + uint PropertySheetIconValue::mask() const + { + typedef ModeStateToPixmapMap::const_iterator ModeStateToPixmapMapConstIt; + + uint flags = 0; + const ModeStateToPixmapMapConstIt cend = m_data->m_paths.constEnd(); + for (ModeStateToPixmapMapConstIt it = m_data->m_paths.constBegin(); it != cend; ++it) + flags |= iconStateToSubPropertyFlag(it.key().first, it.key().second); + if (!m_data->m_theme.isEmpty()) + flags |= ThemeIconMask; + return flags; + } + + uint PropertySheetIconValue::compare(const PropertySheetIconValue &other) const + { + uint diffMask = mask() | other.mask(); + for (int i = 0; i < 8; i++) { + const uint flag = 1 << i; + if (diffMask & flag) { // if state is set in both icons, compare the values + const QPair state = subPropertyFlagToIconModeState(flag); + if (pixmap(state.first, state.second) == other.pixmap(state.first, state.second)) + diffMask &= ~flag; + } + } + if ((diffMask & ThemeIconMask) && theme() == other.theme()) + diffMask &= ~ThemeIconMask; + return diffMask; + } + + PropertySheetIconValue PropertySheetIconValue::themed() const + { + PropertySheetIconValue rc(*this); + rc.m_data->m_paths.clear(); + return rc; + } + + PropertySheetIconValue PropertySheetIconValue::unthemed() const + { + PropertySheetIconValue rc(*this); + rc.m_data->m_theme.clear(); + return rc; + } + + void PropertySheetIconValue::assign(const PropertySheetIconValue &other, uint mask) + { + for (int i = 0; i < 8; i++) { + uint flag = 1 << i; + if (mask & flag) { + const ModeStateKey state = subPropertyFlagToIconModeState(flag); + setPixmap(state.first, state.second, other.pixmap(state.first, state.second)); + } + } + if (mask & ThemeIconMask) + setTheme(other.theme()); + } + + const PropertySheetIconValue::ModeStateToPixmapMap &PropertySheetIconValue::paths() const + { + return m_data->m_paths; + } + + QDESIGNER_SHARED_EXPORT QDebug operator<<(QDebug d, const PropertySheetIconValue &p) + { + typedef PropertySheetIconValue::ModeStateToPixmapMap::const_iterator ModeStateToPixmapMapConstIt; + + QDebug nospace = d.nospace(); + nospace << "PropertySheetIconValue theme='" << p.theme() << "' "; + + const PropertySheetIconValue::ModeStateToPixmapMap &paths = p.paths(); + const ModeStateToPixmapMapConstIt cend = paths.constEnd(); + for (ModeStateToPixmapMapConstIt it = paths.constBegin(); it != cend; ++it) + nospace << " mode=" << it.key().first << ",state=" << it.key().second + << ",'" << it.value().path() << '\''; + nospace << " mask=0x" << QString::number(p.mask(), 16); + return d; + } + + QDESIGNER_SHARED_EXPORT QDesignerFormWindowCommand *createTextPropertyCommand(const QString &propertyName, const QString &text, QObject *object, QDesignerFormWindowInterface *fw) + { + if (text.isEmpty()) { + ResetPropertyCommand *cmd = new ResetPropertyCommand(fw); + cmd->init(object, propertyName); + return cmd; + } + SetPropertyCommand *cmd = new SetPropertyCommand(fw); + cmd->init(object, propertyName, text); + return cmd; + } + + QDESIGNER_SHARED_EXPORT QAction *preferredEditAction(QDesignerFormEditorInterface *core, QWidget *managedWidget) + { + QAction *action = 0; + if (const QDesignerTaskMenuExtension *taskMenu = qt_extension(core->extensionManager(), managedWidget)) { + action = taskMenu->preferredEditAction(); + if (!action) { + const QList actions = taskMenu->taskActions(); + if (!actions.isEmpty()) + action = actions.first(); + } + } + if (!action) { + if (const QDesignerTaskMenuExtension *taskMenu = qobject_cast( + core->extensionManager()->extension(managedWidget, QLatin1String("QDesignerInternalTaskMenuExtension")))) { + action = taskMenu->preferredEditAction(); + if (!action) { + const QList actions = taskMenu->taskActions(); + if (!actions.isEmpty()) + action = actions.first(); + } + } + } + return action; + } + + QDESIGNER_SHARED_EXPORT bool runUIC(const QString &fileName, UIC_Mode mode, QByteArray& ba, QString &errorMessage) + { + QStringList argv; + QString binary = QLibraryInfo::location(QLibraryInfo::BinariesPath); + binary += QDir::separator(); + switch (mode) { + case UIC_GenerateCode: + binary += QLatin1String("uic"); + break; + case UIC_ConvertV3: + binary += QLatin1String("uic3"); + argv += QLatin1String("-convert"); + break; + } + argv += fileName; + QProcess uic; + uic.start(binary, argv); + if (!uic.waitForStarted()) { + errorMessage = QApplication::translate("Designer", "Unable to launch %1.").arg(binary); + return false; + } + if (!uic.waitForFinished()) { + errorMessage = QApplication::translate("Designer", "%1 timed out.").arg(binary); + return false; + } + if (uic.exitCode()) { + errorMessage = QString::fromAscii(uic.readAllStandardError()); + return false; + } + ba = uic.readAllStandardOutput(); + return true; + } + + QDESIGNER_SHARED_EXPORT QString qtify(const QString &name) + { + QString qname = name; + + Q_ASSERT(qname.isEmpty() == false); + + + if (qname.count() > 1 && qname.at(1).isUpper()) { + const QChar first = qname.at(0); + if (first == QLatin1Char('Q') || first == QLatin1Char('K')) + qname.remove(0, 1); + } + + const int len = qname.count(); + for (int i = 0; i < len && qname.at(i).isUpper(); i++) + qname[i] = qname.at(i).toLower(); + + return qname; + } + + // --------------- UpdateBlocker + UpdateBlocker::UpdateBlocker(QWidget *w) : + m_widget(w), + m_enabled(w->updatesEnabled() && w->isVisible()) + { + if (m_enabled) + m_widget->setUpdatesEnabled(false); + } + + UpdateBlocker::~UpdateBlocker() + { + if (m_enabled) + m_widget->setUpdatesEnabled(true); + } + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_utils_p.h b/src/designer/src/lib/shared/qdesigner_utils_p.h new file mode 100644 index 000000000..1e48cf8db --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_utils_p.h @@ -0,0 +1,499 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_UTILS_H +#define QDESIGNER_UTILS_H + +#include "shared_global_p.h" + +#include + +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDebug; + +namespace qdesigner_internal { +class QDesignerFormWindowCommand; +class DesignerIconCache; +class FormWindowBase; + + +QDESIGNER_SHARED_EXPORT void designerWarning(const QString &message); + +QDESIGNER_SHARED_EXPORT void reloadIconResources(DesignerIconCache *iconCache, QObject *object); + +/* Flag/Enumeration helpers for the property sheet: Enumeration or flag values are returned by the property sheet + * as a pair of meta type and integer value. + * The meta type carries all the information required for the property editor and serialization + * by the form builders (names, etc). + * Note that the property editor uses unqualified names ("Cancel") while the form builder serialization (uic) + * requires the whole string + * ("QDialogButtonBox::Cancel" or "com.trolltech.qt.gui.QDialogButtonBox.StandardButton.Cancel").*/ + +/* --------- MetaEnum: Base class representing a QMetaEnum with lookup functions + * in both ways. Template of int type since unsigned is more suitable for flags. + * The keyToValue() is ignorant of scopes, it can handle fully qualified or unqualified names. */ + +template +class MetaEnum +{ +public: + typedef QMap KeyToValueMap; + + MetaEnum(const QString &name, const QString &scope, const QString &separator); + MetaEnum() {} + void addKey(IntType value, const QString &name); + + QString valueToKey(IntType value, bool *ok = 0) const; + // Ignorant of scopes. + IntType keyToValue(QString key, bool *ok = 0) const; + + const QString &name() const { return m_name; } + const QString &scope() const { return m_scope; } + const QString &separator() const { return m_separator; } + + const QStringList &keys() const { return m_keys; } + const KeyToValueMap &keyToValueMap() const { return m_keyToValueMap; } + +protected: + void appendQualifiedName(const QString &key, QString &target) const; + +private: + QString m_name; + QString m_scope; + QString m_separator; + KeyToValueMap m_keyToValueMap; + QStringList m_keys; +}; + +template +MetaEnum::MetaEnum(const QString &name, const QString &scope, const QString &separator) : + m_name(name), + m_scope(scope), + m_separator(separator) +{ +} + +template +void MetaEnum::addKey(IntType value, const QString &name) +{ + m_keyToValueMap.insert(name, value); + m_keys.append(name); +} + +template +QString MetaEnum::valueToKey(IntType value, bool *ok) const +{ + const QString rc = m_keyToValueMap.key(value); + if (ok) + *ok = !rc.isEmpty(); + return rc; +} + +template +IntType MetaEnum::keyToValue(QString key, bool *ok) const +{ + if (!m_scope.isEmpty() && key.startsWith(m_scope)) + key.remove(0, m_scope.size() + m_separator.size()); + const Q_TYPENAME KeyToValueMap::const_iterator it = m_keyToValueMap.find(key); + const bool found = it != m_keyToValueMap.constEnd(); + if (ok) + *ok = found; + return found ? it.value() : IntType(0); +} + +template +void MetaEnum::appendQualifiedName(const QString &key, QString &target) const +{ + if (!m_scope.isEmpty()) { + target += m_scope; + target += m_separator; + } + target += key; +} + +// -------------- DesignerMetaEnum: Meta type for enumerations + +class QDESIGNER_SHARED_EXPORT DesignerMetaEnum : public MetaEnum +{ +public: + DesignerMetaEnum(const QString &name, const QString &scope, const QString &separator); + DesignerMetaEnum() {} + + enum SerializationMode { FullyQualified, NameOnly }; + QString toString(int value, SerializationMode sm, bool *ok = 0) const; + + QString messageToStringFailed(int value) const; + QString messageParseFailed(const QString &s) const; + + // parse a string (ignorant of scopes) + int parseEnum(const QString &s, bool *ok = 0) const { return keyToValue(s, ok); } +}; + +// -------------- DesignerMetaFlags: Meta type for flags. +// Note that while the handling of flags is done using unsigned integers, the actual values returned +// by the property system are integers. + +class QDESIGNER_SHARED_EXPORT DesignerMetaFlags : public MetaEnum +{ +public: + DesignerMetaFlags(const QString &name, const QString &scope, const QString &separator); + DesignerMetaFlags() {} + + enum SerializationMode { FullyQualified, NameOnly }; + QString toString(int value, SerializationMode sm) const; + QStringList flags(int value) const; + + QString messageParseFailed(const QString &s) const; + // parse a string (ignorant of scopes) + int parseFlags(const QString &s, bool *ok = 0) const; +}; + +// -------------- EnumValue: Returned by the property sheet for enumerations + +struct QDESIGNER_SHARED_EXPORT PropertySheetEnumValue +{ + PropertySheetEnumValue(int v, const DesignerMetaEnum &me); + PropertySheetEnumValue(); + + int value; + DesignerMetaEnum metaEnum; +}; + +// -------------- FlagValue: Returned by the property sheet for flags + +struct QDESIGNER_SHARED_EXPORT PropertySheetFlagValue +{ + PropertySheetFlagValue(int v, const DesignerMetaFlags &mf); + PropertySheetFlagValue(); + + int value; + DesignerMetaFlags metaFlags; +}; + +// -------------- PixmapValue: Returned by the property sheet for pixmaps +class QDESIGNER_SHARED_EXPORT PropertySheetPixmapValue +{ +public: + PropertySheetPixmapValue(const QString &path); + PropertySheetPixmapValue(); + + bool operator==(const PropertySheetPixmapValue &other) const { return compare(other) == 0; } + bool operator!=(const PropertySheetPixmapValue &other) const { return compare(other) != 0; } + bool operator<(const PropertySheetPixmapValue &other) const { return compare(other) < 0; } + + // Check where a pixmap comes from + enum PixmapSource { LanguageResourcePixmap , ResourcePixmap, FilePixmap }; + static PixmapSource getPixmapSource(QDesignerFormEditorInterface *core, const QString & path); + + PixmapSource pixmapSource(QDesignerFormEditorInterface *core) const { return getPixmapSource(core, m_path); } + + QString path() const; + void setPath(const QString &path); // passing the empty path resets the pixmap + + int compare(const PropertySheetPixmapValue &other) const; + +private: + QString m_path; +}; + +// -------------- IconValue: Returned by the property sheet for icons + +class PropertySheetIconValueData; + +class QDESIGNER_SHARED_EXPORT PropertySheetIconValue +{ + public: + PropertySheetIconValue(const PropertySheetPixmapValue &pixmap); + PropertySheetIconValue(); + ~PropertySheetIconValue(); + PropertySheetIconValue(const PropertySheetIconValue &); + PropertySheetIconValue &operator=(const PropertySheetIconValue &); + + bool operator==(const PropertySheetIconValue &other) const { return equals(other); } + bool operator!=(const PropertySheetIconValue &other) const { return !equals(other); } + bool operator<(const PropertySheetIconValue &other) const; + + bool isEmpty() const; + + QString theme() const; + void setTheme(const QString &); + + PropertySheetPixmapValue pixmap(QIcon::Mode mode, QIcon::State state) const; + void setPixmap(QIcon::Mode mode, QIcon::State state, const PropertySheetPixmapValue &path); // passing the empty path resets the pixmap + + uint mask() const; + uint compare(const PropertySheetIconValue &other) const; + void assign(const PropertySheetIconValue &other, uint mask); + + // Convenience accessors to get themed/unthemed icons. + PropertySheetIconValue themed() const; + PropertySheetIconValue unthemed() const; + + typedef QPair ModeStateKey; + typedef QMap ModeStateToPixmapMap; + + const ModeStateToPixmapMap &paths() const; + +private: + bool equals(const PropertySheetIconValue &rhs) const; + QSharedDataPointer m_data; +}; + +QDESIGNER_SHARED_EXPORT QDebug operator<<(QDebug, const PropertySheetIconValue &); + +class QDESIGNER_SHARED_EXPORT DesignerPixmapCache : public QObject +{ + Q_OBJECT +public: + DesignerPixmapCache(QObject *parent = 0); + QPixmap pixmap(const PropertySheetPixmapValue &value) const; + void clear(); +signals: + void reloaded(); +private: + mutable QMap m_cache; + friend class FormWindowBase; +}; + +class QDESIGNER_SHARED_EXPORT DesignerIconCache : public QObject +{ + Q_OBJECT +public: + explicit DesignerIconCache(DesignerPixmapCache *pixmapCache, QObject *parent = 0); + QIcon icon(const PropertySheetIconValue &value) const; + void clear(); +signals: + void reloaded(); +private: + mutable QMap m_cache; + DesignerPixmapCache *m_pixmapCache; + friend class FormWindowBase; +}; + +// -------------- StringValue: Returned by the property sheet for strings +class QDESIGNER_SHARED_EXPORT PropertySheetStringValue +{ +public: + explicit PropertySheetStringValue(const QString &value = QString(), + bool translatable = true, + const QString &disambiguation = QString(), + const QString &comment = QString()); + + bool operator==(const PropertySheetStringValue &other) const { return equals(other); } + bool operator!=(const PropertySheetStringValue &other) const { return !equals(other); } + + QString value() const; + void setValue(const QString &value); + bool translatable() const; + void setTranslatable(bool translatable); + QString disambiguation() const; + void setDisambiguation(const QString &disambiguation); + QString comment() const; + void setComment(const QString &comment); + +private: + bool equals(const PropertySheetStringValue &rhs) const; + + QString m_value; + bool m_translatable; + QString m_disambiguation; + QString m_comment; +}; + + + +// -------------- StringValue: Returned by the property sheet for strings +class QDESIGNER_SHARED_EXPORT PropertySheetKeySequenceValue +{ +public: + explicit PropertySheetKeySequenceValue(const QKeySequence &value = QKeySequence(), + bool translatable = true, + const QString &disambiguation = QString(), + const QString &comment = QString()); + explicit PropertySheetKeySequenceValue(const QKeySequence::StandardKey &standardKey, + bool translatable = true, + const QString &disambiguation = QString(), + const QString &comment = QString()); + + bool operator==(const PropertySheetKeySequenceValue &other) const { return equals(other); } + bool operator!=(const PropertySheetKeySequenceValue &other) const { return !equals(other); } + + QKeySequence value() const; + void setValue(const QKeySequence &value); + QKeySequence::StandardKey standardKey() const; + void setStandardKey(const QKeySequence::StandardKey &standardKey); + bool isStandardKey() const; + + bool translatable() const; + void setTranslatable(bool translatable); + QString disambiguation() const; + void setDisambiguation(const QString &disambiguation); + QString comment() const; + void setComment(const QString &comment); + +private: + bool equals(const PropertySheetKeySequenceValue &rhs) const; + + QKeySequence m_value; + QKeySequence::StandardKey m_standardKey; + bool m_translatable; + QString m_disambiguation; + QString m_comment; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + + +// NOTE: Do not move this code, needed for GCC 3.3 +Q_DECLARE_METATYPE(qdesigner_internal::PropertySheetEnumValue) +Q_DECLARE_METATYPE(qdesigner_internal::PropertySheetFlagValue) +Q_DECLARE_METATYPE(qdesigner_internal::PropertySheetPixmapValue) +Q_DECLARE_METATYPE(qdesigner_internal::PropertySheetIconValue) +Q_DECLARE_METATYPE(qdesigner_internal::PropertySheetStringValue) +Q_DECLARE_METATYPE(qdesigner_internal::PropertySheetKeySequenceValue) + + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + + +// Create a command to change a text property (that is, create a reset property command if the text is empty) +QDESIGNER_SHARED_EXPORT QDesignerFormWindowCommand *createTextPropertyCommand(const QString &propertyName, const QString &text, QObject *object, QDesignerFormWindowInterface *fw); + +// Returns preferred task menu action for managed widget +QDESIGNER_SHARED_EXPORT QAction *preferredEditAction(QDesignerFormEditorInterface *core, QWidget *managedWidget); + +// Convenience to run UIC +enum UIC_Mode { UIC_GenerateCode, UIC_ConvertV3 }; +QDESIGNER_SHARED_EXPORT bool runUIC(const QString &fileName, UIC_Mode mode, QByteArray& ba, QString &errorMessage); + +// Find a suitable variable name for a class. +QDESIGNER_SHARED_EXPORT QString qtify(const QString &name); + +/* UpdateBlocker: Blocks the updates of the widget passed on while in scope. + * Does nothing if the incoming widget already has updatesEnabled==false + * which is important to avoid side-effects when putting it into QStackedLayout. */ + +class QDESIGNER_SHARED_EXPORT UpdateBlocker { + Q_DISABLE_COPY(UpdateBlocker) + +public: + UpdateBlocker(QWidget *w); + ~UpdateBlocker(); + +private: + QWidget *m_widget; + const bool m_enabled; +}; + +namespace Utils { + +inline int valueOf(const QVariant &value, bool *ok = 0) +{ + if (value.canConvert()) { + if (ok) + *ok = true; + return qvariant_cast(value).value; + } + else if (value.canConvert()) { + if (ok) + *ok = true; + return qvariant_cast(value).value; + } + return value.toInt(ok); +} + +inline bool isObjectAncestorOf(QObject *ancestor, QObject *child) +{ + QObject *obj = child; + while (obj != 0) { + if (obj == ancestor) + return true; + obj = obj->parent(); + } + return false; +} + +inline bool isCentralWidget(QDesignerFormWindowInterface *fw, QWidget *widget) +{ + if (! fw || ! widget) + return false; + + if (widget == fw->mainContainer()) + return true; + + // ### generalize for other containers + if (QMainWindow *mw = qobject_cast(fw->mainContainer())) { + return mw->centralWidget() == widget; + } + + return false; +} + +} // namespace Utils + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QDESIGNER_UTILS_H diff --git a/src/designer/src/lib/shared/qdesigner_widget.cpp b/src/designer/src/lib/shared/qdesigner_widget.cpp new file mode 100644 index 000000000..0368d5337 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_widget.cpp @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_widget_p.h" +#include "formwindowbase_p.h" +#include "grid_p.h" + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/* QDesignerDialog / QDesignerWidget are used to paint a grid on QDialog and QWidget main containers + * and container extension pages. + * The paint routines work as follows: + * We need to clean the background here (to make the parent grid disappear in case we are a container page + * and to make palette background settings take effect), + * which would normally break style sheets with background settings. + * So, we manually make the style paint after cleaning. On top comes the grid + * In addition, this code works around + * the QStyleSheetStyle setting Qt::WA_StyledBackground to false for subclasses of QWidget. + */ + +QDesignerDialog::QDesignerDialog(QDesignerFormWindowInterface *fw, QWidget *parent) : + QDialog(parent), + m_formWindow(qobject_cast(fw)) +{ +} + +void QDesignerDialog::paintEvent(QPaintEvent *e) +{ + QPainter p(this); + QStyleOption opt; + opt.initFrom(this); + p.fillRect(e->rect(), palette().brush(backgroundRole())); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); + if (m_formWindow && m_formWindow->gridVisible()) + m_formWindow->designerGrid().paint(p, this, e); +} + +QDesignerWidget::QDesignerWidget(QDesignerFormWindowInterface* formWindow, QWidget *parent) : + QWidget(parent), + m_formWindow(qobject_cast(formWindow)) +{ +} + +QDesignerWidget::~QDesignerWidget() +{ +} + +QDesignerFormWindowInterface* QDesignerWidget::formWindow() const +{ + return m_formWindow; +} + +void QDesignerWidget::paintEvent(QPaintEvent *e) +{ + QPainter p(this); + QStyleOption opt; + opt.initFrom(this); + p.fillRect(e->rect(), palette().brush(backgroundRole())); + style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); + if (m_formWindow && m_formWindow->gridVisible()) + m_formWindow->designerGrid().paint(p, this, e); +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_widget_p.h b/src/designer/src/lib/shared/qdesigner_widget_p.h new file mode 100644 index 000000000..bb511ae4b --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_widget_p.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_WIDGET_H +#define QDESIGNER_WIDGET_H + +#include "shared_global_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; + +namespace qdesigner_internal { + class FormWindowBase; +} + +class QDESIGNER_SHARED_EXPORT QDesignerWidget : public QWidget +{ + Q_OBJECT +public: + explicit QDesignerWidget(QDesignerFormWindowInterface* formWindow, QWidget *parent = 0); + virtual ~QDesignerWidget(); + + QDesignerFormWindowInterface* formWindow() const; + + void updatePixmap(); + + virtual QSize minimumSizeHint() const + { return QWidget::minimumSizeHint().expandedTo(QSize(16, 16)); } + +protected: + virtual void paintEvent(QPaintEvent *e); + +private: + qdesigner_internal::FormWindowBase* m_formWindow; +}; + +class QDESIGNER_SHARED_EXPORT QDesignerDialog : public QDialog +{ + Q_OBJECT +public: + explicit QDesignerDialog(QDesignerFormWindowInterface *fw, QWidget *parent); + + virtual QSize minimumSizeHint() const + { return QWidget::minimumSizeHint().expandedTo(QSize(16, 16)); } + +protected: + void paintEvent(QPaintEvent *e); + +private: + qdesigner_internal::FormWindowBase* m_formWindow; +}; + +class QDESIGNER_SHARED_EXPORT Line : public QFrame +{ + Q_OBJECT + Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation) +public: + explicit Line(QWidget *parent) : QFrame(parent) + { setAttribute(Qt::WA_MouseNoMask); setFrameStyle(HLine | Sunken); } + + inline void setOrientation(Qt::Orientation orient) + { setFrameShape(orient == Qt::Horizontal ? HLine : VLine); } + + inline Qt::Orientation orientation() const + { return frameShape() == HLine ? Qt::Horizontal : Qt::Vertical; } +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_WIDGET_H diff --git a/src/designer/src/lib/shared/qdesigner_widgetbox.cpp b/src/designer/src/lib/shared/qdesigner_widgetbox.cpp new file mode 100644 index 000000000..154b2d61d --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_widgetbox.cpp @@ -0,0 +1,181 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_widgetbox_p.h" +#include "qdesigner_utils_p.h" + +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { +QDesignerWidgetBox::QDesignerWidgetBox(QWidget *parent, Qt::WindowFlags flags) + : QDesignerWidgetBoxInterface(parent, flags), + m_loadMode(LoadMerge) +{ + +} + +QDesignerWidgetBox::LoadMode QDesignerWidgetBox::loadMode() const +{ + return m_loadMode; +} + +void QDesignerWidgetBox::setLoadMode(LoadMode lm) +{ + m_loadMode = lm; +} + +// Convenience to find a widget by class name +bool QDesignerWidgetBox::findWidget(const QDesignerWidgetBoxInterface *wbox, + const QString &className, + const QString &category, + Widget *widgetData) +{ + // Note that entry names do not necessarily match the class name + // (at least, not for the standard widgets), so, + // look in the XML for the class name of the first widget to appear + const QString widgetTag = QLatin1String("categoryCount(); + for (int c = 0; c < catCount; c++) { + const Category cat = wbox->category(c); + if (category.isEmpty() || cat.name() == category) { + const int widgetCount = cat.widgetCount(); + for (int w = 0; w < widgetCount; w++) { + const Widget widget = cat.widget(w); + QString xml = widget.domXml(); // Erase the tag that can be present starting from 4.4 + const int widgetTagIndex = xml.indexOf(widgetTag); + if (widgetTagIndex != -1) { + xml.remove(0, widgetTagIndex); + if (regexp.exactMatch(xml)) { + *widgetData = widget; + return true; + } + } + } + } + } + return false; +} + +// Convenience to create a Dom Widget from widget box xml code. +DomUI *QDesignerWidgetBox::xmlToUi(const QString &name, const QString &xml, bool insertFakeTopLevel, + QString *errorMessage) +{ + QXmlStreamReader reader(xml); + DomUI *ui = 0; + + // The xml description must either contain a root element "ui" with a child element "widget" + // or "widget" as the root element (4.3 legacy) + const QString widgetTag = QLatin1String("widget"); + + while (!reader.atEnd()) { + if (reader.readNext() == QXmlStreamReader::StartElement) { + const QStringRef name = reader.name(); + if (ui) { + reader.raiseError(tr("Unexpected element <%1>").arg(name.toString())); + continue; + } + + if (name.compare(QLatin1String("widget"), Qt::CaseInsensitive) == 0) { // 4.3 legacy, wrap into DomUI + ui = new DomUI; + DomWidget *widget = new DomWidget; + widget->read(reader); + ui->setElementWidget(widget); + } else if (name.compare(QLatin1String("ui"), Qt::CaseInsensitive) == 0) { // 4.4 + ui = new DomUI; + ui->read(reader); + } else { + reader.raiseError(tr("Unexpected element <%1>").arg(name.toString())); + } + } + } + + if (reader.hasError()) { + delete ui; + *errorMessage = tr("A parse error occurred at line %1, column %2 of the XML code " + "specified for the widget %3: %4\n%5") + .arg(reader.lineNumber()).arg(reader.columnNumber()).arg(name) + .arg(reader.errorString()).arg(xml); + return 0; + } + + if (!ui || !ui->elementWidget()) { + delete ui; + *errorMessage = tr("The XML code specified for the widget %1 does not contain " + "any widget elements.\n%2").arg(name).arg(xml); + return 0; + } + + if (insertFakeTopLevel) { + DomWidget *fakeTopLevel = new DomWidget; + fakeTopLevel->setAttributeClass(QLatin1String("QWidget")); + QList children; + children.push_back(ui->takeElementWidget()); + fakeTopLevel->setElementWidget(children); + ui->setElementWidget(fakeTopLevel); + } + + return ui; +} + +// Convenience to create a Dom Widget from widget box xml code. +DomUI *QDesignerWidgetBox::xmlToUi(const QString &name, const QString &xml, bool insertFakeTopLevel) +{ + QString errorMessage; + DomUI *rc = xmlToUi(name, xml, insertFakeTopLevel, &errorMessage); + if (!rc) + qdesigner_internal::designerWarning(errorMessage); + return rc; +} + +} // namespace qdesigner_internal + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_widgetbox_p.h b/src/designer/src/lib/shared/qdesigner_widgetbox_p.h new file mode 100644 index 000000000..d0a1285db --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_widgetbox_p.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QDESIGNER_WIDGETBOX_H +#define QDESIGNER_WIDGETBOX_H + +#include "shared_global_p.h" +#include + +QT_BEGIN_NAMESPACE + +class DomUI; + +namespace qdesigner_internal { + +// A widget box with a load mode that allows for updating custom widgets. + +class QDESIGNER_SHARED_EXPORT QDesignerWidgetBox : public QDesignerWidgetBoxInterface +{ + Q_OBJECT +public: + enum LoadMode { LoadMerge, LoadReplace, LoadCustomWidgetsOnly }; + + explicit QDesignerWidgetBox(QWidget *parent = 0, Qt::WindowFlags flags = 0); + + LoadMode loadMode() const; + void setLoadMode(LoadMode lm); + + virtual bool loadContents(const QString &contents) = 0; + + // Convenience to access the widget box icon of a widget. Empty category + // matches all + virtual QIcon iconForWidget(const QString &className, + const QString &category = QString()) const = 0; + + // Convenience to find a widget by class name. Empty category matches all + static bool findWidget(const QDesignerWidgetBoxInterface *wbox, + const QString &className, + const QString &category /* = QString() */, + Widget *widgetData); + // Convenience functions to create a DomWidget from widget box xml. + static DomUI *xmlToUi(const QString &name, const QString &xml, bool insertFakeTopLevel, QString *errorMessage); + static DomUI *xmlToUi(const QString &name, const QString &xml, bool insertFakeTopLevel); + +private: + LoadMode m_loadMode; +}; +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif // QDESIGNER_WIDGETBOX_H diff --git a/src/designer/src/lib/shared/qdesigner_widgetitem.cpp b/src/designer/src/lib/shared/qdesigner_widgetitem.cpp new file mode 100644 index 000000000..a3041ad83 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_widgetitem.cpp @@ -0,0 +1,345 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesigner_widgetitem_p.h" +#include "qdesigner_widget_p.h" +#include "widgetfactory_p.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +enum { DebugWidgetItem = 0 }; +enum { MinimumLength = 10 }; + +// Widget item creation function to be registered as factory method with +// QLayoutPrivate +static QWidgetItem *createDesignerWidgetItem(const QLayout *layout, QWidget *widget) +{ + Qt::Orientations orientations; + if (qdesigner_internal::QDesignerWidgetItem::check(layout, widget, &orientations)) { + if (DebugWidgetItem) + qDebug() << "QDesignerWidgetItem: Creating on " << layout << widget << orientations; + return new qdesigner_internal::QDesignerWidgetItem(layout, widget, orientations); + } + if (DebugWidgetItem) + qDebug() << "QDesignerWidgetItem: Noncontainer: " << layout << widget; + + return 0; +} + +static QString sizePolicyToString(const QSizePolicy &p) +{ + QString rc; { + QTextStream str(&rc); + str << "Control=" << p.controlType() << " expdirs=" << p.expandingDirections() + << " hasHeightForWidth=" << p.hasHeightForWidth() + << " H: Policy=" << p.horizontalPolicy() + << " stretch=" << p.horizontalStretch() + << " V: Policy=" << p.verticalPolicy() + << " stretch=" << p.verticalStretch(); + } + return rc; +} + +// Find the layout the item is contained in, recursing over +// child layouts +static const QLayout *findLayoutOfItem(const QLayout *haystack, const QLayoutItem *needle) +{ + const int count = haystack->count(); + for (int i = 0; i < count; i++) { + QLayoutItem *item = haystack->itemAt(i); + if (item == needle) + return haystack; + if (QLayout *childLayout = item->layout()) + if (const QLayout *containing = findLayoutOfItem(childLayout, needle)) + return containing; + } + return 0; +} + + +namespace qdesigner_internal { + +// ------------------ QDesignerWidgetItem +QDesignerWidgetItem::QDesignerWidgetItem(const QLayout *containingLayout, QWidget *w, Qt::Orientations o) : + QWidgetItemV2(w), + m_orientations(o), + m_nonLaidOutMinSize(w->minimumSizeHint()), + m_nonLaidOutSizeHint(w->sizeHint()), + m_cachedContainingLayout(containingLayout) +{ + // Initialize the minimum size to prevent nonlaid-out frames/widgets + // from being slammed to zero + const QSize minimumSize = w->minimumSize(); + if (!minimumSize.isEmpty()) + m_nonLaidOutMinSize = minimumSize; + expand(&m_nonLaidOutMinSize); + expand(&m_nonLaidOutSizeHint); + w->installEventFilter(this); + connect(containingLayout, SIGNAL(destroyed()), this, SLOT(layoutChanged())); + if (DebugWidgetItem ) + qDebug() << "QDesignerWidgetItem" << w << sizePolicyToString(w->sizePolicy()) << m_nonLaidOutMinSize << m_nonLaidOutSizeHint; +} + +void QDesignerWidgetItem::expand(QSize *s) const +{ + // Expand the size if its too small + if (m_orientations & Qt::Horizontal && s->width() <= 0) + s->setWidth(MinimumLength); + if (m_orientations & Qt::Vertical && s->height() <= 0) + s->setHeight(MinimumLength); +} + +QSize QDesignerWidgetItem::minimumSize() const +{ + // Just track the size in case we are laid-out or stretched. + const QSize baseMinSize = QWidgetItemV2::minimumSize(); + QWidget * w = constWidget(); + if (w->layout() || subjectToStretch(containingLayout(), w)) { + m_nonLaidOutMinSize = baseMinSize; + return baseMinSize; + } + // Nonlaid out: Maintain last laid-out size + const QSize rc = baseMinSize.expandedTo(m_nonLaidOutMinSize); + if (DebugWidgetItem > 1) + qDebug() << "minimumSize" << constWidget() << baseMinSize << rc; + return rc; +} + +QSize QDesignerWidgetItem::sizeHint() const +{ + // Just track the size in case we are laid-out or stretched. + const QSize baseSizeHint = QWidgetItemV2::sizeHint(); + QWidget * w = constWidget(); + if (w->layout() || subjectToStretch(containingLayout(), w)) { + m_nonLaidOutSizeHint = baseSizeHint; + return baseSizeHint; + } + // Nonlaid out: Maintain last laid-out size + const QSize rc = baseSizeHint.expandedTo(m_nonLaidOutSizeHint); + if (DebugWidgetItem > 1) + qDebug() << "sizeHint" << constWidget() << baseSizeHint << rc; + return rc; +} + +bool QDesignerWidgetItem::subjectToStretch(const QLayout *layout, QWidget *w) +{ + if (!layout) + return false; + // Are we under some stretch factor? + if (const QBoxLayout *bl = qobject_cast(layout)) { + const int index = bl->indexOf(w); + Q_ASSERT(index != -1); + return bl->stretch(index) != 0; + } + if (const QGridLayout *cgl = qobject_cast(layout)) { + QGridLayout *gl = const_cast(cgl); + const int index = cgl->indexOf(w); + Q_ASSERT(index != -1); + int row, column, rowSpan, columnSpan; + gl->getItemPosition (index, &row, &column, &rowSpan, &columnSpan); + const int rend = row + rowSpan; + const int cend = column + columnSpan; + for (int r = row; r < rend; r++) + if (cgl->rowStretch(r) != 0) + return true; + for (int c = column; c < cend; c++) + if (cgl->columnStretch(c) != 0) + return true; + } + return false; +} + +/* Return the orientations mask for a layout, specifying + * in which directions squeezing should be prevented. */ +static Qt::Orientations layoutOrientation(const QLayout *layout) +{ + if (const QBoxLayout *bl = qobject_cast(layout)) { + const QBoxLayout::Direction direction = bl->direction(); + return direction == QBoxLayout::LeftToRight || direction == QBoxLayout::RightToLeft ? Qt::Horizontal : Qt::Vertical; + } + if (qobject_cast(layout)) + return Qt::Vertical; + return Qt::Horizontal|Qt::Vertical; +} + +// Check for a non-container extension container +bool QDesignerWidgetItem::isContainer(const QDesignerFormEditorInterface *core, QWidget *w) +{ + if (!WidgetFactory::isFormEditorObject(w)) + return false; + const QDesignerWidgetDataBaseInterface *wdb = core->widgetDataBase(); + const int widx = wdb->indexOfObject(w); + if (widx == -1 || !wdb->item(widx)->isContainer()) + return false; + if (qt_extension(core->extensionManager(), w)) + return false; + return true; +} + +bool QDesignerWidgetItem::check(const QLayout *layout, QWidget *w, Qt::Orientations *ptrToOrientations) +{ + // Check for form-editor non-containerextension-containers (QFrame, etc) + // within laid-out form editor widgets. No check for managed() here as we + // want container pages and widgets in the process of being morphed as + // well. Avoid nested layouts (as the effective stretch cannot be easily + // computed and may mess things up). Won't work for Q3 Group boxes. + if (ptrToOrientations) + *ptrToOrientations = 0; + + const QObject *layoutParent = layout->parent(); + if (!layoutParent || !layoutParent->isWidgetType() || !WidgetFactory::isFormEditorObject(layoutParent)) + return false; + + QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(w); + if (!fw || !isContainer(fw->core(), w)) + return false; + + // If it is a box, restrict to its orientation + if (ptrToOrientations) + *ptrToOrientations = layoutOrientation(layout); + + return true; +} + +QSize QDesignerWidgetItem::nonLaidOutMinSize() const +{ + return m_nonLaidOutMinSize; +} + +void QDesignerWidgetItem::setNonLaidOutMinSize(const QSize &s) +{ + if (DebugWidgetItem > 1) + qDebug() << "setNonLaidOutMinSize" << constWidget() << s; + m_nonLaidOutMinSize = s; +} + +QSize QDesignerWidgetItem::nonLaidOutSizeHint() const +{ + return m_nonLaidOutSizeHint; +} + +void QDesignerWidgetItem::setNonLaidOutSizeHint(const QSize &s) +{ + if (DebugWidgetItem > 1) + qDebug() << "setNonLaidOutSizeHint" << constWidget() << s; + m_nonLaidOutSizeHint = s; +} + +void QDesignerWidgetItem::install() +{ + QLayoutPrivate::widgetItemFactoryMethod = createDesignerWidgetItem; +} + +void QDesignerWidgetItem::deinstall() +{ + QLayoutPrivate::widgetItemFactoryMethod = 0; +} + +const QLayout *QDesignerWidgetItem::containingLayout() const +{ + if (!m_cachedContainingLayout) { + if (QWidget *parentWidget = constWidget()->parentWidget()) + if (QLayout *parentLayout = parentWidget->layout()) { + m_cachedContainingLayout = findLayoutOfItem(parentLayout, this); + if (m_cachedContainingLayout) + connect(m_cachedContainingLayout, SIGNAL(destroyed()), this, SLOT(layoutChanged())); + } + if (DebugWidgetItem) + qDebug() << Q_FUNC_INFO << " found " << m_cachedContainingLayout << " after reparenting " << constWidget(); + } + return m_cachedContainingLayout; +} + +void QDesignerWidgetItem::layoutChanged() +{ + if (DebugWidgetItem) + qDebug() << Q_FUNC_INFO; + m_cachedContainingLayout = 0; +} + +bool QDesignerWidgetItem::eventFilter(QObject * /* watched */, QEvent *event) +{ + if (event->type() == QEvent::ParentChange) + layoutChanged(); + return false; +} + +// ------------------ QDesignerWidgetItemInstaller + +int QDesignerWidgetItemInstaller::m_instanceCount = 0; + +QDesignerWidgetItemInstaller::QDesignerWidgetItemInstaller() +{ + if (m_instanceCount++ == 0) { + if (DebugWidgetItem) + qDebug() << "QDesignerWidgetItemInstaller: installing"; + QDesignerWidgetItem::install(); + } +} + +QDesignerWidgetItemInstaller::~QDesignerWidgetItemInstaller() +{ + if (--m_instanceCount == 0) { + if (DebugWidgetItem) + qDebug() << "QDesignerWidgetItemInstaller: deinstalling"; + QDesignerWidgetItem::deinstall(); + } +} + +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qdesigner_widgetitem_p.h b/src/designer/src/lib/shared/qdesigner_widgetitem_p.h new file mode 100644 index 000000000..f79dbc5a1 --- /dev/null +++ b/src/designer/src/lib/shared/qdesigner_widgetitem_p.h @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef DESIGNERWIDGETITEM_H +#define DESIGNERWIDGETITEM_H + +#include "shared_global_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +// QDesignerWidgetItem: A Layout Item that is used for non-containerextension- +// containers (QFrame, etc) on Designer forms. It prevents its widget +// from being slammed to size 0 if the widget has no layout: +// Pre 4.5, this item ensured only that QWidgets and QFrames were not squeezed +// to size 0 since they have an invalid size hint when non-laid out. +// Since 4.5, the item is used for every non-containerextension-container. +// In case the container has itself a layout, it merely tracks the minimum +// size. If the container has no layout and is not subject to some stretch +// factor, it will return the last valid size. The effect is that after +// breaking a layout on a container within a layout, it just maintains its +// last size and is not slammed to 0,0. In addition, it can be resized. +// The class keeps track of the containing layout by tracking widget reparent +// and destroyed slots as Designer will for example re-create grid layouts to +// shrink them. + +class QDESIGNER_SHARED_EXPORT QDesignerWidgetItem : public QObject, public QWidgetItemV2 { + Q_DISABLE_COPY(QDesignerWidgetItem) + Q_OBJECT +public: + explicit QDesignerWidgetItem(const QLayout *containingLayout, QWidget *w, Qt::Orientations o = Qt::Horizontal|Qt::Vertical); + + const QLayout *containingLayout() const; + + inline QWidget *constWidget() const { return const_cast(this)->widget(); } + + virtual QSize minimumSize() const; + virtual QSize sizeHint() const; + + // Resize: Takes effect if the contained widget does not have a layout + QSize nonLaidOutMinSize() const; + void setNonLaidOutMinSize(const QSize &s); + + QSize nonLaidOutSizeHint() const; + void setNonLaidOutSizeHint(const QSize &s); + + // Check whether a QDesignerWidgetItem should be installed + static bool check(const QLayout *layout, QWidget *w, Qt::Orientations *ptrToOrientations = 0); + + // Register itself using QLayoutPrivate's widget item factory method hook + static void install(); + static void deinstall(); + + // Check for a non-container extension container + static bool isContainer(const QDesignerFormEditorInterface *core, QWidget *w); + + static bool subjectToStretch(const QLayout *layout, QWidget *w); + + virtual bool eventFilter(QObject * watched, QEvent * event); + +private slots: + void layoutChanged(); + +private: + void expand(QSize *s) const; + bool subjectToStretch() const; + + const Qt::Orientations m_orientations; + mutable QSize m_nonLaidOutMinSize; + mutable QSize m_nonLaidOutSizeHint; + mutable const QLayout *m_cachedContainingLayout; +}; + +// Helper class that ensures QDesignerWidgetItem is installed while an +// instance is in scope. + +class QDESIGNER_SHARED_EXPORT QDesignerWidgetItemInstaller { + Q_DISABLE_COPY(QDesignerWidgetItemInstaller) + +public: + QDesignerWidgetItemInstaller(); + ~QDesignerWidgetItemInstaller(); + +private: + static int m_instanceCount; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif diff --git a/src/designer/src/lib/shared/qlayout_widget.cpp b/src/designer/src/lib/shared/qlayout_widget.cpp new file mode 100644 index 000000000..66e7a795b --- /dev/null +++ b/src/designer/src/lib/shared/qlayout_widget.cpp @@ -0,0 +1,2107 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qlayout_widget_p.h" +#include "qdesigner_utils_p.h" +#include "layout_p.h" +#include "layoutinfo_p.h" +#include "invisible_widget_p.h" +#include "qdesigner_widgetitem_p.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +enum { ShiftValue = 1 }; +enum { debugLayout = 0 }; +enum { FormLayoutColumns = 2 }; +enum { indicatorSize = 2 }; +// Grid/form Helpers: get info (overloads to make templates work) + +namespace { // Do not use static, will break HP-UX due to templates + +QT_USE_NAMESPACE + +// overloads to make templates over QGridLayout/QFormLayout work +inline int gridRowCount(const QGridLayout *gridLayout) +{ + return gridLayout->rowCount(); +} + +inline int gridColumnCount(const QGridLayout *gridLayout) +{ + return gridLayout->columnCount(); +} + +// QGridLayout/QFormLayout Helpers: get item position (overloads to make templates work) +inline void getGridItemPosition(QGridLayout *gridLayout, int index, + int *row, int *column, int *rowspan, int *colspan) +{ + gridLayout->getItemPosition(index, row, column, rowspan, colspan); +} + +QRect gridItemInfo(QGridLayout *grid, int index) +{ + int row, column, rowSpan, columnSpan; + // getItemPosition is not const, grmbl.. + grid->getItemPosition(index, &row, &column, &rowSpan, &columnSpan); + return QRect(column, row, columnSpan, rowSpan); +} + +inline int gridRowCount(const QFormLayout *formLayout) { return formLayout->rowCount(); } +inline int gridColumnCount(const QFormLayout *) { return FormLayoutColumns; } + +inline void getGridItemPosition(QFormLayout *formLayout, int index, int *row, int *column, int *rowspan, int *colspan) +{ + qdesigner_internal::getFormLayoutItemPosition(formLayout, index, row, column, rowspan, colspan); +} + +QRect gridItemInfo(const QFormLayout *form, int index) +{ + int row; + int column; + int colspan; + qdesigner_internal::getFormLayoutItemPosition(form, index, &row, &column, 0, &colspan); + return QRect(column, row, colspan, 1); +} +} // namespace anonymous + +QT_BEGIN_NAMESPACE + +static const char *objectNameC = "objectName"; +static const char *sizeConstraintC = "sizeConstraint"; + +/* A padding spacer element that is used to represent an empty form layout cell. It should grow with its cell. + * Should not be used on a grid as it causes resizing inconsistencies */ +namespace qdesigner_internal { + class PaddingSpacerItem : public QSpacerItem { + public: + PaddingSpacerItem() : QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding) {} + virtual Qt::Orientations expandingDirections () const { return Qt::Vertical | Qt::Horizontal; } + }; +} + +static inline QSpacerItem *createGridSpacer() +{ + return new QSpacerItem(0, 0); +} + +static inline QSpacerItem *createFormSpacer() +{ + return new qdesigner_internal::PaddingSpacerItem; +} + +// QGridLayout/QFormLayout Helpers: Debug items of GridLikeLayout +template +static QDebug debugGridLikeLayout(QDebug str, const GridLikeLayout &gl) +{ + const int count = gl.count(); + str << "Grid: " << gl.objectName() << gridRowCount(&gl) << " rows x " << gridColumnCount(&gl) + << " cols " << count << " items\n"; + for (int i = 0; i < count; i++) { + QLayoutItem *item = gl.itemAt(i); + str << "Item " << i << item << item->widget() << gridItemInfo(const_cast(&gl), i) << " empty=" << qdesigner_internal::LayoutInfo::isEmptyItem(item) << "\n"; + } + return str; +} + +static inline QDebug operator<<(QDebug str, const QGridLayout &gl) { return debugGridLikeLayout(str, gl); } +static inline QDebug operator<<(QDebug str, const QFormLayout &fl) { return debugGridLikeLayout(str, fl); } + +static inline bool isEmptyFormLayoutRow(const QFormLayout *fl, int row) +{ + // Spanning can never be empty + if (fl->itemAt(row, QFormLayout::SpanningRole)) + return false; + return qdesigner_internal::LayoutInfo::isEmptyItem(fl->itemAt(row, QFormLayout::LabelRole)) && qdesigner_internal::LayoutInfo::isEmptyItem(fl->itemAt(row, QFormLayout::FieldRole)); +} + +static inline bool canSimplifyFormLayout(const QFormLayout *formLayout, const QRect &restrictionArea) +{ + if (restrictionArea.x() >= FormLayoutColumns) + return false; + // Try to find empty rows + const int bottomCheckRow = qMin(formLayout->rowCount(), restrictionArea.top() + restrictionArea.height()); + for (int r = restrictionArea.y(); r < bottomCheckRow; r++) + if (isEmptyFormLayoutRow(formLayout, r)) + return true; + return false; +} + +// recreate a managed layout (which does not automagically remove +// empty rows/columns like grid or form layout) in case it needs to shrink + +static QLayout *recreateManagedLayout(const QDesignerFormEditorInterface *core, QWidget *w, QLayout *lt) +{ + const qdesigner_internal::LayoutInfo::Type t = qdesigner_internal::LayoutInfo::layoutType(core, lt); + qdesigner_internal::LayoutProperties properties; + const int mask = properties.fromPropertySheet(core, lt, qdesigner_internal::LayoutProperties::AllProperties); + qdesigner_internal::LayoutInfo::deleteLayout(core, w); + QLayout *rc = core->widgetFactory()->createLayout(w, 0, t); + properties.toPropertySheet(core, rc, mask, true); + return rc; +} + +// QGridLayout/QFormLayout Helpers: find an item on a form/grid. Return index +template +int findGridItemAt(GridLikeLayout *gridLayout, int at_row, int at_column) +{ + Q_ASSERT(gridLayout); + const int count = gridLayout->count(); + for (int index = 0; index < count; index++) { + int row, column, rowspan, colspan; + getGridItemPosition(gridLayout, index, &row, &column, &rowspan, &colspan); + if (at_row >= row && at_row < (row + rowspan) + && at_column >= column && at_column < (column + colspan)) { + return index; + } + } + return -1; +} +// QGridLayout/QFormLayout Helpers: remove dummy spacers on form/grid +template +static bool removeEmptyCellsOnGrid(GridLikeLayout *grid, const QRect &area) +{ + // check if there are any items in the way. Should be only spacers + // Unique out items that span rows/columns. + QVector indexesToBeRemoved; + indexesToBeRemoved.reserve(grid->count()); + const int rightColumn = area.x() + area.width(); + const int bottomRow = area.y() + area.height(); + for (int c = area.x(); c < rightColumn; c++) + for (int r = area.y(); r < bottomRow; r++) { + const int index = findGridItemAt(grid, r ,c); + if (index != -1) + if (QLayoutItem *item = grid->itemAt(index)) { + if (qdesigner_internal::LayoutInfo::isEmptyItem(item)) { + if (indexesToBeRemoved.indexOf(index) == -1) + indexesToBeRemoved.push_back(index); + } else { + return false; + } + } + } + // remove, starting from last + if (!indexesToBeRemoved.empty()) { + qStableSort(indexesToBeRemoved.begin(), indexesToBeRemoved.end()); + for (int i = indexesToBeRemoved.size() - 1; i >= 0; i--) + delete grid->takeAt(indexesToBeRemoved[i]); + } + return true; +} + +namespace qdesigner_internal { +// --------- LayoutProperties + +LayoutProperties::LayoutProperties() +{ + clear(); +} + +void LayoutProperties::clear() +{ + qFill(m_margins, m_margins + MarginCount, 0); + qFill(m_marginsChanged, m_marginsChanged + MarginCount, false); + qFill(m_spacings, m_spacings + SpacingsCount, 0); + qFill(m_spacingsChanged, m_spacingsChanged + SpacingsCount, false); + + m_objectName = QVariant(); + m_objectNameChanged = false; + m_sizeConstraint = QVariant(QLayout::SetDefaultConstraint); + m_sizeConstraintChanged = false; + + m_fieldGrowthPolicyChanged = m_rowWrapPolicyChanged = m_labelAlignmentChanged = m_formAlignmentChanged = false; + m_fieldGrowthPolicy = m_rowWrapPolicy = m_formAlignment = QVariant(); + + m_boxStretchChanged = m_gridRowStretchChanged = m_gridColumnStretchChanged = m_gridRowMinimumHeightChanged = false; + m_boxStretch = m_gridRowStretch = m_gridColumnStretch = m_gridRowMinimumHeight = QVariant(); +} + +int LayoutProperties::visibleProperties(const QLayout *layout) +{ + // Grid like layout have 2 spacings. + const bool isFormLayout = qobject_cast(layout); + const bool isGridLike = qobject_cast(layout) || isFormLayout; + int rc = ObjectNameProperty|LeftMarginProperty|TopMarginProperty|RightMarginProperty|BottomMarginProperty| + SizeConstraintProperty; + + rc |= isGridLike ? (HorizSpacingProperty|VertSpacingProperty) : SpacingProperty; + if (isFormLayout) { + rc |= FieldGrowthPolicyProperty|RowWrapPolicyProperty|LabelAlignmentProperty|FormAlignmentProperty; + } else { + if (isGridLike) { + rc |= GridRowStretchProperty|GridColumnStretchProperty|GridRowMinimumHeightProperty|GridColumnMinimumWidthProperty; + } else { + rc |= BoxStretchProperty; + } + } + return rc; +} + +static const char *marginPropertyNamesC[] = {"leftMargin", "topMargin", "rightMargin", "bottomMargin"}; +static const char *spacingPropertyNamesC[] = {"spacing", "horizontalSpacing", "verticalSpacing" }; +static const char *fieldGrowthPolicyPropertyC = "fieldGrowthPolicy"; +static const char *rowWrapPolicyPropertyC = "rowWrapPolicy"; +static const char *labelAlignmentPropertyC = "labelAlignment"; +static const char *formAlignmentPropertyC = "formAlignment"; +static const char *boxStretchPropertyC = "stretch"; +static const char *gridRowStretchPropertyC = "rowStretch"; +static const char *gridColumnStretchPropertyC = "columnStretch"; +static const char *gridRowMinimumHeightPropertyC = "rowMinimumHeight"; +static const char *gridColumnMinimumWidthPropertyC = "columnMinimumWidth"; + +static bool intValueFromSheet(const QDesignerPropertySheetExtension *sheet, const QString &name, int *value, bool *changed) +{ + const int sheetIndex = sheet->indexOf(name); + if (sheetIndex == -1) + return false; + *value = sheet->property(sheetIndex).toInt(); + *changed = sheet->isChanged(sheetIndex); + return true; +} + +static void variantPropertyFromSheet(int mask, int flag, const QDesignerPropertySheetExtension *sheet, const QString &name, + QVariant *value, bool *changed, int *returnMask) +{ + if (mask & flag) { + const int sIndex = sheet->indexOf(name); + if (sIndex != -1) { + *value = sheet->property(sIndex); + *changed = sheet->isChanged(sIndex); + *returnMask |= flag; + } + } +} + +int LayoutProperties::fromPropertySheet(const QDesignerFormEditorInterface *core, QLayout *l, int mask) +{ + int rc = 0; + const QDesignerPropertySheetExtension *sheet = qt_extension(core->extensionManager(), l); + Q_ASSERT(sheet); + // name + if (mask & ObjectNameProperty) { + const int nameIndex = sheet->indexOf(QLatin1String(objectNameC)); + Q_ASSERT(nameIndex != -1); + m_objectName = sheet->property(nameIndex); + m_objectNameChanged = sheet->isChanged(nameIndex); + rc |= ObjectNameProperty; + } + // -- Margins + const int marginFlags[MarginCount] = { LeftMarginProperty, TopMarginProperty, RightMarginProperty, BottomMarginProperty}; + for (int i = 0; i < MarginCount; i++) + if (mask & marginFlags[i]) + if (intValueFromSheet(sheet, QLatin1String(marginPropertyNamesC[i]), m_margins + i, m_marginsChanged + i)) + rc |= marginFlags[i]; + + const int spacingFlags[] = { SpacingProperty, HorizSpacingProperty, VertSpacingProperty}; + for (int i = 0; i < SpacingsCount; i++) + if (mask & spacingFlags[i]) + if (intValueFromSheet(sheet, QLatin1String(spacingPropertyNamesC[i]), m_spacings + i, m_spacingsChanged + i)) + rc |= spacingFlags[i]; + // sizeConstraint, flags + variantPropertyFromSheet(mask, SizeConstraintProperty, sheet, QLatin1String(sizeConstraintC), &m_sizeConstraint, &m_sizeConstraintChanged, &rc); + variantPropertyFromSheet(mask, FieldGrowthPolicyProperty, sheet, QLatin1String(fieldGrowthPolicyPropertyC), &m_fieldGrowthPolicy, &m_fieldGrowthPolicyChanged, &rc); + variantPropertyFromSheet(mask, RowWrapPolicyProperty, sheet, QLatin1String(rowWrapPolicyPropertyC), &m_rowWrapPolicy, &m_rowWrapPolicyChanged, &rc); + variantPropertyFromSheet(mask, LabelAlignmentProperty, sheet, QLatin1String(labelAlignmentPropertyC), &m_labelAlignment, &m_labelAlignmentChanged, &rc); + variantPropertyFromSheet(mask, FormAlignmentProperty, sheet, QLatin1String(formAlignmentPropertyC), &m_formAlignment, &m_formAlignmentChanged, &rc); + variantPropertyFromSheet(mask, BoxStretchProperty, sheet, QLatin1String(boxStretchPropertyC), &m_boxStretch, & m_boxStretchChanged, &rc); + variantPropertyFromSheet(mask, GridRowStretchProperty, sheet, QLatin1String(gridRowStretchPropertyC), &m_gridRowStretch, &m_gridRowStretchChanged, &rc); + variantPropertyFromSheet(mask, GridColumnStretchProperty, sheet, QLatin1String(gridColumnStretchPropertyC), &m_gridColumnStretch, &m_gridColumnStretchChanged, &rc); + variantPropertyFromSheet(mask, GridRowMinimumHeightProperty, sheet, QLatin1String(gridRowMinimumHeightPropertyC), &m_gridRowMinimumHeight, &m_gridRowMinimumHeightChanged, &rc); + variantPropertyFromSheet(mask, GridColumnMinimumWidthProperty, sheet, QLatin1String(gridColumnMinimumWidthPropertyC), &m_gridColumnMinimumWidth, &m_gridColumnMinimumWidthChanged, &rc); + return rc; +} + +static bool intValueToSheet(QDesignerPropertySheetExtension *sheet, const QString &name, int value, bool changed, bool applyChanged) + +{ + + const int sheetIndex = sheet->indexOf(name); + if (sheetIndex == -1) { + qWarning() << " LayoutProperties: Attempt to set property " << name << " that does not exist for the layout."; + return false; + } + sheet->setProperty(sheetIndex, QVariant(value)); + if (applyChanged) + sheet->setChanged(sheetIndex, changed); + return true; +} + +static void variantPropertyToSheet(int mask, int flag, bool applyChanged, QDesignerPropertySheetExtension *sheet, const QString &name, + const QVariant &value, bool changed, int *returnMask) +{ + if (mask & flag) { + const int sIndex = sheet->indexOf(name); + if (sIndex != -1) { + sheet->setProperty(sIndex, value); + if (applyChanged) + sheet->setChanged(sIndex, changed); + *returnMask |= flag; + } + } +} + +int LayoutProperties::toPropertySheet(const QDesignerFormEditorInterface *core, QLayout *l, int mask, bool applyChanged) const +{ + int rc = 0; + QDesignerPropertySheetExtension *sheet = qt_extension(core->extensionManager(), l); + Q_ASSERT(sheet); + // name + if (mask & ObjectNameProperty) { + const int nameIndex = sheet->indexOf(QLatin1String(objectNameC)); + Q_ASSERT(nameIndex != -1); + sheet->setProperty(nameIndex, m_objectName); + if (applyChanged) + sheet->setChanged(nameIndex, m_objectNameChanged); + rc |= ObjectNameProperty; + } + // margins + const int marginFlags[MarginCount] = { LeftMarginProperty, TopMarginProperty, RightMarginProperty, BottomMarginProperty}; + for (int i = 0; i < MarginCount; i++) + if (mask & marginFlags[i]) + if (intValueToSheet(sheet, QLatin1String(marginPropertyNamesC[i]), m_margins[i], m_marginsChanged[i], applyChanged)) + rc |= marginFlags[i]; + + const int spacingFlags[] = { SpacingProperty, HorizSpacingProperty, VertSpacingProperty}; + for (int i = 0; i < SpacingsCount; i++) + if (mask & spacingFlags[i]) + if (intValueToSheet(sheet, QLatin1String(spacingPropertyNamesC[i]), m_spacings[i], m_spacingsChanged[i], applyChanged)) + rc |= spacingFlags[i]; + // sizeConstraint + variantPropertyToSheet(mask, SizeConstraintProperty, applyChanged, sheet, QLatin1String(sizeConstraintC), m_sizeConstraint, m_sizeConstraintChanged, &rc); + variantPropertyToSheet(mask, FieldGrowthPolicyProperty, applyChanged, sheet, QLatin1String(fieldGrowthPolicyPropertyC), m_fieldGrowthPolicy, &m_fieldGrowthPolicyChanged, &rc); + variantPropertyToSheet(mask, RowWrapPolicyProperty, applyChanged, sheet, QLatin1String(rowWrapPolicyPropertyC), m_rowWrapPolicy, m_rowWrapPolicyChanged, &rc); + variantPropertyToSheet(mask, LabelAlignmentProperty, applyChanged, sheet, QLatin1String(labelAlignmentPropertyC), m_labelAlignment, m_labelAlignmentChanged, &rc); + variantPropertyToSheet(mask, FormAlignmentProperty, applyChanged, sheet, QLatin1String(formAlignmentPropertyC), m_formAlignment, m_formAlignmentChanged, &rc); + variantPropertyToSheet(mask, BoxStretchProperty, applyChanged, sheet, QLatin1String(boxStretchPropertyC), m_boxStretch, m_boxStretchChanged, &rc); + variantPropertyToSheet(mask, GridRowStretchProperty, applyChanged, sheet, QLatin1String(gridRowStretchPropertyC), m_gridRowStretch, m_gridRowStretchChanged, &rc); + variantPropertyToSheet(mask, GridColumnStretchProperty, applyChanged, sheet, QLatin1String(gridColumnStretchPropertyC), m_gridColumnStretch, m_gridColumnStretchChanged, &rc); + variantPropertyToSheet(mask, GridRowMinimumHeightProperty, applyChanged, sheet, QLatin1String(gridRowMinimumHeightPropertyC), m_gridRowMinimumHeight, m_gridRowMinimumHeightChanged, &rc); + variantPropertyToSheet(mask, GridColumnMinimumWidthProperty, applyChanged, sheet, QLatin1String(gridColumnMinimumWidthPropertyC), m_gridColumnMinimumWidth, m_gridColumnMinimumWidthChanged, &rc); + return rc; +} + +// ---------------- LayoutHelper +LayoutHelper::LayoutHelper() +{ +} + +LayoutHelper::~LayoutHelper() +{ +} + +int LayoutHelper::indexOf(const QLayout *lt, const QWidget *widget) +{ + if (!lt) + return -1; + + const int itemCount = lt->count(); + for (int i = 0; i < itemCount; i++) + if (lt->itemAt(i)->widget() == widget) + return i; + return -1; +} + +QRect LayoutHelper::itemInfo(QLayout *lt, const QWidget *widget) const +{ + const int index = indexOf(lt, widget); + if (index == -1) { + qWarning() << "LayoutHelper::itemInfo: " << widget << " not in layout " << lt; + return QRect(0, 0, 1, 1); + } + return itemInfo(lt, index); +} + + // ---------------- BoxLayoutHelper + class BoxLayoutHelper : public LayoutHelper { + public: + BoxLayoutHelper(const Qt::Orientation orientation) : m_orientation(orientation) {} + + virtual QRect itemInfo(QLayout *lt, int index) const; + virtual void insertWidget(QLayout *lt, const QRect &info, QWidget *w); + virtual void removeWidget(QLayout *lt, QWidget *widget); + virtual void replaceWidget(QLayout *lt, QWidget *before, QWidget *after); + + virtual void pushState(const QDesignerFormEditorInterface *, const QWidget *); + virtual void popState(const QDesignerFormEditorInterface *, QWidget *); + + virtual bool canSimplify(const QDesignerFormEditorInterface *, const QWidget *, const QRect &) const { return false; } + virtual void simplify(const QDesignerFormEditorInterface *, QWidget *, const QRect &) {} + + // Helper for restoring layout states + typedef QVector LayoutItemVector; + static LayoutItemVector disassembleLayout(QLayout *lt); + static QLayoutItem *findItemOfWidget(const LayoutItemVector &lv, QWidget *w); + + private: + typedef QVector BoxLayoutState; + + static BoxLayoutState state(const QBoxLayout*lt); + + QStack m_states; + const Qt::Orientation m_orientation; + }; + + QRect BoxLayoutHelper::itemInfo(QLayout * /*lt*/, int index) const + { + return m_orientation == Qt::Horizontal ? QRect(index, 0, 1, 1) : QRect(0, index, 1, 1); + } + + void BoxLayoutHelper::insertWidget(QLayout *lt, const QRect &info, QWidget *w) + { + QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem. + QBoxLayout *boxLayout = qobject_cast(lt); + Q_ASSERT(boxLayout); + boxLayout->insertWidget(m_orientation == Qt::Horizontal ? info.x() : info.y(), w); + } + + void BoxLayoutHelper::removeWidget(QLayout *lt, QWidget *widget) + { + QBoxLayout *boxLayout = qobject_cast(lt); + Q_ASSERT(boxLayout); + boxLayout->removeWidget(widget); + } + + void BoxLayoutHelper::replaceWidget(QLayout *lt, QWidget *before, QWidget *after) + { + bool ok = false; + QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem. + if (QBoxLayout *boxLayout = qobject_cast(lt)) { + const int index = boxLayout->indexOf(before); + if (index != -1) { + const bool visible = before->isVisible(); + delete boxLayout->takeAt(index); + if (visible) + before->hide(); + before->setParent(0); + boxLayout->insertWidget(index, after); + ok = true; + } + } + if (!ok) + qWarning() << "BoxLayoutHelper::replaceWidget : Unable to replace " << before << " by " << after << " in " << lt; + } + + BoxLayoutHelper::BoxLayoutState BoxLayoutHelper::state(const QBoxLayout*lt) + { + BoxLayoutState rc; + if (const int count = lt->count()) { + rc.reserve(count); + for (int i = 0; i < count; i++) + if (QWidget *w = lt->itemAt(i)->widget()) + rc.push_back(w); + } + return rc; + } + + void BoxLayoutHelper::pushState(const QDesignerFormEditorInterface *core, const QWidget *w) + { + const QBoxLayout *boxLayout = qobject_cast(LayoutInfo::managedLayout(core, w)); + Q_ASSERT(boxLayout); + m_states.push(state(boxLayout)); + } + + QLayoutItem *BoxLayoutHelper::findItemOfWidget(const LayoutItemVector &lv, QWidget *w) + { + const LayoutItemVector::const_iterator cend = lv.constEnd(); + for (LayoutItemVector::const_iterator it = lv.constBegin(); it != cend; ++it) + if ( (*it)->widget() == w) + return *it; + + return 0; + } + + BoxLayoutHelper::LayoutItemVector BoxLayoutHelper::disassembleLayout(QLayout *lt) + { + // Take items + const int count = lt->count(); + if (count == 0) + return LayoutItemVector(); + LayoutItemVector rc; + rc.reserve(count); + for (int i = count - 1; i >= 0; i--) + rc.push_back(lt->takeAt(i)); + return rc; + } + + void BoxLayoutHelper::popState(const QDesignerFormEditorInterface *core, QWidget *w) + { + QBoxLayout *boxLayout = qobject_cast(LayoutInfo::managedLayout(core, w)); + Q_ASSERT(boxLayout); + const BoxLayoutState savedState = m_states.pop(); + const BoxLayoutState currentState = state(boxLayout); + // Check for equality/empty. Note that this will currently + // always trigger as box layouts do not have a state apart from + // the order and there is no layout order editor yet. + if (savedState == state(boxLayout)) + return; + + const int count = savedState.size(); + Q_ASSERT(count == currentState.size()); + // Take items and reassemble in saved order + const LayoutItemVector items = disassembleLayout(boxLayout); + for (int i = 0; i < count; i++) { + QLayoutItem *item = findItemOfWidget(items, savedState[i]); + Q_ASSERT(item); + boxLayout->addItem(item); + } + } + + // Grid Layout state. Datatype storing the state of a GridLayout as a map of + // widgets to QRect(columns, rows) and size. Used to store the state for undo operations + // that do not change the widgets within the layout; also provides some manipulation + // functions and ability to apply the state to a layout provided its widgets haven't changed. + struct GridLayoutState { + GridLayoutState(); + + void fromLayout(QGridLayout *l); + void applyToLayout(const QDesignerFormEditorInterface *core, QWidget *w) const; + + void insertRow(int row); + void insertColumn(int column); + + bool simplify(const QRect &r, bool testOnly); + void removeFreeRow(int row); + void removeFreeColumn(int column); + + + // State of a cell in one dimension + enum DimensionCellState { + Free, + Spanned, // Item spans it + Occupied // Item bordering on it + }; + // Horiontal, Vertical pair of state + typedef QPair CellState; + typedef QVector CellStates; + + // Figure out states of a cell and return as a flat vector of + // [column1, column2,...] (address as row * columnCount + col) + static CellStates cellStates(const QList &rects, int numRows, int numColumns); + + typedef QMap WidgetItemMap; + typedef QMap WidgetAlignmentMap; + + WidgetItemMap widgetItemMap; + WidgetAlignmentMap widgetAlignmentMap; + + int rowCount; + int colCount; + }; + + static inline bool needsSpacerItem(const GridLayoutState::CellState &cs) { + return cs.first == GridLayoutState::Free && cs.second == GridLayoutState::Free; + } + + static inline QDebug operator<<(QDebug str, const GridLayoutState &gs) + { + str << "GridLayoutState: " << gs.rowCount << " rows x " << gs.colCount + << " cols " << gs.widgetItemMap.size() << " items\n"; + + const GridLayoutState::WidgetItemMap::const_iterator wcend = gs.widgetItemMap.constEnd(); + for (GridLayoutState::WidgetItemMap::const_iterator it = gs.widgetItemMap.constBegin(); it != wcend; ++it) + str << "Item " << it.key() << it.value() << '\n'; + return str; + } + + GridLayoutState::GridLayoutState() : + rowCount(0), + colCount(0) + { + } + + GridLayoutState::CellStates GridLayoutState::cellStates(const QList &rects, int numRows, int numColumns) + { + CellStates rc = CellStates(numRows * numColumns, CellState(Free, Free)); + const QList::const_iterator rcend = rects.constEnd(); + for (QList::const_iterator it = rects.constBegin(); it != rcend; ++it) { + const int leftColumn = it->x(); + const int topRow = it->y(); + const int rightColumn = leftColumn + it->width() - 1; + const int bottomRow = topRow + it->height() - 1; + for (int r = topRow; r <= bottomRow; r++) + for (int c = leftColumn; c <= rightColumn; c++) { + const int flatIndex = r * numColumns + c; + // Bordering horizontally? + DimensionCellState &horizState = rc[flatIndex].first; + if (c == leftColumn || c == rightColumn) { + horizState = Occupied; + } else { + if (horizState < Spanned) + horizState = Spanned; + } + // Bordering vertically? + DimensionCellState &vertState = rc[flatIndex].second; + if (r == topRow || r == bottomRow) { + vertState = Occupied; + } else { + if (vertState < Spanned) + vertState = Spanned; + } + } + } + if (debugLayout) { + qDebug() << "GridLayoutState::cellStates: " << numRows << " x " << numColumns; + for (int r = 0; r < numRows; r++) + for (int c = 0; c < numColumns; c++) + qDebug() << " Row: " << r << " column: " << c << rc[r * numColumns + c]; + } + return rc; + } + + void GridLayoutState::fromLayout(QGridLayout *l) + { + rowCount = l->rowCount(); + colCount = l->columnCount(); + const int count = l->count(); + for (int i = 0; i < count; i++) { + QLayoutItem *item = l->itemAt(i); + if (!LayoutInfo::isEmptyItem(item)) { + widgetItemMap.insert(item->widget(), gridItemInfo(l, i)); + if (item->alignment()) + widgetAlignmentMap.insert(item->widget(), item->alignment()); + } + } + } + + void GridLayoutState::applyToLayout(const QDesignerFormEditorInterface *core, QWidget *w) const + { + typedef QMap LayoutItemRectMap; + QGridLayout *grid = qobject_cast(LayoutInfo::managedLayout(core, w)); + Q_ASSERT(grid); + if (debugLayout) + qDebug() << ">GridLayoutState::applyToLayout" << *this << *grid; + const bool shrink = grid->rowCount() > rowCount || grid->columnCount() > colCount; + // Build a map of existing items to rectangles via widget map, delete spacers + LayoutItemRectMap itemMap; + while (grid->count()) { + QLayoutItem *item = grid->takeAt(0); + if (!LayoutInfo::isEmptyItem(item)) { + QWidget *itemWidget = item->widget(); + const WidgetItemMap::const_iterator it = widgetItemMap.constFind(itemWidget); + if (it == widgetItemMap.constEnd()) + qFatal("GridLayoutState::applyToLayout: Attempt to apply to a layout that has a widget '%s'/'%s' added after saving the state.", + itemWidget->metaObject()->className(), itemWidget->objectName().toUtf8().constData()); + itemMap.insert(item, it.value()); + } else { + delete item; + } + } + Q_ASSERT(itemMap.size() == widgetItemMap.size()); + // recreate if shrink + if (shrink) + grid = static_cast(recreateManagedLayout(core, w, grid)); + + // Add widgets items + const LayoutItemRectMap::const_iterator icend = itemMap.constEnd(); + for (LayoutItemRectMap::const_iterator it = itemMap.constBegin(); it != icend; ++it) { + const QRect info = it.value(); + const Qt::Alignment alignment = widgetAlignmentMap.value(it.key()->widget(), Qt::Alignment(0)); + grid->addItem(it.key(), info.y(), info.x(), info.height(), info.width(), alignment); + } + // create spacers + const CellStates cs = cellStates(itemMap.values(), rowCount, colCount); + for (int r = 0; r < rowCount; r++) + for (int c = 0; c < colCount; c++) + if (needsSpacerItem(cs[r * colCount + c])) + grid->addItem(createGridSpacer(), r, c); + grid->activate(); + if (debugLayout) + qDebug() << "= row) { + it.value().translate(0, 1); + } else { //Over it: Does it span it -> widen? + const int rowSpan = it.value().height(); + if (rowSpan > 1 && topRow + rowSpan > row) + it.value().setHeight(rowSpan + 1); + } + } + } + + void GridLayoutState::insertColumn(int column) + { + colCount++; + const WidgetItemMap::iterator iend = widgetItemMap.end(); + for (WidgetItemMap::iterator it = widgetItemMap.begin(); it != iend; ++it) { + const int leftColumn = it.value().x(); + if (leftColumn >= column) { + it.value().translate(1, 0); + } else { // Left of it: Does it span it -> widen? + const int colSpan = it.value().width(); + if (colSpan > 1 && leftColumn + colSpan > column) + it.value().setWidth(colSpan + 1); + } + } + } + + // Simplify: Remove empty columns/rows and such ones that are only spanned (shrink + // spanning items). + // 'AB.C.' 'ABC' + // 'DDDD.' ==> 'DDD' + // 'EF.G.' 'EFG' + bool GridLayoutState::simplify(const QRect &r, bool testOnly) + { + // figure out free rows/columns. + QVector occupiedRows(rowCount, false); + QVector occupiedColumns(colCount, false); + // Mark everything outside restriction rectangle as occupied + const int restrictionLeftColumn = r.x(); + const int restrictionRightColumn = restrictionLeftColumn + r.width(); + const int restrictionTopRow = r.y(); + const int restrictionBottomRow = restrictionTopRow + r.height(); + if (restrictionLeftColumn > 0 || restrictionRightColumn < colCount || + restrictionTopRow > 0 || restrictionBottomRow < rowCount) { + for (int r = 0; r < rowCount; r++) + if (r < restrictionTopRow || r >= restrictionBottomRow) + occupiedRows[r] = true; + for (int c = 0; c < colCount; c++) + if (c < restrictionLeftColumn || c >= restrictionRightColumn) + occupiedColumns[c] = true; + } + // figure out free fields and tick off occupied rows and columns + const CellStates cs = cellStates(widgetItemMap.values(), rowCount, colCount); + for (int r = 0; r < rowCount; r++) + for (int c = 0; c < colCount; c++) { + const CellState &state = cs[r * colCount + c]; + if (state.first == Occupied) + occupiedColumns[c] = true; + if (state.second == Occupied) + occupiedRows[r] = true; + } + // Any free rows/columns? + if (occupiedRows.indexOf(false) == -1 && occupiedColumns.indexOf(false) == -1) + return false; + if (testOnly) + return true; + // remove rows + for (int r = rowCount - 1; r >= 0; r--) + if (!occupiedRows[r]) + removeFreeRow(r); + // remove columns + for (int c = colCount - 1; c >= 0; c--) + if (!occupiedColumns[c]) + removeFreeColumn(c); + return true; + } + + void GridLayoutState::removeFreeRow(int removeRow) + { + const WidgetItemMap::iterator iend = widgetItemMap.end(); + for (WidgetItemMap::iterator it = widgetItemMap.begin(); it != iend; ++it) { + const int r = it.value().y(); + Q_ASSERT(r != removeRow); // Free rows only + if (r < removeRow) { // Does the item span it? - shrink it + const int rowSpan = it.value().height(); + if (rowSpan > 1) { + const int bottomRow = r + rowSpan; + if (bottomRow > removeRow) + it.value().setHeight(rowSpan - 1); + } + } else + if (r > removeRow) // Item below it? - move. + it.value().translate(0, -1); + } + rowCount--; + } + + void GridLayoutState::removeFreeColumn(int removeColumn) + { + const WidgetItemMap::iterator iend = widgetItemMap.end(); + for (WidgetItemMap::iterator it = widgetItemMap.begin(); it != iend; ++it) { + const int c = it.value().x(); + Q_ASSERT(c != removeColumn); // Free columns only + if (c < removeColumn) { // Does the item span it? - shrink it + const int colSpan = it.value().width(); + if (colSpan > 1) { + const int rightColumn = c + colSpan; + if (rightColumn > removeColumn) + it.value().setWidth(colSpan - 1); + } + } else + if (c > removeColumn) // Item to the right of it? - move. + it.value().translate(-1, 0); + } + colCount--; + } + + // ---------------- GridLayoutHelper + class GridLayoutHelper : public LayoutHelper { + public: + GridLayoutHelper() {} + + virtual QRect itemInfo(QLayout *lt, int index) const; + virtual void insertWidget(QLayout *lt, const QRect &info, QWidget *w); + virtual void removeWidget(QLayout *lt, QWidget *widget); + virtual void replaceWidget(QLayout *lt, QWidget *before, QWidget *after); + + virtual void pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout); + virtual void popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout); + + virtual bool canSimplify(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout, const QRect &restrictionArea) const; + virtual void simplify(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout, const QRect &restrictionArea); + + static void insertRow(QGridLayout *grid, int row); + + private: + QStack m_states; + }; + + void GridLayoutHelper::insertRow(QGridLayout *grid, int row) + { + GridLayoutState state; + state.fromLayout(grid); + state.insertRow(row); + QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(grid); + state.applyToLayout(fw->core(), grid->parentWidget()); + } + + QRect GridLayoutHelper::itemInfo(QLayout * lt, int index) const + { + QGridLayout *grid = qobject_cast(lt); + Q_ASSERT(grid); + return gridItemInfo(grid, index); + } + + void GridLayoutHelper::insertWidget(QLayout *lt, const QRect &info, QWidget *w) + { + QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem. + QGridLayout *gridLayout = qobject_cast(lt); + Q_ASSERT(gridLayout); + // check if there are any items. Should be only spacers, else something is wrong + const int row = info.y(); + int column = info.x(); + int colSpan = info.width(); + int rowSpan = info.height(); + // If not empty: A multiselection was dropped on an empty item, insert row + // and spread items along new row + if (!removeEmptyCellsOnGrid(gridLayout, info)) { + int freeColumn = -1; + colSpan = rowSpan = 1; + // First look to the right for a free column + const int columnCount = gridLayout->columnCount(); + for (int c = column; c < columnCount; c++) { + const int idx = findGridItemAt(gridLayout, row, c); + if (idx != -1 && LayoutInfo::isEmptyItem(gridLayout->itemAt(idx))) { + freeColumn = c; + break; + } + } + if (freeColumn != -1) { + removeEmptyCellsOnGrid(gridLayout, QRect(freeColumn, row, 1, 1)); + column = freeColumn; + } else { + GridLayoutHelper::insertRow(gridLayout, row); + column = 0; + } + } + gridLayout->addWidget(w, row , column, rowSpan, colSpan); + } + + void GridLayoutHelper::removeWidget(QLayout *lt, QWidget *widget) + { + QGridLayout *gridLayout = qobject_cast(lt); + Q_ASSERT(gridLayout); + const int index = gridLayout->indexOf(widget); + if (index == -1) { + qWarning() << "GridLayoutHelper::removeWidget : Attempt to remove " << widget << " which is not in the layout."; + return; + } + // delete old item and pad with by spacer items + int row, column, rowspan, colspan; + gridLayout->getItemPosition(index, &row, &column, &rowspan, &colspan); + delete gridLayout->takeAt(index); + const int rightColumn = column + colspan; + const int bottomRow = row + rowspan; + for (int c = column; c < rightColumn; c++) + for (int r = row; r < bottomRow; r++) + gridLayout->addItem(createGridSpacer(), r, c); + } + + void GridLayoutHelper::replaceWidget(QLayout *lt, QWidget *before, QWidget *after) + { + bool ok = false; + QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem. + if (QGridLayout *gridLayout = qobject_cast(lt)) { + const int index = gridLayout->indexOf(before); + if (index != -1) { + int row, column, rowSpan, columnSpan; + gridLayout->getItemPosition (index, &row, &column, &rowSpan, &columnSpan); + const bool visible = before->isVisible(); + delete gridLayout->takeAt(index); + if (visible) + before->hide(); + before->setParent(0); + gridLayout->addWidget(after, row, column, rowSpan, columnSpan); + ok = true; + } + } + if (!ok) + qWarning() << "GridLayoutHelper::replaceWidget : Unable to replace " << before << " by " << after << " in " << lt; + } + + void GridLayoutHelper::pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout) + { + QGridLayout *gridLayout = qobject_cast(LayoutInfo::managedLayout(core, widgetWithManagedLayout)); + Q_ASSERT(gridLayout); + GridLayoutState gs; + gs.fromLayout(gridLayout); + m_states.push(gs); + } + + void GridLayoutHelper::popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout) + { + Q_ASSERT(!m_states.empty()); + const GridLayoutState state = m_states.pop(); + state.applyToLayout(core, widgetWithManagedLayout); + } + + bool GridLayoutHelper::canSimplify(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout, const QRect &restrictionArea) const + { + QGridLayout *gridLayout = qobject_cast(LayoutInfo::managedLayout(core, widgetWithManagedLayout)); + Q_ASSERT(gridLayout); + GridLayoutState gs; + gs.fromLayout(gridLayout); + return gs.simplify(restrictionArea, true); + } + + void GridLayoutHelper::simplify(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout, const QRect &restrictionArea) + { + QGridLayout *gridLayout = qobject_cast(LayoutInfo::managedLayout(core, widgetWithManagedLayout)); + Q_ASSERT(gridLayout); + if (debugLayout) + qDebug() << ">GridLayoutHelper::simplify" << *gridLayout; + GridLayoutState gs; + gs.fromLayout(gridLayout); + if (gs.simplify(restrictionArea, false)) + gs.applyToLayout(core, widgetWithManagedLayout); + if (debugLayout) + qDebug() << " WidgetPair; + typedef QVector FormLayoutState; + + FormLayoutHelper() {} + + virtual QRect itemInfo(QLayout *lt, int index) const; + virtual void insertWidget(QLayout *lt, const QRect &info, QWidget *w); + virtual void removeWidget(QLayout *lt, QWidget *widget); + virtual void replaceWidget(QLayout *lt, QWidget *before, QWidget *after); + + virtual void pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout); + virtual void popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout); + + virtual bool canSimplify(const QDesignerFormEditorInterface *core, const QWidget *, const QRect &) const; + virtual void simplify(const QDesignerFormEditorInterface *, QWidget *, const QRect &); + + private: + static FormLayoutState state(const QFormLayout *lt); + + QStack m_states; + }; + + QRect FormLayoutHelper::itemInfo(QLayout * lt, int index) const + { + QFormLayout *form = qobject_cast(lt); + Q_ASSERT(form); + int row, column, colspan; + getFormLayoutItemPosition(form, index, &row, &column, 0, &colspan); + return QRect(column, row, colspan, 1); + } + + void FormLayoutHelper::insertWidget(QLayout *lt, const QRect &info, QWidget *w) + { + if (debugLayout) + qDebug() << "FormLayoutHelper::insertWidget:" << w << info; + QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem. + QFormLayout *formLayout = qobject_cast(lt); + Q_ASSERT(formLayout); + // check if there are any nonspacer items? (Drop on 3rd column or drop of a multiselection + // on an empty item. As the Form layout does not have insert semantics; we need to manually insert a row + const bool insert = !removeEmptyCellsOnGrid(formLayout, info); + formLayoutAddWidget(formLayout, w, info, insert); + QLayoutSupport::createEmptyCells(formLayout); + } + + void FormLayoutHelper::removeWidget(QLayout *lt, QWidget *widget) + { + QFormLayout *formLayout = qobject_cast(lt); + Q_ASSERT(formLayout); + const int index = formLayout->indexOf(widget); + if (index == -1) { + qWarning() << "FormLayoutHelper::removeWidget : Attempt to remove " << widget << " which is not in the layout."; + return; + } + // delete old item and pad with by spacer items + int row, column, colspan; + getFormLayoutItemPosition(formLayout, index, &row, &column, 0, &colspan); + if (debugLayout) + qDebug() << "FormLayoutHelper::removeWidget: #" << index << widget << " at " << row << column << colspan; + delete formLayout->takeAt(index); + if (colspan > 1 || column == 0) + formLayout->setItem(row, QFormLayout::LabelRole, createFormSpacer()); + if (colspan > 1 || column == 1) + formLayout->setItem(row, QFormLayout::FieldRole, createFormSpacer()); + } + + void FormLayoutHelper::replaceWidget(QLayout *lt, QWidget *before, QWidget *after) + { + bool ok = false; + QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem. + if (QFormLayout *formLayout = qobject_cast(lt)) { + const int index = formLayout->indexOf(before); + if (index != -1) { + int row; + QFormLayout::ItemRole role; + formLayout->getItemPosition (index, &row, &role); + const bool visible = before->isVisible(); + delete formLayout->takeAt(index); + if (visible) + before->hide(); + before->setParent(0); + formLayout->setWidget(row, role, after); + ok = true; + } + } + if (!ok) + qWarning() << "FormLayoutHelper::replaceWidget : Unable to replace " << before << " by " << after << " in " << lt; + } + + FormLayoutHelper::FormLayoutState FormLayoutHelper::state(const QFormLayout *lt) + { + const int rowCount = lt->rowCount(); + if (rowCount == 0) + return FormLayoutState(); + FormLayoutState rc(rowCount, WidgetPair(0, 0)); + const int count = lt->count(); + int row, column, colspan; + for (int i = 0; i < count; i++) { + QLayoutItem *item = lt->itemAt(i); + if (!LayoutInfo::isEmptyItem(item)) { + QWidget *w = item->widget(); + Q_ASSERT(w); + getFormLayoutItemPosition(lt, i, &row, &column, 0, &colspan); + if (colspan > 1 || column == 0) + rc[row].first = w; + if (colspan > 1 || column == 1) + rc[row].second = w; + } + } + if (debugLayout) { + qDebug() << "FormLayoutHelper::state: " << rowCount; + for (int r = 0; r < rowCount; r++) + qDebug() << " Row: " << r << rc[r].first << rc[r].second; + } + return rc; + } + + void FormLayoutHelper::pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout) + { + QFormLayout *formLayout = qobject_cast(LayoutInfo::managedLayout(core, widgetWithManagedLayout)); + Q_ASSERT(formLayout); + m_states.push(state(formLayout)); + } + + void FormLayoutHelper::popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout) + { + QFormLayout *formLayout = qobject_cast(LayoutInfo::managedLayout(core, widgetWithManagedLayout)); + Q_ASSERT(!m_states.empty() && formLayout); + + const FormLayoutState storedState = m_states.pop(); + const FormLayoutState currentState = state(formLayout); + if (currentState == storedState) + return; + const int rowCount = storedState.size(); + // clear out, shrink if required, but maintain items via map, pad spacers + const BoxLayoutHelper::LayoutItemVector items = BoxLayoutHelper::disassembleLayout(formLayout); + if (rowCount < formLayout->rowCount()) + formLayout = static_cast(recreateManagedLayout(core, widgetWithManagedLayout, formLayout )); + for (int r = 0; r < rowCount; r++) { + QWidget *widgets[FormLayoutColumns] = { storedState[r].first, storedState[r].second }; + const bool spanning = widgets[0] != 0 && widgets[0] == widgets[1]; + if (spanning) { + formLayout->setWidget(r, QFormLayout::SpanningRole, widgets[0]); + } else { + for (int c = 0; c < FormLayoutColumns; c++) { + const QFormLayout::ItemRole role = c == 0 ? QFormLayout::LabelRole : QFormLayout::FieldRole; + if (widgets[c] && BoxLayoutHelper::findItemOfWidget(items, widgets[c])) { + formLayout->setWidget(r, role, widgets[c]); + } else { + formLayout->setItem(r, role, createFormSpacer()); + } + } + } + } + } + + bool FormLayoutHelper::canSimplify(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout, const QRect &restrictionArea) const + { + const QFormLayout *formLayout = qobject_cast(LayoutInfo::managedLayout(core, widgetWithManagedLayout)); + Q_ASSERT(formLayout); + return canSimplifyFormLayout(formLayout, restrictionArea); + } + + void FormLayoutHelper::simplify(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout, const QRect &restrictionArea) + { + typedef QPair LayoutItemPair; + typedef QVector LayoutItemPairs; + + QFormLayout *formLayout = qobject_cast(LayoutInfo::managedLayout(core, widgetWithManagedLayout)); + Q_ASSERT(formLayout); + if (debugLayout) + qDebug() << "FormLayoutHelper::simplify"; + // Transform into vector of item pairs + const int rowCount = formLayout->rowCount(); + LayoutItemPairs pairs(rowCount, LayoutItemPair(0, 0)); + for (int i = formLayout->count() - 1; i >= 0; i--) { + int row, col,colspan; + getFormLayoutItemPosition(formLayout, i, &row, &col, 0, &colspan); + if (colspan > 1) { + pairs[row].first = pairs[row].second = formLayout->takeAt(i); + } else { + if (col == 0) + pairs[row].first = formLayout->takeAt(i); + else + pairs[row].second = formLayout->takeAt(i); + } + } + // Weed out empty ones + const int bottomCheckRow = qMin(rowCount, restrictionArea.y() + restrictionArea.height()); + for (int r = bottomCheckRow - 1; r >= restrictionArea.y(); r--) + if (LayoutInfo::isEmptyItem(pairs[r].first) && LayoutInfo::isEmptyItem(pairs[r].second)) { + delete pairs[r].first; + delete pairs[r].second; + pairs.remove(r); + } + const int simpleRowCount = pairs.size(); + if (simpleRowCount < rowCount) + formLayout = static_cast(recreateManagedLayout(core, widgetWithManagedLayout, formLayout)); + // repopulate + for (int r = 0; r < simpleRowCount; r++) { + const bool spanning = pairs[r].first == pairs[r].second; + if (spanning) { + formLayout->setItem(r, QFormLayout::SpanningRole, pairs[r].first); + } else { + formLayout->setItem(r, QFormLayout::LabelRole, pairs[r].first); + formLayout->setItem(r, QFormLayout::FieldRole, pairs[r].second); + } + } + } + +LayoutHelper *LayoutHelper::createLayoutHelper(int type) +{ + LayoutHelper *rc = 0; + switch (type) { + case LayoutInfo::HBox: + rc = new BoxLayoutHelper(Qt::Horizontal); + break; + case LayoutInfo::VBox: + rc = new BoxLayoutHelper(Qt::Vertical); + break; + case LayoutInfo::Grid: + rc = new GridLayoutHelper; + break; + case LayoutInfo::Form: + return new FormLayoutHelper; + default: + break; + } + Q_ASSERT(rc); + return rc; +} + +// ---- QLayoutSupport (LayoutDecorationExtension) +QLayoutSupport::QLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, LayoutHelper *helper, QObject *parent) : + QObject(parent), + m_formWindow(formWindow), + m_helper(helper), + m_widget(widget), + m_currentIndex(-1), + m_currentInsertMode(QDesignerLayoutDecorationExtension::InsertWidgetMode) +{ +} + +QLayout * QLayoutSupport::layout() const +{ + return LayoutInfo::managedLayout(m_formWindow->core(), m_widget); +} + +void QLayoutSupport::hideIndicator(Indicator i) +{ + if (m_indicators[i]) + m_indicators[i]->hide(); +} + +void QLayoutSupport::showIndicator(Indicator i, const QRect &geometry, const QPalette &p) +{ + if (!m_indicators[i]) + m_indicators[i] = new qdesigner_internal::InvisibleWidget(m_widget); + QWidget *indicator = m_indicators[i]; + indicator->setAutoFillBackground(true); + indicator->setPalette(p); + indicator->setGeometry(geometry); + indicator->show(); + indicator->raise(); +} + +QLayoutSupport::~QLayoutSupport() +{ + delete m_helper; + for (int i = 0; i < NumIndicators; i++) + if (m_indicators[i]) + m_indicators[i]->deleteLater(); +} + +QGridLayout * QLayoutSupport::gridLayout() const +{ + return qobject_cast(LayoutInfo::managedLayout(m_formWindow->core(), m_widget)); +} + +QRect QLayoutSupport::itemInfo(int index) const +{ + return m_helper->itemInfo(LayoutInfo::managedLayout(m_formWindow->core(), m_widget), index); +} + +void QLayoutSupport::setInsertMode(InsertMode im) +{ + m_currentInsertMode = im; +} + +void QLayoutSupport::setCurrentCell(const QPair &cell) +{ + m_currentCell = cell; +} + +void QLayoutSupport::adjustIndicator(const QPoint &pos, int index) +{ + if (index == -1) { // first item goes anywhere + hideIndicator(LeftIndicator); + hideIndicator(TopIndicator); + hideIndicator(RightIndicator); + hideIndicator(BottomIndicator); + return; + } + m_currentIndex = index; + m_currentInsertMode = QDesignerLayoutDecorationExtension::InsertWidgetMode; + + QLayoutItem *item = layout()->itemAt(index); + const QRect g = extendedGeometry(index); + // ### cleanup + if (LayoutInfo::isEmptyItem(item)) { + // Empty grid/form cell. Draw a rectangle + QPalette redPalette; + redPalette.setColor(QPalette::Window, Qt::red); + + showIndicator(LeftIndicator, QRect(g.x(), g.y(), indicatorSize, g.height()), redPalette); + showIndicator(TopIndicator, QRect(g.x(), g.y(), g.width(), indicatorSize), redPalette); + showIndicator(RightIndicator, QRect(g.right(), g.y(), indicatorSize, g.height()), redPalette); + showIndicator(BottomIndicator, QRect(g.x(), g.bottom(), g.width(), indicatorSize), redPalette); + setCurrentCellFromIndicatorOnEmptyCell(m_currentIndex); + } else { + // Append/Insert. Draw a bar left/right or above/below + QPalette bluePalette; + bluePalette.setColor(QPalette::Window, Qt::blue); + hideIndicator(LeftIndicator); + hideIndicator(TopIndicator); + + const int fromRight = g.right() - pos.x(); + const int fromBottom = g.bottom() - pos.y(); + + const int fromLeft = pos.x() - g.x(); + const int fromTop = pos.y() - g.y(); + + const int fromLeftRight = qMin(fromRight, fromLeft ); + const int fromBottomTop = qMin(fromBottom, fromTop); + + const Qt::Orientation indicatorOrientation = fromLeftRight < fromBottomTop ? Qt::Vertical : Qt::Horizontal; + + if (supportsIndicatorOrientation(indicatorOrientation)) { + const QRect r(layout()->geometry().topLeft(), layout()->parentWidget()->size()); + switch (indicatorOrientation) { + case Qt::Vertical: { + hideIndicator(BottomIndicator); + const bool closeToLeft = fromLeftRight == fromLeft; + showIndicator(RightIndicator, QRect(closeToLeft ? g.x() : g.right() + 1 - indicatorSize, 0, indicatorSize, r.height()), bluePalette); + + const int incr = closeToLeft ? 0 : +1; + setCurrentCellFromIndicator(indicatorOrientation, m_currentIndex, incr); + } + break; + case Qt::Horizontal: { + hideIndicator(RightIndicator); + const bool closeToTop = fromBottomTop == fromTop; + showIndicator(BottomIndicator, QRect(r.x(), closeToTop ? g.y() : g.bottom() + 1 - indicatorSize, r.width(), indicatorSize), bluePalette); + + const int incr = closeToTop ? 0 : +1; + setCurrentCellFromIndicator(indicatorOrientation, m_currentIndex, incr); + } + break; + } + } else { + hideIndicator(RightIndicator); + hideIndicator(BottomIndicator); + } // can handle indicatorOrientation + } +} + +int QLayoutSupport::indexOf(QLayoutItem *i) const +{ + const QLayout *lt = layout(); + if (!lt) + return -1; + + int index = 0; + + while (QLayoutItem *item = lt->itemAt(index)) { + if (item == i) + return index; + + ++index; + } + + return -1; +} + +int QLayoutSupport::indexOf(QWidget *widget) const +{ + const QLayout *lt = layout(); + if (!lt) + return -1; + + int index = 0; + while (QLayoutItem *item = lt->itemAt(index)) { + if (item->widget() == widget) + return index; + + ++index; + } + + return -1; +} + +QList QLayoutSupport::widgets(QLayout *layout) const +{ + if (!layout) + return QList(); + + QList lst; + int index = 0; + while (QLayoutItem *item = layout->itemAt(index)) { + ++index; + + QWidget *widget = item->widget(); + if (widget && formWindow()->isManaged(widget)) + lst.append(widget); + } + + return lst; +} + +int QLayoutSupport::findItemAt(QGridLayout *gridLayout, int at_row, int at_column) +{ + return findGridItemAt(gridLayout, at_row, at_column); +} + +// Quick check whether simplify should be enabled for grids. May return false positives. +// Note: Calculating the occupied area does not work as spanning items may also be simplified. + +bool QLayoutSupport::canSimplifyQuickCheck(const QGridLayout *gl) +{ + if (!gl) + return false; + const int colCount = gl->columnCount(); + const int rowCount = gl->rowCount(); + if (colCount < 2 || rowCount < 2) + return false; + // try to find a spacer. + const int count = gl->count(); + for (int index = 0; index < count; index++) + if (LayoutInfo::isEmptyItem(gl->itemAt(index))) + return true; + return false; +} + +bool QLayoutSupport::canSimplifyQuickCheck(const QFormLayout *fl) +{ + return canSimplifyFormLayout(fl, QRect(QPoint(0, 0), QSize(32767, 32767))); +} + +// remove dummy spacers +bool QLayoutSupport::removeEmptyCells(QGridLayout *grid, const QRect &area) +{ + return removeEmptyCellsOnGrid(grid, area); +} + +void QLayoutSupport::createEmptyCells(QGridLayout *gridLayout) +{ + Q_ASSERT(gridLayout); + GridLayoutState gs; + gs.fromLayout(gridLayout); + + const GridLayoutState::CellStates cs = GridLayoutState::cellStates(gs.widgetItemMap.values(), gs.rowCount, gs.colCount); + for (int c = 0; c < gs.colCount; c++) + for (int r = 0; r < gs.rowCount; r++) + if (needsSpacerItem(cs[r * gs.colCount + c])) { + const int existingItemIndex = findItemAt(gridLayout, r, c); + if (existingItemIndex == -1) + gridLayout->addItem(createGridSpacer(), r, c); + } +} + +bool QLayoutSupport::removeEmptyCells(QFormLayout *formLayout, const QRect &area) +{ + return removeEmptyCellsOnGrid(formLayout, area); +} + +void QLayoutSupport::createEmptyCells(QFormLayout *formLayout) +{ + // No spanning items here.. + if (const int rowCount = formLayout->rowCount()) + for (int c = 0; c < FormLayoutColumns; c++) + for (int r = 0; r < rowCount; r++) + if (findGridItemAt(formLayout, r, c) == -1) + formLayout->setItem(r, c == 0 ? QFormLayout::LabelRole : QFormLayout::FieldRole, createFormSpacer()); +} + +int QLayoutSupport::findItemAt(const QPoint &pos) const +{ + if (!layout()) + return -1; + + const QLayout *lt = layout(); + const int count = lt->count(); + + if (count == 0) + return -1; + + int best = -1; + int bestIndex = -1; + + for (int index = 0; index < count; index++) { + QLayoutItem *item = lt->itemAt(index); + bool visible = true; + // When dragging widgets within layout, the source widget is invisible and must not be hit + if (const QWidget *w = item->widget()) + visible = w->isVisible(); + if (visible) { + const QRect g = item->geometry(); + + const int dist = (g.center() - pos).manhattanLength(); + if (best == -1 || dist < best) { + best = dist; + bestIndex = index; + } + } + } + return bestIndex; +} + +// ------------ QBoxLayoutSupport (LayoutDecorationExtension) +namespace { +class QBoxLayoutSupport: public QLayoutSupport +{ +public: + QBoxLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, Qt::Orientation orientation, QObject *parent = 0); + + virtual void insertWidget(QWidget *widget, const QPair &cell); + virtual void removeWidget(QWidget *widget); + virtual void simplify() {} + virtual void insertRow(int /*row*/) {} + virtual void insertColumn(int /*column*/) {} + + virtual int findItemAt(int /*at_row*/, int /*at_column*/) const { return -1; } + +private: + virtual void setCurrentCellFromIndicatorOnEmptyCell(int index); + virtual void setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment); + virtual bool supportsIndicatorOrientation(Qt::Orientation indicatorOrientation) const; + virtual QRect extendedGeometry(int index) const; + + const Qt::Orientation m_orientation; +}; + +void QBoxLayoutSupport::removeWidget(QWidget *widget) +{ + QLayout *lt = layout(); + const int index = lt->indexOf(widget); + // Adjust the current cell in case a widget was dragged within the same layout to a position + // of higher index, which happens as follows: + // Drag start: The widget is hidden + // Drop: Current cell is stored, widget is removed and re-added, causing an index offset that needs to be compensated + QPair currCell = currentCell(); + switch (m_orientation) { + case Qt::Horizontal: + if (currCell.second > 0 && index < currCell.second ) { + currCell.second--; + setCurrentCell(currCell); + } + break; + case Qt::Vertical: + if (currCell.first > 0 && index < currCell.first) { + currCell.first--; + setCurrentCell(currCell); + } + break; + } + helper()->removeWidget(lt, widget); +} + +QBoxLayoutSupport::QBoxLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, Qt::Orientation orientation, QObject *parent) : + QLayoutSupport(formWindow, widget, new BoxLayoutHelper(orientation), parent), + m_orientation(orientation) +{ +} + +void QBoxLayoutSupport::setCurrentCellFromIndicatorOnEmptyCell(int index) +{ + qDebug() << "QBoxLayoutSupport::setCurrentCellFromIndicatorOnEmptyCell(): Warning: found a fake spacer inside a vbox layout at " << index; + setCurrentCell(qMakePair(0, 0)); +} + +void QBoxLayoutSupport::insertWidget(QWidget *widget, const QPair &cell) +{ + switch (m_orientation) { + case Qt::Horizontal: + helper()->insertWidget(layout(), QRect(cell.second, 0, 1, 1), widget); + break; + case Qt::Vertical: + helper()->insertWidget(layout(), QRect(0, cell.first, 1, 1), widget); + break; + } +} + +void QBoxLayoutSupport::setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment) +{ + if (m_orientation == Qt::Horizontal && indicatorOrientation == Qt::Vertical) { + setCurrentCell(qMakePair(0, index + increment)); + } else if (m_orientation == Qt::Vertical && indicatorOrientation == Qt::Horizontal) { + setCurrentCell(qMakePair(index + increment, 0)); + } +} + +bool QBoxLayoutSupport::supportsIndicatorOrientation(Qt::Orientation indicatorOrientation) const +{ + return m_orientation != indicatorOrientation; +} + +QRect QBoxLayoutSupport::extendedGeometry(int index) const +{ + QLayoutItem *item = layout()->itemAt(index); + // start off with item geometry + QRect g = item->geometry(); + + const QRect info = itemInfo(index); + + // On left border: extend to widget border + if (info.x() == 0) { + QPoint topLeft = g.topLeft(); + topLeft.rx() = layout()->geometry().left(); + g.setTopLeft(topLeft); + } + + // On top border: extend to widget border + if (info.y() == 0) { + QPoint topLeft = g.topLeft(); + topLeft.ry() = layout()->geometry().top(); + g.setTopLeft(topLeft); + } + + // is this the last item? + const QBoxLayout *box = static_cast(layout()); + if (index < box->count() -1) + return g; // Nope. + + // extend to widget border + QPoint bottomRight = g.bottomRight(); + switch (m_orientation) { + case Qt::Vertical: + bottomRight.ry() = layout()->geometry().bottom(); + break; + case Qt::Horizontal: + bottomRight.rx() = layout()->geometry().right(); + break; + } + g.setBottomRight(bottomRight); + return g; +} + +// -------------- Base class for QGridLayout-like support classes (LayoutDecorationExtension) +template +class GridLikeLayoutSupportBase: public QLayoutSupport +{ +public: + + GridLikeLayoutSupportBase(QDesignerFormWindowInterface *formWindow, QWidget *widget, LayoutHelper *helper, QObject *parent = 0) : + QLayoutSupport(formWindow, widget, helper, parent) {} + + void insertWidget(QWidget *widget, const QPair &cell); + virtual void removeWidget(QWidget *widget) { helper()->removeWidget(layout(), widget); } + virtual int findItemAt(int row, int column) const; + +protected: + GridLikeLayout *gridLikeLayout() const { + return qobject_cast(LayoutInfo::managedLayout(formWindow()->core(), widget())); + } + +private: + + virtual void setCurrentCellFromIndicatorOnEmptyCell(int index); + virtual void setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment); + virtual bool supportsIndicatorOrientation(Qt::Orientation) const { return true; } + + virtual QRect extendedGeometry(int index) const; + + // Overwrite to check the insertion position (if there are limits) + virtual void checkCellForInsertion(int * /*row*/, int * /*col*/) const {} +}; + +template +void GridLikeLayoutSupportBase::setCurrentCellFromIndicatorOnEmptyCell(int index) +{ + GridLikeLayout *grid = gridLikeLayout(); + Q_ASSERT(grid); + + setInsertMode(InsertWidgetMode); + int row, column, rowspan, colspan; + + getGridItemPosition(grid, index, &row, &column, &rowspan, &colspan); + setCurrentCell(qMakePair(row, column)); +} + +template +void GridLikeLayoutSupportBase::setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment) { + const QRect info = itemInfo(index); + switch (indicatorOrientation) { + case Qt::Vertical: { + setInsertMode(InsertColumnMode); + int row = info.top(); + int column = increment ? info.right() + 1 : info.left(); + checkCellForInsertion(&row, &column); + setCurrentCell(qMakePair(row , column)); + } + break; + case Qt::Horizontal: { + setInsertMode(InsertRowMode); + int row = increment ? info.bottom() + 1 : info.top(); + int column = info.left(); + checkCellForInsertion(&row, &column); + setCurrentCell(qMakePair(row, column)); + } + break; + } +} + +template +void GridLikeLayoutSupportBase::insertWidget(QWidget *widget, const QPair &cell) +{ + helper()->insertWidget(layout(), QRect(cell.second, cell.first, 1, 1), widget); +} + +template +int GridLikeLayoutSupportBase::findItemAt(int at_row, int at_column) const +{ + GridLikeLayout *grid = gridLikeLayout(); + Q_ASSERT(grid); + return findGridItemAt(grid, at_row, at_column); +} + +template +QRect GridLikeLayoutSupportBase::extendedGeometry(int index) const +{ + QLayoutItem *item = layout()->itemAt(index); + // start off with item geometry + QRect g = item->geometry(); + + const QRect info = itemInfo(index); + + // On left border: extend to widget border + if (info.x() == 0) { + QPoint topLeft = g.topLeft(); + topLeft.rx() = layout()->geometry().left(); + g.setTopLeft(topLeft); + } + + // On top border: extend to widget border + if (info.y() == 0) { + QPoint topLeft = g.topLeft(); + topLeft.ry() = layout()->geometry().top(); + g.setTopLeft(topLeft); + } + const GridLikeLayout *grid = gridLikeLayout(); + Q_ASSERT(grid); + + // extend to widget border + QPoint bottomRight = g.bottomRight(); + if (gridRowCount(grid) == info.y()) + bottomRight.ry() = layout()->geometry().bottom(); + if (gridColumnCount(grid) == info.x()) + bottomRight.rx() = layout()->geometry().right(); + g.setBottomRight(bottomRight); + return g; +} + +// -------------- QGridLayoutSupport (LayoutDecorationExtension) +class QGridLayoutSupport: public GridLikeLayoutSupportBase +{ +public: + + QGridLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent = 0); + + virtual void simplify(); + virtual void insertRow(int row); + virtual void insertColumn(int column); + +private: +}; + +QGridLayoutSupport::QGridLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent) : + GridLikeLayoutSupportBase(formWindow, widget, new GridLayoutHelper, parent) +{ +} + +void QGridLayoutSupport::insertRow(int row) +{ + QGridLayout *grid = gridLayout(); + Q_ASSERT(grid); + GridLayoutHelper::insertRow(grid, row); +} + +void QGridLayoutSupport::insertColumn(int column) +{ + QGridLayout *grid = gridLayout(); + Q_ASSERT(grid); + GridLayoutState state; + state.fromLayout(grid); + state.insertColumn(column); + state.applyToLayout(formWindow()->core(), widget()); +} + +void QGridLayoutSupport::simplify() +{ + QGridLayout *grid = gridLayout(); + Q_ASSERT(grid); + GridLayoutState state; + state.fromLayout(grid); + + const QRect fullArea = QRect(0, 0, state.colCount, state.rowCount); + if (state.simplify(fullArea, false)) + state.applyToLayout(formWindow()->core(), widget()); +} + +// -------------- QFormLayoutSupport (LayoutDecorationExtension) +class QFormLayoutSupport: public GridLikeLayoutSupportBase +{ +public: + QFormLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent = 0); + + virtual void simplify() {} + virtual void insertRow(int /*row*/) {} + virtual void insertColumn(int /*column*/) {} + +private: + virtual void checkCellForInsertion(int * row, int *col) const; +}; + +QFormLayoutSupport::QFormLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent) : + GridLikeLayoutSupportBase(formWindow, widget, new FormLayoutHelper, parent) +{ +} + +void QFormLayoutSupport::checkCellForInsertion(int *row, int *col) const +{ + if (*col >= FormLayoutColumns) { // Clamp to 2 columns + *col = 1; + (*row)++; + } +} +} // anonymous namespace + +QLayoutSupport *QLayoutSupport::createLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent) +{ + const QLayout *layout = LayoutInfo::managedLayout(formWindow->core(), widget); + Q_ASSERT(layout); + QLayoutSupport *rc = 0; + switch (LayoutInfo::layoutType(formWindow->core(), layout)) { + case LayoutInfo::HBox: + rc = new QBoxLayoutSupport(formWindow, widget, Qt::Horizontal, parent); + break; + case LayoutInfo::VBox: + rc = new QBoxLayoutSupport(formWindow, widget, Qt::Vertical, parent); + break; + case LayoutInfo::Grid: + rc = new QGridLayoutSupport(formWindow, widget, parent); + break; + case LayoutInfo::Form: + rc = new QFormLayoutSupport(formWindow, widget, parent); + break; + default: + break; + } + Q_ASSERT(rc); + return rc; +} +} // namespace qdesigner_internal + +// -------------- QLayoutWidget +QLayoutWidget::QLayoutWidget(QDesignerFormWindowInterface *formWindow, QWidget *parent) + : QWidget(parent), m_formWindow(formWindow), + m_leftMargin(0), m_topMargin(0), m_rightMargin(0), m_bottomMargin(0) +{ +} + +void QLayoutWidget::paintEvent(QPaintEvent*) +{ + if (m_formWindow->currentTool() != 0) + return; + + // only draw red borders if we're editting widgets + + QPainter p(this); + + QMap > excludedRowsForColumn; + QMap > excludedColumnsForRow; + + QLayout *lt = layout(); + QGridLayout *grid = qobject_cast(lt); + if (lt) { + if (const int count = lt->count()) { + p.setPen(QPen(QColor(255, 0, 0, 35), 1)); + for (int i = 0; i < count; i++) { + QLayoutItem *item = lt->itemAt(i); + if (grid) { + int row, column, rowSpan, columnSpan; + grid->getItemPosition(i, &row, &column, &rowSpan, &columnSpan); + QMap rows; + QMap columns; + for (int i = rowSpan; i > 1; i--) + rows[row + i - 2] = true; + for (int i = columnSpan; i > 1; i--) + columns[column + i - 2] = true; + + while (rowSpan > 0) { + excludedColumnsForRow[row + rowSpan - 1].unite(columns); + rowSpan--; + } + while (columnSpan > 0) { + excludedRowsForColumn[column + columnSpan - 1].unite(rows); + columnSpan--; + } + } + if (item->spacerItem()) { + const QRect geometry = item->geometry(); + if (!geometry.isNull()) + p.drawRect(geometry.adjusted(1, 1, -2, -2)); + } + } + } + } + if (grid) { + p.setPen(QPen(QColor(0, 0x80, 0, 0x80), 1)); + const int rowCount = grid->rowCount(); + const int columnCount = grid->columnCount(); + for (int i = 0; i < rowCount; i++) { + for (int j = 0; j < columnCount; j++) { + const QRect cellRect = grid->cellRect(i, j); + if (j < columnCount - 1 && excludedColumnsForRow.value(i).value(j, false) == false) { + const double y0 = (i == 0) + ? 0 : (grid->cellRect(i - 1, j).bottom() + cellRect.top()) / 2.0; + const double y1 = (i == rowCount - 1) + ? height() - 1 : (cellRect.bottom() + grid->cellRect(i + 1, j).top()) / 2.0; + const double x = (cellRect.right() + grid->cellRect(i, j + 1).left()) / 2.0; + p.drawLine(QPointF(x, y0), QPointF(x, y1)); + } + if (i < rowCount - 1 && excludedRowsForColumn.value(j).value(i, false) == false) { + const double x0 = (j == 0) + ? 0 : (grid->cellRect(i, j - 1).right() + cellRect.left()) / 2.0; + const double x1 = (j == columnCount - 1) + ? width() - 1 : (cellRect.right() + grid->cellRect(i, j + 1).left()) / 2.0; + const double y = (cellRect.bottom() + grid->cellRect(i + 1, j).top()) / 2.0; + p.drawLine(QPointF(x0, y), QPointF(x1, y)); + } + } + } + } + p.setPen(QPen(QColor(255, 0, 0, 128), 1)); + p.drawRect(0, 0, width() - 1, height() - 1); +} + +bool QLayoutWidget::event(QEvent *e) +{ + switch (e->type()) { + case QEvent::LayoutRequest: { + (void) QWidget::event(e); + // Magic: We are layouted, but the parent is not.. + if (layout() && qdesigner_internal::LayoutInfo::layoutType(formWindow()->core(), parentWidget()) == qdesigner_internal::LayoutInfo::NoLayout) { + resize(layout()->totalMinimumSize().expandedTo(size())); + } + + update(); + + return true; + } + + default: + break; + } + + return QWidget::event(e); +} + +int QLayoutWidget::layoutLeftMargin() const +{ + if (m_leftMargin < 0 && layout()) { + int margin; + layout()->getContentsMargins(&margin, 0, 0, 0); + return margin; + } + return m_leftMargin; +} + +void QLayoutWidget::setLayoutLeftMargin(int layoutMargin) +{ + m_leftMargin = layoutMargin; + if (layout()) { + int newMargin = m_leftMargin; + if (newMargin >= 0 && newMargin < ShiftValue) + newMargin = ShiftValue; + int left, top, right, bottom; + layout()->getContentsMargins(&left, &top, &right, &bottom); + layout()->setContentsMargins(newMargin, top, right, bottom); + } +} + +int QLayoutWidget::layoutTopMargin() const +{ + if (m_topMargin < 0 && layout()) { + int margin; + layout()->getContentsMargins(0, &margin, 0, 0); + return margin; + } + return m_topMargin; +} + +void QLayoutWidget::setLayoutTopMargin(int layoutMargin) +{ + m_topMargin = layoutMargin; + if (layout()) { + int newMargin = m_topMargin; + if (newMargin >= 0 && newMargin < ShiftValue) + newMargin = ShiftValue; + int left, top, right, bottom; + layout()->getContentsMargins(&left, &top, &right, &bottom); + layout()->setContentsMargins(left, newMargin, right, bottom); + } +} + +int QLayoutWidget::layoutRightMargin() const +{ + if (m_rightMargin < 0 && layout()) { + int margin; + layout()->getContentsMargins(0, 0, &margin, 0); + return margin; + } + return m_rightMargin; +} + +void QLayoutWidget::setLayoutRightMargin(int layoutMargin) +{ + m_rightMargin = layoutMargin; + if (layout()) { + int newMargin = m_rightMargin; + if (newMargin >= 0 && newMargin < ShiftValue) + newMargin = ShiftValue; + int left, top, right, bottom; + layout()->getContentsMargins(&left, &top, &right, &bottom); + layout()->setContentsMargins(left, top, newMargin, bottom); + } +} + +int QLayoutWidget::layoutBottomMargin() const +{ + if (m_bottomMargin < 0 && layout()) { + int margin; + layout()->getContentsMargins(0, 0, 0, &margin); + return margin; + } + return m_bottomMargin; +} + +void QLayoutWidget::setLayoutBottomMargin(int layoutMargin) +{ + m_bottomMargin = layoutMargin; + if (layout()) { + int newMargin = m_bottomMargin; + if (newMargin >= 0 && newMargin < ShiftValue) + newMargin = ShiftValue; + int left, top, right, bottom; + layout()->getContentsMargins(&left, &top, &right, &bottom); + layout()->setContentsMargins(left, top, right, newMargin); + } +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qlayout_widget_p.h b/src/designer/src/lib/shared/qlayout_widget_p.h new file mode 100644 index 000000000..a87679e75 --- /dev/null +++ b/src/designer/src/lib/shared/qlayout_widget_p.h @@ -0,0 +1,292 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QLAYOUT_WIDGET_H +#define QLAYOUT_WIDGET_H + +#include "shared_global_p.h" + +#include + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QDesignerFormWindowInterface; +class QDesignerFormEditorInterface; +class QGridLayout; +class QFormLayout; + +namespace qdesigner_internal { +// ---- LayoutProperties: Helper struct that stores all layout-relevant properties +// with functions to retrieve and apply to property sheets. Can be used to store the state +// for undo commands and while rebuilding layouts. +struct QDESIGNER_SHARED_EXPORT LayoutProperties +{ + LayoutProperties(); + void clear(); + + enum Margins { LeftMargin, TopMargin, RightMargin, BottomMargin, MarginCount }; + enum Spacings { Spacing, HorizSpacing, VertSpacing, SpacingsCount }; + + enum PropertyMask { + ObjectNameProperty = 0x1, + LeftMarginProperty = 0x2, TopMarginProperty = 0x4, RightMarginProperty = 0x8, BottomMarginProperty = 0x10, + SpacingProperty = 0x20, HorizSpacingProperty = 0x40, VertSpacingProperty = 0x80, + SizeConstraintProperty = 0x100, + FieldGrowthPolicyProperty = 0x200, RowWrapPolicyProperty = 0x400, LabelAlignmentProperty = 0x0800, FormAlignmentProperty = 0x1000, + BoxStretchProperty = 0x2000, GridRowStretchProperty = 0x4000, GridColumnStretchProperty = 0x8000, + GridRowMinimumHeightProperty = 0x10000, GridColumnMinimumWidthProperty = 0x20000, + AllProperties = 0xFFFF}; + + // return a PropertyMask of visible properties + static int visibleProperties(const QLayout *layout); + + // Retrieve from /apply to sheet: A property mask is returned indicating the properties found in the sheet + int fromPropertySheet(const QDesignerFormEditorInterface *core, QLayout *l, int mask = AllProperties); + int toPropertySheet(const QDesignerFormEditorInterface *core, QLayout *l, int mask = AllProperties, bool applyChanged = true) const; + + int m_margins[MarginCount]; + bool m_marginsChanged[MarginCount]; + + int m_spacings[SpacingsCount]; + bool m_spacingsChanged[SpacingsCount]; + + QVariant m_objectName; // receives a PropertySheetStringValue + bool m_objectNameChanged; + QVariant m_sizeConstraint; + bool m_sizeConstraintChanged; + + bool m_fieldGrowthPolicyChanged; + QVariant m_fieldGrowthPolicy; + bool m_rowWrapPolicyChanged; + QVariant m_rowWrapPolicy; + bool m_labelAlignmentChanged; + QVariant m_labelAlignment; + bool m_formAlignmentChanged; + QVariant m_formAlignment; + + bool m_boxStretchChanged; + QVariant m_boxStretch; + + bool m_gridRowStretchChanged; + QVariant m_gridRowStretch; + + bool m_gridColumnStretchChanged; + QVariant m_gridColumnStretch; + + bool m_gridRowMinimumHeightChanged; + QVariant m_gridRowMinimumHeight; + + bool m_gridColumnMinimumWidthChanged; + QVariant m_gridColumnMinimumWidth; +}; + +// -- LayoutHelper: For use with the 'insert widget'/'delete widget' command, +// able to store and restore states. +// This could become part of 'QDesignerLayoutDecorationExtensionV2', +// but to keep any existing old extensions working, it is provided as +// separate class with a factory function. +class LayoutHelper { +protected: + LayoutHelper(); + +public: + virtual ~LayoutHelper(); + + static LayoutHelper *createLayoutHelper(int type); + + static int indexOf(const QLayout *lt, const QWidget *widget); + + // Return area of an item (x == columns) + QRect itemInfo(QLayout *lt, const QWidget *widget) const; + + virtual QRect itemInfo(QLayout *lt, int index) const = 0; + virtual void insertWidget(QLayout *lt, const QRect &info, QWidget *w) = 0; + virtual void removeWidget(QLayout *lt, QWidget *widget) = 0; + // Since 4.5: The 'morphing' feature requires an API for replacing widgets on layouts. + virtual void replaceWidget(QLayout *lt, QWidget *before, QWidget *after) = 0; + + // Simplify a grid, remove empty columns, rows within the rectangle + // The DeleteWidget command restricts the area to be simplified. + virtual bool canSimplify(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout, const QRect &restrictionArea) const = 0; + virtual void simplify(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout, const QRect &restrictionArea) = 0; + + // Push and pop a state. Can be used for implementing undo for + // simplify/row, column insertion commands, provided that + // the widgets remain the same. + virtual void pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout) = 0; + virtual void popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout) = 0; +}; + +// Base class for layout decoration extensions. +class QDESIGNER_SHARED_EXPORT QLayoutSupport: public QObject, public QDesignerLayoutDecorationExtension +{ + Q_OBJECT + Q_INTERFACES(QDesignerLayoutDecorationExtension) + +protected: + QLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, LayoutHelper *helper, QObject *parent = 0); + +public: + virtual ~QLayoutSupport(); + + inline QDesignerFormWindowInterface *formWindow() const { return m_formWindow; } + + // DecorationExtension V2 + LayoutHelper* helper() const { return m_helper; } + + // DecorationExtension + virtual int currentIndex() const { return m_currentIndex; } + + virtual InsertMode currentInsertMode() const { return m_currentInsertMode; } + + virtual QPair currentCell() const { return m_currentCell; } + + virtual int findItemAt(const QPoint &pos) const; + virtual int indexOf(QWidget *widget) const; + virtual int indexOf(QLayoutItem *item) const; + + virtual void adjustIndicator(const QPoint &pos, int index); + + virtual QList widgets(QLayout *layout) const; + + // Pad empty cells with dummy spacers. Called by layouting commands. + static void createEmptyCells(QGridLayout *gridLayout); + // remove dummy spacers in the area. Returns false if there are non-empty items in the way + static bool removeEmptyCells(QGridLayout *gridLayout, const QRect &area); + static void createEmptyCells(QFormLayout *formLayout); // ditto. + static bool removeEmptyCells(QFormLayout *formLayout, const QRect &area); + + // grid helpers: find item index + static int findItemAt(QGridLayout *, int row, int column); + // grid helpers: Quick check whether simplify should be enabled for grids. May return false positives. + static bool canSimplifyQuickCheck(const QGridLayout *); + static bool canSimplifyQuickCheck(const QFormLayout *fl); + // Factory function, create layout support according to layout type of widget + static QLayoutSupport *createLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent = 0); + +protected: + // figure out insertion position and mode from indicator on empty cell if supported + virtual void setCurrentCellFromIndicatorOnEmptyCell(int index) = 0; + // figure out insertion position and mode from indicator + virtual void setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment) = 0; + + // Overwrite to return the extended geometry of an item, that is, + // if it is a border item, include the widget border for the indicator to work correctly + virtual QRect extendedGeometry(int index) const = 0; + virtual bool supportsIndicatorOrientation(Qt::Orientation indicatorOrientation) const = 0; + + QRect itemInfo(int index) const; + QLayout *layout() const; + QGridLayout *gridLayout() const; + QWidget *widget() const { return m_widget; } + + void setInsertMode(InsertMode im); + void setCurrentCell(const QPair &cell); + +private: + enum Indicator { LeftIndicator, TopIndicator, RightIndicator, BottomIndicator, NumIndicators }; + + void hideIndicator(Indicator i); + void showIndicator(Indicator i, const QRect &geometry, const QPalette &); + + QDesignerFormWindowInterface *m_formWindow; + LayoutHelper* m_helper; + + QPointer m_widget; + QPointer m_indicators[NumIndicators]; + int m_currentIndex; + InsertMode m_currentInsertMode; + QPair m_currentCell; +}; +} // namespace qdesigner_internal + +// Red layout widget. +class QDESIGNER_SHARED_EXPORT QLayoutWidget: public QWidget +{ + Q_OBJECT +public: + explicit QLayoutWidget(QDesignerFormWindowInterface *formWindow, QWidget *parent = 0); + + int layoutLeftMargin() const; + void setLayoutLeftMargin(int layoutMargin); + + int layoutTopMargin() const; + void setLayoutTopMargin(int layoutMargin); + + int layoutRightMargin() const; + void setLayoutRightMargin(int layoutMargin); + + int layoutBottomMargin() const; + void setLayoutBottomMargin(int layoutMargin); + + inline QDesignerFormWindowInterface *formWindow() const { return m_formWindow; } + +protected: + virtual bool event(QEvent *e); + virtual void paintEvent(QPaintEvent *e); + +private: + QDesignerFormWindowInterface *m_formWindow; + int m_leftMargin; + int m_topMargin; + int m_rightMargin; + int m_bottomMargin; +}; + +QT_END_NAMESPACE + +#endif // QDESIGNER_WIDGET_H diff --git a/src/designer/src/lib/shared/qscripthighlighter.cpp b/src/designer/src/lib/shared/qscripthighlighter.cpp new file mode 100644 index 000000000..67555f39e --- /dev/null +++ b/src/designer/src/lib/shared/qscripthighlighter.cpp @@ -0,0 +1,468 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qscripthighlighter_p.h" + +#include + +QT_BEGIN_NAMESPACE + +static const QSet &qscriptKeywords() { + static QSet keywords; + if (keywords.empty()) { + keywords.insert(QLatin1String("Infinity")); + keywords.insert(QLatin1String("NaN")); + keywords.insert(QLatin1String("abstract")); + keywords.insert(QLatin1String("boolean")); + keywords.insert(QLatin1String("break")); + keywords.insert(QLatin1String("byte")); + keywords.insert(QLatin1String("case")); + keywords.insert(QLatin1String("catch")); + keywords.insert(QLatin1String("char")); + keywords.insert(QLatin1String("class")); + keywords.insert(QLatin1String("const")); + keywords.insert(QLatin1String("constructor")); + keywords.insert(QLatin1String("continue")); + keywords.insert(QLatin1String("debugger")); + keywords.insert(QLatin1String("default")); + keywords.insert(QLatin1String("delete")); + keywords.insert(QLatin1String("do")); + keywords.insert(QLatin1String("double")); + keywords.insert(QLatin1String("else")); + keywords.insert(QLatin1String("enum")); + keywords.insert(QLatin1String("export")); + keywords.insert(QLatin1String("extends")); + keywords.insert(QLatin1String("false")); + keywords.insert(QLatin1String("final")); + keywords.insert(QLatin1String("finally")); + keywords.insert(QLatin1String("float")); + keywords.insert(QLatin1String("for")); + keywords.insert(QLatin1String("function")); + keywords.insert(QLatin1String("goto")); + keywords.insert(QLatin1String("if")); + keywords.insert(QLatin1String("implements")); + keywords.insert(QLatin1String("import")); + keywords.insert(QLatin1String("in")); + keywords.insert(QLatin1String("instanceof")); + keywords.insert(QLatin1String("int")); + keywords.insert(QLatin1String("interface")); + keywords.insert(QLatin1String("long")); + keywords.insert(QLatin1String("native")); + keywords.insert(QLatin1String("new")); + keywords.insert(QLatin1String("package")); + keywords.insert(QLatin1String("private")); + keywords.insert(QLatin1String("protected")); + keywords.insert(QLatin1String("public")); + keywords.insert(QLatin1String("return")); + keywords.insert(QLatin1String("short")); + keywords.insert(QLatin1String("static")); + keywords.insert(QLatin1String("super")); + keywords.insert(QLatin1String("switch")); + keywords.insert(QLatin1String("synchronized")); + keywords.insert(QLatin1String("this")); + keywords.insert(QLatin1String("throw")); + keywords.insert(QLatin1String("throws")); + keywords.insert(QLatin1String("transient")); + keywords.insert(QLatin1String("true")); + keywords.insert(QLatin1String("try")); + keywords.insert(QLatin1String("typeof")); + keywords.insert(QLatin1String("undefined")); + keywords.insert(QLatin1String("var")); + keywords.insert(QLatin1String("void")); + keywords.insert(QLatin1String("volatile")); + keywords.insert(QLatin1String("while")); + keywords.insert(QLatin1String("with")); // end + } + return keywords; +} + +static QSet alphaChars() { + QSet rc; + const QString alpha = QLatin1String("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + foreach (QChar chr, alpha) + rc.insert(chr); + return rc; +} + +namespace qdesigner_internal { + +QScriptHighlighter::QScriptHighlighter(QTextDocument *parent) + : QSyntaxHighlighter(parent) +{ + m_numberFormat.setForeground(Qt::blue); + m_stringFormat.setForeground(Qt::darkGreen); + m_typeFormat.setForeground(Qt::darkMagenta); + m_keywordFormat.setForeground(Qt::darkYellow); + m_labelFormat.setForeground(Qt::darkRed); + m_commentFormat.setForeground(Qt::red); + //m_commentFormat.setFontFamily("times"); + m_commentFormat.setFontItalic(true); + m_preProcessorFormat.setForeground(Qt::darkBlue); +} + +void QScriptHighlighter::highlightBlock(const QString &text) +{ + // states + enum { + StateStandard, + StateCommentStart1, + StateCCommentStart2, + StateCppCommentStart2, + StateCComment, + StateCppComment, + StateCCommentEnd1, + StateCCommentEnd2, + StateStringStart, + StateString, + StateStringEnd, + StateString2Start, + StateString2, + StateString2End, + StateNumber, + StatePreProcessor, + NumStates + }; + // tokens + enum { + InputAlpha, + InputNumber, + InputAsterix, + InputSlash, + InputParen, + InputSpace, + InputHash, + InputQuotation, + InputApostrophe, + InputSep, + NumInputs + }; + + static const uchar table[NumStates][NumInputs] = { + { StateStandard, StateNumber, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateStandard + { StateStandard, StateNumber, StateCCommentStart2, StateCppCommentStart2, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateCommentStart1 + { StateCComment, StateCComment, StateCCommentEnd1, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment }, // StateCCommentStart2 + { StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment }, // CppCommentStart2 + { StateCComment, StateCComment, StateCCommentEnd1, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment }, // StateCComment + { StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment, StateCppComment }, // StateCppComment + { StateCComment, StateCComment, StateCCommentEnd1, StateCCommentEnd2, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment, StateCComment }, // StateCCommentEnd1 + { StateStandard, StateNumber, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateCCommentEnd2 + { StateString, StateString, StateString, StateString, StateString, StateString, StateString, StateStringEnd, StateString, StateString }, // StateStringStart + { StateString, StateString, StateString, StateString, StateString, StateString, StateString, StateStringEnd, StateString, StateString }, // StateString + { StateStandard, StateStandard, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateStringEnd + { StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2End, StateString2 }, // StateString2Start + { StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2, StateString2End, StateString2 }, // StateString2 + { StateStandard, StateStandard, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateString2End + { StateNumber, StateNumber, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard }, // StateNumber + { StatePreProcessor, StateStandard, StateStandard, StateCommentStart1, StateStandard, StateStandard, StatePreProcessor, StateStringStart, StateString2Start, StateStandard } // StatePreProcessor + }; + + QString buffer; + buffer.reserve(text.length()); + QTextCharFormat emptyFormat; + + int state = StateStandard; + const int previousState = previousBlockState(); + if (previousState != -1) + state = previousState; + + if (text.isEmpty()) { + setCurrentBlockState(previousState); + return; + } + + int input = -1; + int i = 0; + bool lastWasBackSlash = false; + bool makeLastStandard = false; + + static const QSet alphabeth = alphaChars(); + static const QString mathChars = QString::fromLatin1("xXeE"); + static const QString numbers = QString::fromLatin1("0123456789"); + bool questionMark = false; + QChar lastChar; + QString firstWord; + forever { + const QChar c = text.at(i); + + if (lastWasBackSlash) { + input = InputSep; + } else { + switch (c.toLatin1()) { + case '*': + input = InputAsterix; + break; + case '/': + input = InputSlash; + break; + case '(': case '[': case '{': + input = InputParen; + if (state == StateStandard + || state == StateNumber + || state == StatePreProcessor + || state == StateCCommentEnd2 + || state == StateCCommentEnd1 + || state == StateString2End + || state == StateStringEnd + ) + //blockData->parentheses << Parenthesis(Parenthesis::Open, c, i); + break; + case ')': case ']': case '}': + input = InputParen; + if (state == StateStandard + || state == StateNumber + || state == StatePreProcessor + || state == StateCCommentEnd2 + || state == StateCCommentEnd1 + || state == StateString2End + || state == StateStringEnd + ) { + //blockData->parentheses << Parenthesis(Parenthesis::Closed, c, i); + } + break; + case '#': + input = InputHash; + break; + case '"': + input = InputQuotation; + break; + case '\'': + input = InputApostrophe; + break; + case ' ': + input = InputSpace; + break; + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': case '0': + if (alphabeth.contains(lastChar) + && (!mathChars.contains(lastChar) || !numbers.contains(text.at(i - 1)))) { + input = InputAlpha; + } else { + if (input == InputAlpha && numbers.contains(lastChar)) + input = InputAlpha; + else + input = InputNumber; + } + break; + case ':': { + input = InputAlpha; + QChar nextChar = QLatin1Char(' '); + if (i < text.length() - 1) + nextChar = text.at(i + 1); + if (state == StateStandard && !questionMark && + lastChar != QLatin1Char(':') && nextChar != QLatin1Char(':')) { + for (int j = 0; j < i; ++j) { + if (format(j) == emptyFormat) + setFormat(j, 1, m_labelFormat); + } + } + break; + } + default: { + if (!questionMark && c == QLatin1Char('?')) + questionMark = true; + if (c.isLetter() || c == QLatin1Char('_')) + input = InputAlpha; + else + input = InputSep; + } break; + } + } + + lastWasBackSlash = !lastWasBackSlash && c == QLatin1Char('\\'); + + if (input == InputAlpha) + buffer += c; + + state = table[state][input]; + + switch (state) { + case StateStandard: { + setFormat(i, 1, emptyFormat); + if (makeLastStandard) + setFormat(i - 1, 1, emptyFormat); + makeLastStandard = false; + if (!buffer.isEmpty() && input != InputAlpha ) { + highlightKeyword(i, buffer); + buffer.clear(); + } + } break; + case StateCommentStart1: + if (makeLastStandard) + setFormat(i - 1, 1, emptyFormat); + makeLastStandard = true; + buffer.resize(0); + break; + case StateCCommentStart2: + setFormat(i - 1, 2, m_commentFormat); + makeLastStandard = false; + buffer.resize(0); + break; + case StateCppCommentStart2: + setFormat(i - 1, 2, m_commentFormat); + makeLastStandard = false; + buffer.resize(0); + break; + case StateCComment: + if (makeLastStandard) + setFormat(i - 1, 1, emptyFormat); + makeLastStandard = false; + setFormat(i, 1, m_commentFormat); + buffer.resize(0); + break; + case StateCppComment: + if (makeLastStandard) + setFormat(i - 1, 1, emptyFormat); + makeLastStandard = false; + setFormat(i, 1, m_commentFormat); + buffer.resize(0); + break; + case StateCCommentEnd1: + if (makeLastStandard) + setFormat(i - 1, 1, emptyFormat); + makeLastStandard = false; + setFormat(i, 1, m_commentFormat); + buffer.resize(0); + break; + case StateCCommentEnd2: + if (makeLastStandard) + setFormat(i - 1, 1, emptyFormat); + makeLastStandard = false; + setFormat(i, 1, m_commentFormat); + buffer.resize(0); + break; + case StateStringStart: + if (makeLastStandard) + setFormat(i - 1, 1, emptyFormat); + makeLastStandard = false; + setFormat(i, 1, emptyFormat); + buffer.resize(0); + break; + case StateString: + if (makeLastStandard) + setFormat(i - 1, 1, emptyFormat); + makeLastStandard = false; + setFormat(i, 1, m_stringFormat); + buffer.resize(0); + break; + case StateStringEnd: + if (makeLastStandard) + setFormat(i - 1, 1, emptyFormat); + makeLastStandard = false; + setFormat(i, 1, emptyFormat); + buffer.resize(0); + break; + case StateString2Start: + if (makeLastStandard) + setFormat(i - 1, 1, emptyFormat); + makeLastStandard = false; + setFormat(i, 1, emptyFormat); + buffer.resize(0); + break; + case StateString2: + if (makeLastStandard) + setFormat(i - 1, 1, emptyFormat); + makeLastStandard = false; + setFormat(i, 1, m_stringFormat); + buffer.resize(0); + break; + case StateString2End: + if (makeLastStandard) + setFormat(i - 1, 1, emptyFormat); + makeLastStandard = false; + setFormat(i, 1, emptyFormat); + buffer.resize(0); + break; + case StateNumber: + if (makeLastStandard) + setFormat(i - 1, 1, emptyFormat); + makeLastStandard = false; + setFormat( i, 1, m_numberFormat); + buffer.resize(0); + break; + case StatePreProcessor: + if (makeLastStandard) + setFormat(i - 1, 1, emptyFormat); + makeLastStandard = false; + setFormat(i, 1, m_preProcessorFormat); + buffer.resize(0); + break; + } + + lastChar = c; + i++; + if (i >= text.length()) + break; + } + + highlightKeyword(text.length(), buffer); + + if (state == StateCComment + || state == StateCCommentEnd1 + || state == StateCCommentStart2 + ) { + state = StateCComment; + } else if (state == StateString) { + state = StateString; + } else if (state == StateString2) { + state = StateString2; + } else { + state = StateStandard; + } + + setCurrentBlockState(state); +} + +void QScriptHighlighter::highlightKeyword(int currentPos, const QString &buffer) +{ + if (buffer.isEmpty()) + return; + + if (buffer.at(0) == QLatin1Char('Q')) { + setFormat(currentPos - buffer.length(), buffer.length(), m_typeFormat); + } else { + if (qscriptKeywords().contains(buffer)) { + setFormat(currentPos - buffer.length(), buffer.length(), m_keywordFormat); + } + } +} +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qscripthighlighter_p.h b/src/designer/src/lib/shared/qscripthighlighter_p.h new file mode 100644 index 000000000..7e067c299 --- /dev/null +++ b/src/designer/src/lib/shared/qscripthighlighter_p.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QSCRIPTSYNTAXHIGHLIGHTER_H +#define QSCRIPTSYNTAXHIGHLIGHTER_H + +#include + +QT_BEGIN_NAMESPACE + +namespace qdesigner_internal { + +class QScriptHighlighter : public QSyntaxHighlighter +{ +public: + explicit QScriptHighlighter(QTextDocument *parent); + virtual void highlightBlock(const QString &text); + +private: + void highlightKeyword(int currentPos, const QString &buffer); + + QTextCharFormat m_numberFormat; + QTextCharFormat m_stringFormat; + QTextCharFormat m_typeFormat; + QTextCharFormat m_keywordFormat; + QTextCharFormat m_labelFormat; + QTextCharFormat m_commentFormat; + QTextCharFormat m_preProcessorFormat; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif diff --git a/src/designer/src/lib/shared/qsimpleresource.cpp b/src/designer/src/lib/shared/qsimpleresource.cpp new file mode 100644 index 000000000..178ba3e18 --- /dev/null +++ b/src/designer/src/lib/shared/qsimpleresource.cpp @@ -0,0 +1,418 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsimpleresource_p.h" +#include "widgetfactory_p.h" +#include "widgetdatabase_p.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +QT_BEGIN_NAMESPACE + +namespace { + typedef QList DomWidgetDataList; + typedef QList DomPropertyList; + typedef QList CustomWidgetInterfaces; +} + +namespace qdesigner_internal { + +bool QSimpleResource::m_warningsEnabled = true; + +QSimpleResource::QSimpleResource(QDesignerFormEditorInterface *core) : + QAbstractFormBuilder(), + m_core(core) +{ + QString workingDirectory = QDir::homePath(); + workingDirectory += QDir::separator(); + workingDirectory += QLatin1String(".designer"); + setWorkingDirectory(QDir(workingDirectory)); +#ifndef QT_FORMBUILDER_NO_SCRIPT + // Disable scripting in the editors. + formScriptRunner()-> setOptions(QFormScriptRunner::DisableScripts); +#endif +} + +QSimpleResource::~QSimpleResource() +{ + +} + +QBrush QSimpleResource::setupBrush(DomBrush *brush) +{ + return QAbstractFormBuilder::setupBrush(brush); +} + +DomBrush *QSimpleResource::saveBrush(const QBrush &brush) +{ + return QAbstractFormBuilder::saveBrush(brush); +} + +QIcon QSimpleResource::nameToIcon(const QString &filePath, const QString &qrcPath) +{ + Q_UNUSED(filePath) + Q_UNUSED(qrcPath) + qWarning() << "QSimpleResource::nameToIcon() is obsoleted"; + return QIcon(); +} + +QString QSimpleResource::iconToFilePath(const QIcon &pm) const +{ + Q_UNUSED(pm) + qWarning() << "QSimpleResource::iconToFilePath() is obsoleted"; + return QString(); +} + +QString QSimpleResource::iconToQrcPath(const QIcon &pm) const +{ + Q_UNUSED(pm) + qWarning() << "QSimpleResource::iconToQrcPath() is obsoleted"; + return QString(); +} + +QPixmap QSimpleResource::nameToPixmap(const QString &filePath, const QString &qrcPath) +{ + Q_UNUSED(filePath) + Q_UNUSED(qrcPath) + qWarning() << "QSimpleResource::nameToPixmap() is obsoleted"; + return QPixmap(); +} + +QString QSimpleResource::pixmapToFilePath(const QPixmap &pm) const +{ + Q_UNUSED(pm) + qWarning() << "QSimpleResource::pixmapToFilePath() is obsoleted"; + return QString(); +} + +QString QSimpleResource::pixmapToQrcPath(const QPixmap &pm) const +{ + Q_UNUSED(pm) + qWarning() << "QSimpleResource::pixmapToQrcPath() is obsoleted"; + return QString(); +} + +DomScript *QSimpleResource::createScript(const QString &script, ScriptSource source) +{ + if (script.isEmpty()) + return 0; + DomScript *domScript = new DomScript(); + switch (source) { + case ScriptExtension: + domScript->setAttributeSource(QLatin1String("extension")); + break; + case ScriptDesigner: + domScript->setAttributeSource(QLatin1String("designer")); + break; + case ScriptCustomWidgetPlugin: + domScript->setAttributeSource(QLatin1String("customwidgetplugin")); + break; + } + domScript->setAttributeLanguage(QLatin1String("Qt Script")); + domScript->setText(script); + return domScript; +} + +// Add a script to a list of DomScripts unless empty +void QSimpleResource::addScript(const QString &script, ScriptSource source, DomScripts &domScripts) +{ + if (DomScript *domScript = createScript(script, source)) { + domScripts += domScript; + } +} + +void QSimpleResource::addExtensionDataToDOM(QAbstractFormBuilder *afb, + QDesignerFormEditorInterface *core, + DomWidget *ui_widget, QWidget *widget) +{ + QExtensionManager *emgr = core->extensionManager(); + if (QDesignerExtraInfoExtension *extra = qt_extension(emgr, widget)) { + extra->saveWidgetExtraInfo(ui_widget); + } + if (QDesignerScriptExtension *scriptExt = qt_extension(emgr, widget)) { + // Add internal state + const QVariantMap data = scriptExt->data(); + if (!data.empty()) { + // Convert the map to a DomState. + // We pass on the widget for property introspection. Thus, non-designable properties + // that have to be converted using QMetaObject (enums and the like) will work. + DomPropertyList properties; + const QVariantMap::const_iterator vcend = data.constEnd(); + for (QVariantMap::const_iterator it = data.constBegin(); it != vcend; ++it) { + if (DomProperty *prop = variantToDomProperty(afb, widget->metaObject(), it.key(), it.value())) + properties += prop; + } + if (!properties.empty()) { + DomWidgetData *domData = new DomWidgetData; + domData->setElementProperty(properties); + DomWidgetDataList domDataList; + domDataList += domData; + ui_widget->setElementWidgetData(domDataList); + } + + } + // Add script + const QString script = scriptExt->script(); + if (!script.isEmpty()) { + DomScripts domScripts = ui_widget->elementScript(); + addScript(script, ScriptExtension, domScripts); + ui_widget->setElementScript(domScripts); + } + } +} + +void QSimpleResource::applyExtensionDataFromDOM(QAbstractFormBuilder *afb, + QDesignerFormEditorInterface *core, + DomWidget *ui_widget, QWidget *widget, bool applyState) +{ + QExtensionManager *emgr = core->extensionManager(); + if (QDesignerExtraInfoExtension *extra = qt_extension(emgr, widget)) { + extra->loadWidgetExtraInfo(ui_widget); + } + if (applyState) { + if (QDesignerScriptExtension *scriptExt = qt_extension(emgr, widget)) { + // Apply the state. + // We pass on the widget for property introspection. Thus, non-designable properties + // that have to be converted using QMetaObject (enums and the like) will work. + QVariantMap data; + DomWidgetDataList domDataList = ui_widget->elementWidgetData(); + if (!domDataList.empty()) { + foreach (const DomWidgetData *domData, domDataList) { + const DomPropertyList properties = domData->elementProperty(); + foreach(const DomProperty *prop, properties) { + const QVariant vprop = domPropertyToVariant(afb, widget->metaObject(), prop); + if (vprop.type() != QVariant::Invalid) + data.insert(prop->attributeName(), vprop); + } + } + } + scriptExt->setData(data); + } + } +} + +QString QSimpleResource::customWidgetScript(QDesignerFormEditorInterface *core, QObject *object) +{ + return customWidgetScript(core, qdesigner_internal::WidgetFactory::classNameOf(core, object)); +} + +bool QSimpleResource::hasCustomWidgetScript(QDesignerFormEditorInterface *, QObject *) +{ + return false; +} + +QString QSimpleResource::customWidgetScript(QDesignerFormEditorInterface *, const QString &) +{ + return QString(); +} + +bool QSimpleResource::setWarningsEnabled(bool warningsEnabled) +{ + const bool rc = m_warningsEnabled; + m_warningsEnabled = warningsEnabled; + return rc; +} + +bool QSimpleResource::warningsEnabled() +{ + return m_warningsEnabled; +} + +// Custom widgets handling helpers + +// Add unique fake slots and signals to lists +bool QSimpleResource::addFakeMethods(const DomSlots *domSlots, QStringList &fakeSlots, QStringList &fakeSignals) +{ + if (!domSlots) + return false; + + bool rc = false; + foreach (const QString &fakeSlot, domSlots->elementSlot()) + if (fakeSlots.indexOf(fakeSlot) == -1) { + fakeSlots += fakeSlot; + rc = true; + } + + foreach (const QString &fakeSignal, domSlots->elementSignal()) + if (fakeSignals.indexOf(fakeSignal) == -1) { + fakeSignals += fakeSignal; + rc = true; + } + return rc; +} + +void QSimpleResource::addFakeMethodsToWidgetDataBase(const DomCustomWidget *domCustomWidget, WidgetDataBaseItem *item) +{ + const DomSlots *domSlots = domCustomWidget->elementSlots(); + if (!domSlots) + return; + + // Merge in new slots, signals + QStringList fakeSlots = item->fakeSlots(); + QStringList fakeSignals = item->fakeSignals(); + if (addFakeMethods(domSlots, fakeSlots, fakeSignals)) { + item->setFakeSlots(fakeSlots); + item->setFakeSignals(fakeSignals); + } +} + +// Perform one iteration of adding the custom widgets to the database, +// looking up the base class and inheriting its data. +// Remove the succeeded custom widgets from the list. +// Classes whose base class could not be found are left in the list. + +void QSimpleResource::addCustomWidgetsToWidgetDatabase(const QDesignerFormEditorInterface *core, + QList& custom_widget_list) +{ + QDesignerWidgetDataBaseInterface *db = core->widgetDataBase(); + for (int i=0; i < custom_widget_list.size(); ) { + bool classInserted = false; + DomCustomWidget *custom_widget = custom_widget_list[i]; + const QString customClassName = custom_widget->elementClass(); + const QString base_class = custom_widget->elementExtends(); + QString includeFile; + IncludeType includeType = IncludeLocal; + if (const DomHeader *header = custom_widget->elementHeader()) { + includeFile = header->text(); + if (header->hasAttributeLocation() && header->attributeLocation() == QLatin1String("global")) + includeType = IncludeGlobal; + } + const bool domIsContainer = custom_widget->elementContainer(); + // Append a new item + if (base_class.isEmpty()) { + WidgetDataBaseItem *item = new WidgetDataBaseItem(customClassName); + item->setPromoted(false); + item->setGroup(QCoreApplication::translate("Designer", "Custom Widgets")); + item->setIncludeFile(buildIncludeFile(includeFile, includeType)); + item->setContainer(domIsContainer); + item->setCustom(true); + addFakeMethodsToWidgetDataBase(custom_widget, item); + db->append(item); + custom_widget_list.removeAt(i); + classInserted = true; + } else { + // Create a new entry cloned from base class. Note that this will ignore existing + // classes, eg, plugin custom widgets. + QDesignerWidgetDataBaseItemInterface *item = + appendDerived(db, customClassName, QCoreApplication::translate("Designer", "Promoted Widgets"), + base_class, + buildIncludeFile(includeFile, includeType), + true,true); + // Ok, base class found. + if (item) { + // Hack to accommodate for old UI-files in which "container" is not set properly: + // Apply "container" from DOM only if true (else, eg classes from QFrame might not accept + // dropping child widgets on them as container=false). This also allows for + // QWidget-derived stacked pages. + if (domIsContainer) + item->setContainer(domIsContainer); + + addFakeMethodsToWidgetDataBase(custom_widget, static_cast(item)); + custom_widget_list.removeAt(i); + classInserted = true; + } + } + // Skip failed item. + if (!classInserted) + i++; + } + +} + +void QSimpleResource::handleDomCustomWidgets(const QDesignerFormEditorInterface *core, + const DomCustomWidgets *dom_custom_widgets) +{ + if (dom_custom_widgets == 0) + return; + QList custom_widget_list = dom_custom_widgets->elementCustomWidget(); + // Attempt to insert each item derived from its base class. + // This should at most require two iterations in the event that the classes are out of order + // (derived first, max depth: promoted custom plugin = 2) + for (int iteration = 0; iteration < 2; iteration++) { + addCustomWidgetsToWidgetDatabase(core, custom_widget_list); + if (custom_widget_list.empty()) + return; + } + // Oops, there are classes left whose base class could not be found. + // Default them to QWidget with warnings. + const QString fallBackBaseClass = QLatin1String("QWidget"); + for (int i=0; i < custom_widget_list.size(); i++ ) { + DomCustomWidget *custom_widget = custom_widget_list[i]; + const QString customClassName = custom_widget->elementClass(); + const QString base_class = custom_widget->elementExtends(); + qDebug() << "** WARNING The base class " << base_class << " of the custom widget class " << customClassName + << " could not be found. Defaulting to " << fallBackBaseClass << '.'; + custom_widget->setElementExtends(fallBackBaseClass); + } + // One more pass. + addCustomWidgetsToWidgetDatabase(core, custom_widget_list); +} + +// ------------ FormBuilderClipboard + +FormBuilderClipboard::FormBuilderClipboard(QWidget *w) +{ + m_widgets += w; +} + +bool FormBuilderClipboard::empty() const +{ + return m_widgets.empty() && m_actions.empty(); +} +} + +QT_END_NAMESPACE diff --git a/src/designer/src/lib/shared/qsimpleresource_p.h b/src/designer/src/lib/shared/qsimpleresource_p.h new file mode 100644 index 000000000..597b101cd --- /dev/null +++ b/src/designer/src/lib/shared/qsimpleresource_p.h @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QSIMPLERESOURCE_H +#define QSIMPLERESOURCE_H + +#include "shared_global_p.h" +#include "abstractformbuilder.h" +#include + +QT_BEGIN_NAMESPACE + +class DomScript; +class DomCustomWidgets; +class DomCustomWidget; +class DomSlots; + +class QDesignerFormEditorInterface; + +namespace qdesigner_internal { + +class WidgetDataBaseItem; + +class QDESIGNER_SHARED_EXPORT QSimpleResource : public QAbstractFormBuilder +{ +public: + explicit QSimpleResource(QDesignerFormEditorInterface *core); + virtual ~QSimpleResource(); + + QBrush setupBrush(DomBrush *brush); + DomBrush *saveBrush(const QBrush &brush); + + inline QDesignerFormEditorInterface *core() const + { return m_core; } + + // Query extensions for additional data + static void addExtensionDataToDOM(QAbstractFormBuilder *afb, + QDesignerFormEditorInterface *core, + DomWidget *ui_widget, QWidget *widget); + static void applyExtensionDataFromDOM(QAbstractFormBuilder *afb, + QDesignerFormEditorInterface *core, + DomWidget *ui_widget, QWidget *widget, + bool applyState); + // Enable warnings while saving. Turn off for backups. + static bool setWarningsEnabled(bool warningsEnabled); + static bool warningsEnabled(); + // Return the script returned by the CustomWidget codeTemplate API + static QString customWidgetScript(QDesignerFormEditorInterface *core, QObject *object); + static QString customWidgetScript(QDesignerFormEditorInterface *core, const QString &className); + static bool hasCustomWidgetScript(QDesignerFormEditorInterface *core, QObject *object); + + // Implementation for FormBuilder::createDomCustomWidgets() that adds + // the custom widgets to the widget database + static void handleDomCustomWidgets(const QDesignerFormEditorInterface *core, + const DomCustomWidgets *dom_custom_widgets); + +protected: + virtual QIcon nameToIcon(const QString &filePath, const QString &qrcPath); + virtual QString iconToFilePath(const QIcon &pm) const; + virtual QString iconToQrcPath(const QIcon &pm) const; + virtual QPixmap nameToPixmap(const QString &filePath, const QString &qrcPath); + virtual QString pixmapToFilePath(const QPixmap &pm) const; + virtual QString pixmapToQrcPath(const QPixmap &pm) const; + + enum ScriptSource { ScriptDesigner, ScriptExtension, ScriptCustomWidgetPlugin }; + static DomScript*createScript(const QString &script, ScriptSource source); + typedef QList DomScripts; + static void addScript(const QString &script, ScriptSource source, DomScripts &domScripts); + + static bool addFakeMethods(const DomSlots *domSlots, QStringList &fakeSlots, QStringList &fakeSignals); + +private: + static void addCustomWidgetsToWidgetDatabase(const QDesignerFormEditorInterface *core, + QList& custom_widget_list); + static void addFakeMethodsToWidgetDataBase(const DomCustomWidget *domCustomWidget, WidgetDataBaseItem *item); + + static bool m_warningsEnabled; + QDesignerFormEditorInterface *m_core; +}; + +// Contents of clipboard for formbuilder copy and paste operations +// (Actions and widgets) +struct QDESIGNER_SHARED_EXPORT FormBuilderClipboard { + typedef QList ActionList; + + FormBuilderClipboard() {} + FormBuilderClipboard(QWidget *w); + + bool empty() const; + + QWidgetList m_widgets; + ActionList m_actions; +}; + +// Base class for a form builder used in the editor that +// provides copy and paste.(move into base interface) +class QDESIGNER_SHARED_EXPORT QEditorFormBuilder : public QSimpleResource +{ +public: + explicit QEditorFormBuilder(QDesignerFormEditorInterface *core) : QSimpleResource(core) {} + + virtual bool copy(QIODevice *dev, const FormBuilderClipboard &selection) = 0; + virtual DomUI *copy(const FormBuilderClipboard &selection) = 0; + + // A widget parent needs to be specified, otherwise, the widget factory cannot locate the form window via parent + // and thus is not able to construct special widgets (QLayoutWidget). + virtual FormBuilderClipboard paste(DomUI *ui, QWidget *widgetParent, QObject *actionParent = 0) = 0; + virtual FormBuilderClipboard paste(QIODevice *dev, QWidget *widgetParent, QObject *actionParent = 0) = 0; +}; + +} // namespace qdesigner_internal + +QT_END_NAMESPACE + +#endif diff --git a/src/designer/src/lib/shared/qtresourceeditordialog.cpp b/src/designer/src/lib/shared/qtresourceeditordialog.cpp new file mode 100644 index 000000000..9162b097d --- /dev/null +++ b/src/designer/src/lib/shared/qtresourceeditordialog.cpp @@ -0,0 +1,2223 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractsettings_p.h" +#include "abstractformeditor.h" +#include "qtresourceeditordialog_p.h" +#include "ui_qtresourceeditordialog.h" +#include "qtresourcemodel_p.h" +#include "iconloader_p.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static const char *rccRootTag = "RCC"; +static const char *rccTag = "qresource"; +static const char *rccFileTag = "file"; +static const char *rccAliasAttribute = "alias"; +static const char *rccPrefixAttribute = "prefix"; +static const char *rccLangAttribute = "lang"; +static const char *SplitterPosition = "SplitterPosition"; +static const char *Geometry = "Geometry"; +static const char *QrcDialogC = "QrcDialog"; + +static QString msgOverwrite(const QString &fname) +{ + return QApplication::translate("QtResourceEditorDialog", "%1 already exists.\nDo you want to replace it?", 0, QApplication::UnicodeUTF8).arg(fname); +} + +static QString msgTagMismatch(const QString &got, const QString &expected) +{ + return QApplication::translate("QtResourceEditorDialog", "The file does not appear to be a resource file; element '%1' was found where '%2' was expected.").arg(got).arg(expected); +} + +namespace { + +// below 3 data classes should be derived from QSharedData and made implicit shared class +struct QtResourceFileData { + QString path; + QString alias; + bool operator==(const QtResourceFileData &other) const { + if (path == other.path && alias == other.alias) + return true; + return false; + } +}; + +struct QtResourcePrefixData { + QString prefix; + QString language; + QList resourceFileList; + bool operator==(const QtResourcePrefixData &other) const { + if (prefix == other.prefix && language == other.language && resourceFileList == other.resourceFileList) + return true; + return false; + } +}; + +struct QtQrcFileData { + QString qrcPath; + QList resourceList; + bool operator==(const QtQrcFileData &other) const { + if (qrcPath == other.qrcPath && resourceList == other.resourceList) + return true; + return false; + } +}; + +bool loadResourceFileData(const QDomElement &fileElem, QtResourceFileData *fileData, QString *errorMessage) +{ + if (!fileData) + return false; + + if (fileElem.tagName() != QLatin1String(rccFileTag)) { + *errorMessage = msgTagMismatch(fileElem.tagName(), QLatin1String(rccFileTag)); + return false; + } + + QtResourceFileData &data = *fileData; + + data.path = fileElem.text(); + data.alias = fileElem.attribute(QLatin1String(rccAliasAttribute)); + + return true; +} + +static bool loadResourcePrefixData(const QDomElement &prefixElem, QtResourcePrefixData *prefixData, QString *errorMessage) +{ + if (!prefixData) + return false; + + if (prefixElem.tagName() != QLatin1String(rccTag)) { + *errorMessage = msgTagMismatch(prefixElem.tagName(), QLatin1String(rccTag)); + return false; + } + + QtResourcePrefixData &data = *prefixData; + + data.prefix = prefixElem.attribute(QLatin1String(rccPrefixAttribute)); + data.language = prefixElem.attribute(QLatin1String(rccLangAttribute)); + QDomElement fileElem = prefixElem.firstChildElement(); + while (!fileElem.isNull()) { + QtResourceFileData fileData; + if (!loadResourceFileData(fileElem, &fileData, errorMessage)) + return false; + data.resourceFileList.append(fileData); + fileElem = fileElem.nextSiblingElement(); + } + return true; +} + +static bool loadQrcFileData(const QDomDocument &doc, const QString &path, QtQrcFileData *qrcFileData, QString *errorMessage) +{ + if (!qrcFileData) + return false; + + QtQrcFileData &data = *qrcFileData; + + QDomElement docElem = doc.documentElement(); + if (docElem.tagName() != QLatin1String(rccRootTag)) { + *errorMessage = msgTagMismatch(docElem.tagName(), QLatin1String(rccRootTag)); + return false; + } + + QDomElement prefixElem = docElem.firstChildElement(); + while (!prefixElem.isNull()) { + QtResourcePrefixData prefixData; + if (!loadResourcePrefixData(prefixElem, &prefixData, errorMessage)) + return false; + data.resourceList.append(prefixData); + prefixElem = prefixElem.nextSiblingElement(); + } + + data.qrcPath = path; + + return true; +} + +QDomElement saveResourceFileData(QDomDocument &doc, const QtResourceFileData &fileData) +{ + QDomElement fileElem = doc.createElement(QLatin1String(rccFileTag)); + if (!fileData.alias.isEmpty()) + fileElem.setAttribute(QLatin1String(rccAliasAttribute), fileData.alias); + + QDomText textElem = doc.createTextNode(fileData.path); + fileElem.appendChild(textElem); + + return fileElem; +} + +QDomElement saveResourcePrefixData(QDomDocument &doc, const QtResourcePrefixData &prefixData) +{ + QDomElement prefixElem = doc.createElement(QLatin1String(rccTag)); + if (!prefixData.prefix.isEmpty()) + prefixElem.setAttribute(QLatin1String(rccPrefixAttribute), prefixData.prefix); + if (!prefixData.language.isEmpty()) + prefixElem.setAttribute(QLatin1String(rccLangAttribute), prefixData.language); + + QListIterator itFile(prefixData.resourceFileList); + while (itFile.hasNext()) { + QDomElement fileElem = saveResourceFileData(doc, itFile.next()); + prefixElem.appendChild(fileElem); + } + + return prefixElem; +} + +QDomDocument saveQrcFileData(const QtQrcFileData &qrcFileData) +{ + QDomDocument doc; + QDomElement docElem = doc.createElement(QLatin1String(rccRootTag)); + QListIterator itPrefix(qrcFileData.resourceList); + while (itPrefix.hasNext()) { + QDomElement prefixElem = saveResourcePrefixData(doc, itPrefix.next()); + + docElem.appendChild(prefixElem); + } + doc.appendChild(docElem); + + return doc; +} +// --------------- QtResourceFile +class QtResourceFile { +public: + friend class QtQrcManager; + + QString path() const { return m_path; } + QString alias() const { return m_alias; } + QString fullPath() const { return m_fullPath; } +private: + QtResourceFile() {} + + QString m_path; + QString m_alias; + QString m_fullPath; +}; + +class QtResourcePrefix { +public: + friend class QtQrcManager; + + QString prefix() const { return m_prefix; } + QString language() const { return m_language; } + QList resourceFiles() const { return m_resourceFiles; } +private: + QtResourcePrefix() {} + + QString m_prefix; + QString m_language; + QList m_resourceFiles; + +}; +// ------------------- QtQrcFile +class QtQrcFile { +public: + friend class QtQrcManager; + + QString path() const { return m_path; } + QString fileName() const { return m_fileName; } + QList resourcePrefixList() const { return m_resourcePrefixes; } + QtQrcFileData initialState() const { return m_initialState; } + +private: + QtQrcFile() { } + + void setPath(const QString &path) { + m_path = path; + QFileInfo fi(path); + m_fileName = fi.fileName(); + } + + QString m_path; + QString m_fileName; + QList m_resourcePrefixes; + QtQrcFileData m_initialState; +}; + +// ------------------ QtQrcManager +class QtQrcManager : public QObject +{ + Q_OBJECT +public: + QtQrcManager(QObject *parent = 0); + ~QtQrcManager(); + + QList qrcFiles() const; + + // helpers + QtQrcFile *qrcFileOf(const QString &path) const; + QtQrcFile *qrcFileOf(QtResourcePrefix *resourcePrefix) const; + QtQrcFile *qrcFileOf(QtResourceFile *resourceFile) const; + QtResourcePrefix *resourcePrefixOf(QtResourceFile *resourceFile) const; + + QtQrcFile *importQrcFile(const QtQrcFileData &qrcFileData, QtQrcFile *beforeQrcFile = 0); + void exportQrcFile(QtQrcFile *qrcFile, QtQrcFileData *qrcFileData) const; + + QList resourceFilesOf(const QString &resourceFullPath) const; + QIcon icon(const QString &resourceFullPath) const; + bool exists(const QString &resourceFullPath) const; + bool exists(QtQrcFile *qrcFile) const; + + QtQrcFile *prevQrcFile(QtQrcFile *qrcFile) const; + QtQrcFile *nextQrcFile(QtQrcFile *qrcFile) const; + QtResourcePrefix *prevResourcePrefix(QtResourcePrefix *resourcePrefix) const; + QtResourcePrefix *nextResourcePrefix(QtResourcePrefix *resourcePrefix) const; + QtResourceFile *prevResourceFile(QtResourceFile *resourceFile) const; + QtResourceFile *nextResourceFile(QtResourceFile *resourceFile) const; + + void clear(); + +public slots: + + QtQrcFile *insertQrcFile(const QString &path, QtQrcFile *beforeQrcFile = 0, bool newFile = false); + void moveQrcFile(QtQrcFile *qrcFile, QtQrcFile *beforeQrcFile); + void setInitialState(QtQrcFile *qrcFile, const QtQrcFileData &initialState); + void removeQrcFile(QtQrcFile *qrcFile); + + QtResourcePrefix *insertResourcePrefix(QtQrcFile *qrcFile, const QString &prefix, + const QString &language, QtResourcePrefix *beforeResourcePrefix = 0); + void moveResourcePrefix(QtResourcePrefix *resourcePrefix, QtResourcePrefix *beforeResourcePrefix); // the same qrc file??? + void changeResourcePrefix(QtResourcePrefix *resourcePrefix, const QString &newPrefix); + void changeResourceLanguage(QtResourcePrefix *resourcePrefix, const QString &newLanguage); + void removeResourcePrefix(QtResourcePrefix *resourcePrefix); + + QtResourceFile *insertResourceFile(QtResourcePrefix *resourcePrefix, const QString &path, + const QString &alias, QtResourceFile *beforeResourceFile = 0); + void moveResourceFile(QtResourceFile *resourceFile, QtResourceFile *beforeResourceFile); // the same prefix??? + void changeResourceAlias(QtResourceFile *resourceFile, const QString &newAlias); + void removeResourceFile(QtResourceFile *resourceFile); + +signals: + void qrcFileInserted(QtQrcFile *qrcFile); + void qrcFileMoved(QtQrcFile *qrcFile, QtQrcFile *oldBeforeQrcFile); + void qrcFileRemoved(QtQrcFile *qrcFile); + + void resourcePrefixInserted(QtResourcePrefix *resourcePrefix); + void resourcePrefixMoved(QtResourcePrefix *resourcePrefix, QtResourcePrefix *oldBeforeResourcePrefix); + void resourcePrefixChanged(QtResourcePrefix *resourcePrefix, const QString &oldPrefix); + void resourceLanguageChanged(QtResourcePrefix *resourcePrefix, const QString &oldLanguage); + void resourcePrefixRemoved(QtResourcePrefix *resourcePrefix); + + void resourceFileInserted(QtResourceFile *resourceFile); + void resourceFileMoved(QtResourceFile *resourceFile, QtResourceFile *oldBeforeResourceFile); + void resourceAliasChanged(QtResourceFile *resourceFile, const QString &oldAlias); + void resourceFileRemoved(QtResourceFile *resourceFile); +private: + + QList m_qrcFiles; + QMap m_pathToQrc; + QMap m_qrcFileToExists; + QMap m_prefixToQrc; + QMap m_fileToPrefix; + QMap > m_fullPathToResourceFiles; + QMap m_fullPathToIcon; + QMap m_fullPathToExists; +}; + +QtQrcManager::QtQrcManager(QObject *parent) + : QObject(parent) +{ + +} + +QtQrcManager::~QtQrcManager() +{ + clear(); +} + +QList QtQrcManager::qrcFiles() const +{ + return m_qrcFiles; +} + +QtQrcFile *QtQrcManager::qrcFileOf(const QString &path) const +{ + return m_pathToQrc.value(path); +} + +QtQrcFile *QtQrcManager::qrcFileOf(QtResourcePrefix *resourcePrefix) const +{ + return m_prefixToQrc.value(resourcePrefix); +} + +QtQrcFile *QtQrcManager::qrcFileOf(QtResourceFile *resourceFile) const +{ + return qrcFileOf(resourcePrefixOf(resourceFile)); +} + +QtResourcePrefix *QtQrcManager::resourcePrefixOf(QtResourceFile *resourceFile) const +{ + return m_fileToPrefix.value(resourceFile); +} + +QtQrcFile *QtQrcManager::importQrcFile(const QtQrcFileData &qrcFileData, QtQrcFile *beforeQrcFile) +{ + QtQrcFile *qrcFile = insertQrcFile(qrcFileData.qrcPath, beforeQrcFile); + if (!qrcFile) + return 0; + QListIterator itPrefix(qrcFileData.resourceList); + while (itPrefix.hasNext()) { + const QtResourcePrefixData &prefixData = itPrefix.next(); + QtResourcePrefix *resourcePrefix = insertResourcePrefix(qrcFile, prefixData.prefix, prefixData.language, 0); + QListIterator itFile(prefixData.resourceFileList); + while (itFile.hasNext()) { + const QtResourceFileData &fileData = itFile.next(); + insertResourceFile(resourcePrefix, fileData.path, fileData.alias, 0); + } + } + setInitialState(qrcFile, qrcFileData); + return qrcFile; +} + +void QtQrcManager::exportQrcFile(QtQrcFile *qrcFile, QtQrcFileData *qrcFileData) const +{ + if (!qrcFileData) + return; + + if (!qrcFile) + return; + + QtQrcFileData &data = *qrcFileData; + + QList resourceList; + + QList resourcePrefixes = qrcFile->resourcePrefixList(); + QListIterator itPrefix(resourcePrefixes); + while (itPrefix.hasNext()) { + QList resourceFileList; + + QtResourcePrefix *prefix = itPrefix.next(); + + QList resourceFiles = prefix->resourceFiles(); + QListIterator itFile(resourceFiles); + while (itFile.hasNext()) { + QtResourceFile *file = itFile.next(); + QtResourceFileData fileData; + fileData.path = file->path(); + fileData.alias = file->alias(); + resourceFileList << fileData; + } + QtResourcePrefixData prefixData; + prefixData.prefix = prefix->prefix(); + prefixData.language = prefix->language(); + prefixData.resourceFileList = resourceFileList; + + resourceList << prefixData; + } + data = QtQrcFileData(); + data.qrcPath = qrcFile->path(); + data.resourceList = resourceList; +} + +QList QtQrcManager::resourceFilesOf(const QString &resourcePath) const +{ + return m_fullPathToResourceFiles.value(resourcePath); +} + +QIcon QtQrcManager::icon(const QString &resourceFullPath) const +{ + return m_fullPathToIcon.value(resourceFullPath); +} + +bool QtQrcManager::exists(const QString &resourceFullPath) const +{ + return m_fullPathToExists.value(resourceFullPath, false); +} + +bool QtQrcManager::exists(QtQrcFile *qrcFile) const +{ + return m_qrcFileToExists.value(qrcFile, false); +} + +QtQrcFile *QtQrcManager::prevQrcFile(QtQrcFile *qrcFile) const +{ + if (!qrcFile) + return 0; + const int idx = m_qrcFiles.indexOf(qrcFile); + if (idx <= 0) + return 0; + return m_qrcFiles.at(idx - 1); +} + +QtQrcFile *QtQrcManager::nextQrcFile(QtQrcFile *qrcFile) const +{ + if (!qrcFile) + return 0; + const int idx = m_qrcFiles.indexOf(qrcFile); + if (idx < 0 || idx == m_qrcFiles.size() - 1) + return 0; + return m_qrcFiles.at(idx + 1); +} + +QtResourcePrefix *QtQrcManager::prevResourcePrefix(QtResourcePrefix *resourcePrefix) const +{ + if (!resourcePrefix) + return 0; + QList prefixes = qrcFileOf(resourcePrefix)->resourcePrefixList(); + const int idx = prefixes.indexOf(resourcePrefix); + if (idx <= 0) + return 0; + return prefixes.at(idx - 1); +} + +QtResourcePrefix *QtQrcManager::nextResourcePrefix(QtResourcePrefix *resourcePrefix) const +{ + if (!resourcePrefix) + return 0; + QList prefixes = qrcFileOf(resourcePrefix)->resourcePrefixList(); + const int idx = prefixes.indexOf(resourcePrefix); + if (idx < 0 || idx == prefixes.size() - 1) + return 0; + return prefixes.at(idx + 1); +} + +QtResourceFile *QtQrcManager::prevResourceFile(QtResourceFile *resourceFile) const +{ + if (!resourceFile) + return 0; + QList files = resourcePrefixOf(resourceFile)->resourceFiles(); + const int idx = files.indexOf(resourceFile); + if (idx <= 0) + return 0; + return files.at(idx - 1); +} + +QtResourceFile *QtQrcManager::nextResourceFile(QtResourceFile *resourceFile) const +{ + if (!resourceFile) + return 0; + QList files = resourcePrefixOf(resourceFile)->resourceFiles(); + const int idx = files.indexOf(resourceFile); + if (idx < 0 || idx == files.size() - 1) + return 0; + return files.at(idx + 1); +} + +void QtQrcManager::clear() +{ + QList oldQrcFiles = qrcFiles(); + QListIterator it(oldQrcFiles); + while (it.hasNext()) + removeQrcFile(it.next()); +} + +QtQrcFile *QtQrcManager::insertQrcFile(const QString &path, QtQrcFile *beforeQrcFile, bool newFile) +{ + if (m_pathToQrc.contains(path)) + return 0; + + int idx = m_qrcFiles.indexOf(beforeQrcFile); + if (idx < 0) + idx = m_qrcFiles.size(); + + QtQrcFile *qrcFile = new QtQrcFile(); + qrcFile->setPath(path); + + m_qrcFiles.insert(idx, qrcFile); + m_pathToQrc[path] = qrcFile; + + const QFileInfo fi(path); + m_qrcFileToExists[qrcFile] = fi.exists() || newFile; + + emit qrcFileInserted(qrcFile); + return qrcFile; +} + +void QtQrcManager::moveQrcFile(QtQrcFile *qrcFile, QtQrcFile *beforeQrcFile) +{ + if (qrcFile == beforeQrcFile) + return; + + const int idx = m_qrcFiles.indexOf(qrcFile); + if (idx < 0) + return; + + int beforeIdx = m_qrcFiles.indexOf(beforeQrcFile); + if (beforeIdx < 0) + beforeIdx = m_qrcFiles.size(); + + if (idx == beforeIdx - 1) // the same position, nothing changes + return; + + QtQrcFile *oldBefore = 0; + if (idx < m_qrcFiles.size() - 1) + oldBefore = m_qrcFiles.at(idx + 1); + + m_qrcFiles.removeAt(idx); + if (idx < beforeIdx) + beforeIdx -= 1; + + m_qrcFiles.insert(beforeIdx, qrcFile); + + emit qrcFileMoved(qrcFile, oldBefore); +} + +void QtQrcManager::setInitialState(QtQrcFile *qrcFile, const QtQrcFileData &initialState) +{ + qrcFile->m_initialState = initialState; +} + +void QtQrcManager::removeQrcFile(QtQrcFile *qrcFile) +{ + const int idx = m_qrcFiles.indexOf(qrcFile); + if (idx < 0) + return; + + QList resourcePrefixes = qrcFile->resourcePrefixList(); + QListIterator it(resourcePrefixes); + while (it.hasNext()) + removeResourcePrefix(it.next()); + + emit qrcFileRemoved(qrcFile); + + m_qrcFiles.removeAt(idx); + m_pathToQrc.remove(qrcFile->path()); + m_qrcFileToExists.remove(qrcFile); + delete qrcFile; +} + +QtResourcePrefix *QtQrcManager::insertResourcePrefix(QtQrcFile *qrcFile, const QString &prefix, + const QString &language, QtResourcePrefix *beforeResourcePrefix) +{ + if (!qrcFile) + return 0; + + int idx = qrcFile->m_resourcePrefixes.indexOf(beforeResourcePrefix); + if (idx < 0) + idx = qrcFile->m_resourcePrefixes.size(); + + QtResourcePrefix *resourcePrefix = new QtResourcePrefix(); + resourcePrefix->m_prefix = prefix; + resourcePrefix->m_language = language; + + qrcFile->m_resourcePrefixes.insert(idx, resourcePrefix); + m_prefixToQrc[resourcePrefix] = qrcFile; + + emit resourcePrefixInserted(resourcePrefix); + return resourcePrefix; +} + +void QtQrcManager::moveResourcePrefix(QtResourcePrefix *resourcePrefix, QtResourcePrefix *beforeResourcePrefix) +{ + if (resourcePrefix == beforeResourcePrefix) + return; + + QtQrcFile *qrcFile = qrcFileOf(resourcePrefix); + if (!qrcFile) + return; + + if (beforeResourcePrefix && qrcFileOf(beforeResourcePrefix) != qrcFile) + return; + + const int idx = qrcFile->m_resourcePrefixes.indexOf(resourcePrefix); + + int beforeIdx = qrcFile->m_resourcePrefixes.indexOf(beforeResourcePrefix); + if (beforeIdx < 0) + beforeIdx = qrcFile->m_resourcePrefixes.size(); + + if (idx == beforeIdx - 1) // the same position, nothing changes + return; + + QtResourcePrefix *oldBefore = 0; + if (idx < qrcFile->m_resourcePrefixes.size() - 1) + oldBefore = qrcFile->m_resourcePrefixes.at(idx + 1); + + qrcFile->m_resourcePrefixes.removeAt(idx); + if (idx < beforeIdx) + beforeIdx -= 1; + + qrcFile->m_resourcePrefixes.insert(beforeIdx, resourcePrefix); + + emit resourcePrefixMoved(resourcePrefix, oldBefore); +} + +void QtQrcManager::changeResourcePrefix(QtResourcePrefix *resourcePrefix, const QString &newPrefix) +{ + if (!resourcePrefix) + return; + + const QString oldPrefix = resourcePrefix->m_prefix; + if (oldPrefix == newPrefix) + return; + + resourcePrefix->m_prefix = newPrefix; + + emit resourcePrefixChanged(resourcePrefix, oldPrefix); +} + +void QtQrcManager::changeResourceLanguage(QtResourcePrefix *resourcePrefix, const QString &newLanguage) +{ + if (!resourcePrefix) + return; + + const QString oldLanguage = resourcePrefix->m_language; + if (oldLanguage == newLanguage) + return; + + resourcePrefix->m_language = newLanguage; + + emit resourceLanguageChanged(resourcePrefix, oldLanguage); +} + +void QtQrcManager::removeResourcePrefix(QtResourcePrefix *resourcePrefix) +{ + QtQrcFile *qrcFile = qrcFileOf(resourcePrefix); + if (!qrcFile) + return; + + const int idx = qrcFile->m_resourcePrefixes.indexOf(resourcePrefix); + + QList resourceFiles = resourcePrefix->resourceFiles(); + QListIterator it(resourceFiles); + while (it.hasNext()) + removeResourceFile(it.next()); + + emit resourcePrefixRemoved(resourcePrefix); + + qrcFile->m_resourcePrefixes.removeAt(idx); + m_prefixToQrc.remove(resourcePrefix); + delete resourcePrefix; +} + +QtResourceFile *QtQrcManager::insertResourceFile(QtResourcePrefix *resourcePrefix, const QString &path, + const QString &alias, QtResourceFile *beforeResourceFile) +{ + if (!resourcePrefix) + return 0; + + int idx = resourcePrefix->m_resourceFiles.indexOf(beforeResourceFile); + if (idx < 0) + idx = resourcePrefix->m_resourceFiles.size(); + + QtResourceFile *resourceFile = new QtResourceFile(); + resourceFile->m_path = path; + resourceFile->m_alias = alias; + const QFileInfo fi(qrcFileOf(resourcePrefix)->path()); + const QDir dir(fi.absolutePath()); + const QString fullPath = dir.absoluteFilePath(path); + resourceFile->m_fullPath = fullPath; + + resourcePrefix->m_resourceFiles.insert(idx, resourceFile); + m_fileToPrefix[resourceFile] = resourcePrefix; + m_fullPathToResourceFiles[fullPath].append(resourceFile); + if (!m_fullPathToIcon.contains(fullPath)) { + m_fullPathToIcon[fullPath] = QIcon(fullPath); + const QFileInfo fullInfo(fullPath); + m_fullPathToExists[fullPath] = fullInfo.exists(); + } + + emit resourceFileInserted(resourceFile); + return resourceFile; +} + +void QtQrcManager::moveResourceFile(QtResourceFile *resourceFile, QtResourceFile *beforeResourceFile) +{ + if (resourceFile == beforeResourceFile) + return; + + QtResourcePrefix *resourcePrefix = resourcePrefixOf(resourceFile); + if (!resourcePrefix) + return; + + if (beforeResourceFile && resourcePrefixOf(beforeResourceFile) != resourcePrefix) + return; + + const int idx = resourcePrefix->m_resourceFiles.indexOf(resourceFile); + + int beforeIdx = resourcePrefix->m_resourceFiles.indexOf(beforeResourceFile); + if (beforeIdx < 0) + beforeIdx = resourcePrefix->m_resourceFiles.size(); + + if (idx == beforeIdx - 1) // the same position, nothing changes + return; + + QtResourceFile *oldBefore = 0; + if (idx < resourcePrefix->m_resourceFiles.size() - 1) + oldBefore = resourcePrefix->m_resourceFiles.at(idx + 1); + + resourcePrefix->m_resourceFiles.removeAt(idx); + if (idx < beforeIdx) + beforeIdx -= 1; + + resourcePrefix->m_resourceFiles.insert(beforeIdx, resourceFile); + + emit resourceFileMoved(resourceFile, oldBefore); +} + +void QtQrcManager::changeResourceAlias(QtResourceFile *resourceFile, const QString &newAlias) +{ + if (!resourceFile) + return; + + const QString oldAlias = resourceFile->m_alias; + if (oldAlias == newAlias) + return; + + resourceFile->m_alias = newAlias; + + emit resourceAliasChanged(resourceFile, oldAlias); +} + +void QtQrcManager::removeResourceFile(QtResourceFile *resourceFile) +{ + QtResourcePrefix *resourcePrefix = resourcePrefixOf(resourceFile); + if (!resourcePrefix) + return; + + const int idx = resourcePrefix->m_resourceFiles.indexOf(resourceFile); + + emit resourceFileRemoved(resourceFile); + + resourcePrefix->m_resourceFiles.removeAt(idx); + m_fileToPrefix.remove(resourceFile); + const QString fullPath = resourceFile->fullPath(); + m_fullPathToResourceFiles[fullPath].removeAll(resourceFile); // optimize me + if (m_fullPathToResourceFiles[fullPath].isEmpty()) { + m_fullPathToResourceFiles.remove(fullPath); + m_fullPathToIcon.remove(fullPath); + m_fullPathToExists.remove(fullPath); + } + delete resourceFile; +} + + + +} + +// ----------------- QtResourceEditorDialogPrivate +class QtResourceEditorDialogPrivate +{ + QtResourceEditorDialog *q_ptr; + Q_DECLARE_PUBLIC(QtResourceEditorDialog) +public: + QtResourceEditorDialogPrivate(); + + void slotQrcFileInserted(QtQrcFile *qrcFile); + void slotQrcFileMoved(QtQrcFile *qrcFile); + void slotQrcFileRemoved(QtQrcFile *qrcFile); + + QStandardItem *insertResourcePrefix(QtResourcePrefix *resourcePrefix); + + void slotResourcePrefixInserted(QtResourcePrefix *resourcePrefix) { insertResourcePrefix(resourcePrefix); } + void slotResourcePrefixMoved(QtResourcePrefix *resourcePrefix); + void slotResourcePrefixChanged(QtResourcePrefix *resourcePrefix); + void slotResourceLanguageChanged(QtResourcePrefix *resourcePrefix); + void slotResourcePrefixRemoved(QtResourcePrefix *resourcePrefix); + void slotResourceFileInserted(QtResourceFile *resourceFile); + void slotResourceFileMoved(QtResourceFile *resourceFile); + void slotResourceAliasChanged(QtResourceFile *resourceFile); + void slotResourceFileRemoved(QtResourceFile *resourceFile); + + void slotCurrentQrcFileChanged(QListWidgetItem *item); + void slotCurrentTreeViewItemChanged(const QModelIndex &index); + void slotListWidgetContextMenuRequested(const QPoint &pos); + void slotTreeViewContextMenuRequested(const QPoint &pos); + void slotTreeViewItemChanged(QStandardItem *item); + + void slotNewQrcFile(); + void slotImportQrcFile(); + void slotRemoveQrcFile(); + void slotMoveUpQrcFile(); + void slotMoveDownQrcFile(); + + void slotNewPrefix(); + void slotAddFiles(); + void slotChangePrefix(); + void slotChangeLanguage(); + void slotChangeAlias(); + void slotClonePrefix(); + void slotRemove(); + void slotMoveUp(); + void slotMoveDown(); + + bool loadQrcFile(const QString &path, QtQrcFileData *qrcFileData, QString *errorMessage); + bool loadQrcFile(const QString &path, QtQrcFileData *qrcFileData); + bool saveQrcFile(const QtQrcFileData &qrcFileData); + + QString qrcFileText(QtQrcFile *qrcFile) const; + + QMessageBox::StandardButton warning(const QString &title, const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, + QMessageBox::StandardButton defaultButton = QMessageBox::NoButton) const; + + QString browseForNewLocation(const QString &resourceFile, const QDir &rootDir) const; + QString copyResourceFile(const QString &resourceFile, const QString &destPath) const; + QtResourceFile *getCurrentResourceFile() const; + QtResourcePrefix *getCurrentResourcePrefix() const; + void selectTreeRow(QStandardItem *item); + QString getSaveFileNameWithExtension(QWidget *parent, + const QString &title, QString dir, const QString &filter, const QString &extension) const; + QString qrcStartDirectory() const; + + Ui::QtResourceEditorDialog m_ui; + QDesignerFormEditorInterface *m_core; + QtResourceModel *m_resourceModel; + QDesignerDialogGuiInterface *m_dlgGui; + QtQrcManager *m_qrcManager; + QList m_initialState; + + QMap m_qrcFileToItem; + QMap m_itemToQrcFile; + QMap m_resourcePrefixToPrefixItem; + QMap m_resourcePrefixToLanguageItem; + QMap m_prefixItemToResourcePrefix; + QMap m_languageItemToResourcePrefix; + QMap m_resourceFileToPathItem; + QMap m_resourceFileToAliasItem; + QMap m_pathItemToResourceFile; + QMap m_aliasItemToResourceFile; + + bool m_ignoreCurrentChanged; + bool m_firstQrcFileDialog; + QtQrcFile *m_currentQrcFile; + + QAction *m_newQrcFileAction; + QAction *m_importQrcFileAction; + QAction *m_removeQrcFileAction; + QAction *m_moveUpQrcFileAction; + QAction *m_moveDownQrcFileAction; + + QAction *m_newPrefixAction; + QAction *m_addResourceFileAction; + QAction *m_changePrefixAction; + QAction *m_changeLanguageAction; + QAction *m_changeAliasAction; + QAction *m_clonePrefixAction; + QAction *m_moveUpAction; + QAction *m_moveDownAction; + QAction *m_removeAction; + + QStandardItemModel *m_treeModel; + QItemSelectionModel *m_treeSelection; +}; + +QtResourceEditorDialogPrivate::QtResourceEditorDialogPrivate() : + q_ptr(0), + m_core(0), + m_resourceModel(0), + m_dlgGui(0), + m_qrcManager(0), + m_ignoreCurrentChanged(false), + m_firstQrcFileDialog(true), + m_currentQrcFile(0), + m_newQrcFileAction(0), + m_importQrcFileAction(0), + m_removeQrcFileAction(0), + m_moveUpQrcFileAction(0), + m_moveDownQrcFileAction(0), + m_newPrefixAction(0), + m_addResourceFileAction(0), + m_changePrefixAction(0), + m_changeLanguageAction(0), + m_changeAliasAction(0), + m_clonePrefixAction(0), + m_moveUpAction(0), + m_moveDownAction(0), + m_removeAction(0), + m_treeModel(0), + m_treeSelection(0) +{ +} + +QMessageBox::StandardButton QtResourceEditorDialogPrivate::warning(const QString &title, const QString &text, QMessageBox::StandardButtons buttons, + QMessageBox::StandardButton defaultButton) const +{ + return m_dlgGui->message(q_ptr, QDesignerDialogGuiInterface::ResourceEditorMessage, QMessageBox::Warning, title, text, buttons, defaultButton); +} + +QString QtResourceEditorDialogPrivate::qrcFileText(QtQrcFile *qrcFile) const +{ + const QString path = qrcFile->path(); + const QString fileName = qrcFile->fileName(); + const QFileInfo fi(path); + if (fi.exists() && !fi.isWritable()) + return QApplication::translate("QtResourceEditorDialog", "%1 [read-only]").arg(fileName); + if (!m_qrcManager->exists(qrcFile)) + return QApplication::translate("QtResourceEditorDialog", "%1 [missing]").arg(fileName); + return fileName; +} + +void QtResourceEditorDialogPrivate::slotQrcFileInserted(QtQrcFile *qrcFile) +{ + QListWidgetItem *currentItem = m_ui.qrcFileList->currentItem(); + int idx = m_ui.qrcFileList->count(); + QtQrcFile *nextQrcFile = m_qrcManager->nextQrcFile(qrcFile); + QListWidgetItem *nextItem = m_qrcFileToItem.value(nextQrcFile); + if (nextItem) { + const int row = m_ui.qrcFileList->row(nextItem); + if (row >= 0) + idx = row; + } + const QString path = qrcFile->path(); + QListWidgetItem *item = new QListWidgetItem(qrcFileText(qrcFile)); + item->setToolTip(path); + m_ignoreCurrentChanged = true; + m_ui.qrcFileList->insertItem(idx, item); + m_ui.qrcFileList->setCurrentItem(currentItem); + m_ignoreCurrentChanged = false; + m_qrcFileToItem[qrcFile] = item; + m_itemToQrcFile[item] = qrcFile; + if (!m_qrcManager->exists(qrcFile)) + item->setForeground(QBrush(Qt::red)); +} + +void QtResourceEditorDialogPrivate::slotQrcFileMoved(QtQrcFile *qrcFile) +{ + QListWidgetItem *currentItem = m_ui.qrcFileList->currentItem(); + QListWidgetItem *item = m_qrcFileToItem.value(qrcFile); + m_ignoreCurrentChanged = true; + m_ui.qrcFileList->takeItem(m_ui.qrcFileList->row(item)); + + int idx = m_ui.qrcFileList->count(); + QtQrcFile *nextQrcFile = m_qrcManager->nextQrcFile(qrcFile); + QListWidgetItem *nextItem = m_qrcFileToItem.value(nextQrcFile); + if (nextItem) { + int row = m_ui.qrcFileList->row(nextItem); + if (row >= 0) + idx = row; + } + m_ui.qrcFileList->insertItem(idx, item); + if (currentItem == item) + m_ui.qrcFileList->setCurrentItem(item); + m_ignoreCurrentChanged = false; +} + +void QtResourceEditorDialogPrivate::slotQrcFileRemoved(QtQrcFile *qrcFile) +{ + QListWidgetItem *item = m_qrcFileToItem.value(qrcFile); + if (item == m_ui.qrcFileList->currentItem()) + m_ui.qrcFileList->setCurrentItem(0); // this should trigger list view signal currentItemChanged(0), and slot should set m_currentQrcFile to 0 + m_ignoreCurrentChanged = true; + delete item; + m_ignoreCurrentChanged = false; + m_itemToQrcFile.remove(item); + m_qrcFileToItem.remove(qrcFile); +} + +QStandardItem *QtResourceEditorDialogPrivate::insertResourcePrefix(QtResourcePrefix *resourcePrefix) +{ + if (m_qrcManager->qrcFileOf(resourcePrefix) != m_currentQrcFile) + return 0; + + QtResourcePrefix *prevResourcePrefix = m_qrcManager->prevResourcePrefix(resourcePrefix); + QStandardItem *prevItem = m_resourcePrefixToPrefixItem.value(prevResourcePrefix); + + int row = 0; + if (prevItem) + row = m_treeModel->indexFromItem(prevItem).row() + 1; + + QStandardItem *prefixItem = new QStandardItem(); + QStandardItem *languageItem = new QStandardItem(); + QList items; + items << prefixItem; + items << languageItem; + m_treeModel->insertRow(row, items); + const QModelIndex newIndex = m_treeModel->indexFromItem(prefixItem); + m_ui.resourceTreeView->setExpanded(newIndex, true); + prefixItem->setFlags(prefixItem->flags() | Qt::ItemIsEditable); + languageItem->setFlags(languageItem->flags() | Qt::ItemIsEditable); + m_resourcePrefixToPrefixItem[resourcePrefix] = prefixItem; + m_resourcePrefixToLanguageItem[resourcePrefix] = languageItem; + m_prefixItemToResourcePrefix[prefixItem] = resourcePrefix; + m_languageItemToResourcePrefix[languageItem] = resourcePrefix; + slotResourcePrefixChanged(resourcePrefix); + slotResourceLanguageChanged(resourcePrefix); + return prefixItem; +} + +void QtResourceEditorDialogPrivate::slotResourcePrefixMoved(QtResourcePrefix *resourcePrefix) +{ + QStandardItem *prefixItem = m_resourcePrefixToPrefixItem.value(resourcePrefix); + if (!prefixItem) + return; + + QStandardItem *languageItem = m_resourcePrefixToLanguageItem.value(resourcePrefix); + if (!languageItem) + return; + + const QModelIndex index = m_treeModel->indexFromItem(prefixItem); + const bool expanded = m_ui.resourceTreeView->isExpanded(index); + m_ignoreCurrentChanged = true; + const QList items = m_treeModel->takeRow(index.row()); + + int row = m_treeModel->rowCount(); + QtResourcePrefix *nextResourcePrefix = m_qrcManager->nextResourcePrefix(resourcePrefix); + QStandardItem *nextItem = m_resourcePrefixToPrefixItem.value(nextResourcePrefix); + if (nextItem) + row = m_treeModel->indexFromItem(nextItem).row(); + m_treeModel->insertRow(row, items); + m_ignoreCurrentChanged = false; + m_ui.resourceTreeView->setExpanded(m_treeModel->indexFromItem(items.at(0)), expanded); +} + +void QtResourceEditorDialogPrivate::slotResourcePrefixChanged(QtResourcePrefix *resourcePrefix) +{ + QStandardItem *item = m_resourcePrefixToPrefixItem.value(resourcePrefix); + if (!item) + return; + + m_ignoreCurrentChanged = true; + QString prefix = resourcePrefix->prefix(); + if (prefix.isEmpty()) + prefix = QApplication::translate("QtResourceEditorDialog", "", 0, QApplication::UnicodeUTF8); + item->setText(prefix); + item->setToolTip(prefix); + m_ignoreCurrentChanged = false; +} + +void QtResourceEditorDialogPrivate::slotResourceLanguageChanged(QtResourcePrefix *resourcePrefix) +{ + QStandardItem *item = m_resourcePrefixToLanguageItem.value(resourcePrefix); + if (!item) + return; + + m_ignoreCurrentChanged = true; + const QString language = resourcePrefix->language(); + item->setText(language); + item->setToolTip(language); + + m_ignoreCurrentChanged = false; +} + +void QtResourceEditorDialogPrivate::slotResourcePrefixRemoved(QtResourcePrefix *resourcePrefix) +{ + QStandardItem *prefixItem = m_resourcePrefixToPrefixItem.value(resourcePrefix); + if (!prefixItem) + return; + + QStandardItem *languageItem = m_resourcePrefixToLanguageItem.value(resourcePrefix); + if (!languageItem) + return; + + m_ignoreCurrentChanged = true; + m_treeModel->takeRow(m_treeModel->indexFromItem(prefixItem).row()); + delete prefixItem; + delete languageItem; + m_ignoreCurrentChanged = false; + m_prefixItemToResourcePrefix.remove(prefixItem); + m_languageItemToResourcePrefix.remove(languageItem); + m_resourcePrefixToPrefixItem.remove(resourcePrefix); + m_resourcePrefixToLanguageItem.remove(resourcePrefix); +} + +void QtResourceEditorDialogPrivate::slotResourceFileInserted(QtResourceFile *resourceFile) +{ + QtResourcePrefix *resourcePrefix = m_qrcManager->resourcePrefixOf(resourceFile); + if (m_qrcManager->qrcFileOf(resourcePrefix) != m_currentQrcFile) + return; + + QtResourceFile *prevResourceFile = m_qrcManager->prevResourceFile(resourceFile); + QStandardItem *prevItem = m_resourceFileToPathItem.value(prevResourceFile); + + QStandardItem *pathItem = new QStandardItem(resourceFile->path()); + QStandardItem *aliasItem = new QStandardItem(); + QStandardItem *parentItem = m_resourcePrefixToPrefixItem.value(resourcePrefix); + QList items; + items << pathItem; + items << aliasItem; + + int row = 0; + if (prevItem) + row = m_treeModel->indexFromItem(prevItem).row() + 1; + + parentItem->insertRow(row, items); + + pathItem->setFlags(pathItem->flags() & ~Qt::ItemIsEditable); + aliasItem->setFlags(aliasItem->flags() | Qt::ItemIsEditable); + m_resourceFileToPathItem[resourceFile] = pathItem; + m_resourceFileToAliasItem[resourceFile] = aliasItem; + m_pathItemToResourceFile[pathItem] = resourceFile; + m_aliasItemToResourceFile[aliasItem] = resourceFile; + pathItem->setToolTip(resourceFile->path()); + pathItem->setIcon(m_qrcManager->icon(resourceFile->fullPath())); + if (!m_qrcManager->exists(resourceFile->fullPath())) { + pathItem->setText(QApplication::translate("QtResourceEditorDialog", "%1 [missing]").arg(resourceFile->path())); + QBrush redBrush(Qt::red); + pathItem->setForeground(redBrush); + aliasItem->setForeground(redBrush); + } + slotResourceAliasChanged(resourceFile); +} + +void QtResourceEditorDialogPrivate::slotResourceFileMoved(QtResourceFile *resourceFile) +{ + QStandardItem *pathItem = m_resourceFileToPathItem.value(resourceFile); + if (!pathItem) + return; + + QStandardItem *aliasItem = m_resourceFileToAliasItem.value(resourceFile); + if (!aliasItem) + return; + + QStandardItem *parentItem = pathItem->parent(); + m_ignoreCurrentChanged = true; + const QList items = parentItem->takeRow(m_treeModel->indexFromItem(pathItem).row()); + + int row = parentItem->rowCount(); + QtResourceFile *nextResourceFile = m_qrcManager->nextResourceFile(resourceFile); + QStandardItem *nextItem = m_resourceFileToPathItem.value(nextResourceFile); + if (nextItem) + row = m_treeModel->indexFromItem(nextItem).row(); + parentItem->insertRow(row, items); + m_ignoreCurrentChanged = false; +} + +void QtResourceEditorDialogPrivate::slotResourceAliasChanged(QtResourceFile *resourceFile) +{ + QStandardItem *item = m_resourceFileToAliasItem.value(resourceFile); + if (!item) + return; + + m_ignoreCurrentChanged = true; + const QString alias = resourceFile->alias(); + item->setText(alias); + item->setToolTip(alias); + + m_ignoreCurrentChanged = false; +} + +void QtResourceEditorDialogPrivate::slotResourceFileRemoved(QtResourceFile *resourceFile) +{ + QStandardItem *pathItem = m_resourceFileToPathItem.value(resourceFile); + if (!pathItem) + return; + + QStandardItem *aliasItem = m_resourceFileToAliasItem.value(resourceFile); + if (!aliasItem) + return; + + QStandardItem *parentItem = pathItem->parent(); + + m_ignoreCurrentChanged = true; + parentItem->takeRow(m_treeModel->indexFromItem(pathItem).row()); + delete pathItem; + delete aliasItem; + m_ignoreCurrentChanged = false; + m_pathItemToResourceFile.remove(pathItem); + m_aliasItemToResourceFile.remove(aliasItem); + m_resourceFileToPathItem.remove(resourceFile); + m_resourceFileToAliasItem.remove(resourceFile); +} + + +void QtResourceEditorDialogPrivate::slotCurrentQrcFileChanged(QListWidgetItem *item) +{ + if (m_ignoreCurrentChanged) + return; + + QtQrcFile *newCurrentQrcFile = m_itemToQrcFile.value(item); + + if (newCurrentQrcFile == m_currentQrcFile) + return; + + if (m_currentQrcFile) { + QMap currentPrefixList = m_resourcePrefixToPrefixItem; + QMapIterator itPrefix(currentPrefixList); + while (itPrefix.hasNext()) { + QtResourcePrefix *resourcePrefix = itPrefix.next().key(); + QList currentResourceFiles = resourcePrefix->resourceFiles(); + QListIterator itFile(currentResourceFiles); + while (itFile.hasNext()) + slotResourceFileRemoved(itFile.next()); + slotResourcePrefixRemoved(resourcePrefix); + } + } + + m_currentQrcFile = newCurrentQrcFile; + slotCurrentTreeViewItemChanged(QModelIndex()); + QStandardItem *firstPrefix = 0; // select first prefix + if (m_currentQrcFile) { + QList newPrefixList = m_currentQrcFile->resourcePrefixList(); + QListIterator itPrefix(newPrefixList); + while (itPrefix.hasNext()) { + QtResourcePrefix *resourcePrefix = itPrefix.next(); + if (QStandardItem *newPrefixItem = insertResourcePrefix(resourcePrefix)) + if (!firstPrefix) + firstPrefix = newPrefixItem; + QList newResourceFiles = resourcePrefix->resourceFiles(); + QListIterator itFile(newResourceFiles); + while (itFile.hasNext()) + slotResourceFileInserted(itFile.next()); + } + } + m_ui.resourceTreeView->setCurrentIndex(firstPrefix ? m_treeModel->indexFromItem(firstPrefix) : QModelIndex()); + + m_removeQrcFileAction->setEnabled(m_currentQrcFile); + m_moveUpQrcFileAction->setEnabled(m_currentQrcFile && m_qrcManager->prevQrcFile(m_currentQrcFile)); + m_moveDownQrcFileAction->setEnabled(m_currentQrcFile && m_qrcManager->nextQrcFile(m_currentQrcFile)); +} + +void QtResourceEditorDialogPrivate::slotCurrentTreeViewItemChanged(const QModelIndex &index) +{ + QStandardItem *item = m_treeModel->itemFromIndex(index); + QtResourceFile *resourceFile = m_pathItemToResourceFile.value(item); + if (!resourceFile) + resourceFile = m_aliasItemToResourceFile.value(item); + QtResourcePrefix *resourcePrefix = m_prefixItemToResourcePrefix.value(item); + if (!resourcePrefix) + resourcePrefix = m_languageItemToResourcePrefix.value(item); + + bool moveUpEnabled = false; + bool moveDownEnabled = false; + bool currentItem = resourceFile || resourcePrefix; + + if (resourceFile) { + if (m_qrcManager->prevResourceFile(resourceFile)) + moveUpEnabled = true; + if (m_qrcManager->nextResourceFile(resourceFile)) + moveDownEnabled = true; + } else if (resourcePrefix) { + if (m_qrcManager->prevResourcePrefix(resourcePrefix)) + moveUpEnabled = true; + if (m_qrcManager->nextResourcePrefix(resourcePrefix)) + moveDownEnabled = true; + } + + m_newPrefixAction->setEnabled(m_currentQrcFile); + m_addResourceFileAction->setEnabled(currentItem); + m_changePrefixAction->setEnabled(currentItem); + m_changeLanguageAction->setEnabled(currentItem); + m_changeAliasAction->setEnabled(resourceFile); + m_removeAction->setEnabled(currentItem); + m_moveUpAction->setEnabled(moveUpEnabled); + m_moveDownAction->setEnabled(moveDownEnabled); + m_clonePrefixAction->setEnabled(currentItem); +} + +void QtResourceEditorDialogPrivate::slotListWidgetContextMenuRequested(const QPoint &pos) +{ + QMenu menu(q_ptr); + menu.addAction(m_newQrcFileAction); + menu.addAction(m_importQrcFileAction); + menu.addAction(m_removeQrcFileAction); + menu.addSeparator(); + menu.addAction(m_moveUpQrcFileAction); + menu.addAction(m_moveDownQrcFileAction); + menu.exec(m_ui.qrcFileList->mapToGlobal(pos)); +} + +void QtResourceEditorDialogPrivate::slotTreeViewContextMenuRequested(const QPoint &pos) +{ + QMenu menu(q_ptr); + menu.addAction(m_newPrefixAction); + menu.addAction(m_addResourceFileAction); + menu.addAction(m_removeAction); + menu.addSeparator(); + menu.addAction(m_changePrefixAction); + menu.addAction(m_changeLanguageAction); + menu.addAction(m_changeAliasAction); + menu.addSeparator(); + menu.addAction(m_clonePrefixAction); + menu.addSeparator(); + menu.addAction(m_moveUpAction); + menu.addAction(m_moveDownAction); + menu.exec(m_ui.resourceTreeView->mapToGlobal(pos)); +} + +void QtResourceEditorDialogPrivate::slotTreeViewItemChanged(QStandardItem *item) +{ + if (m_ignoreCurrentChanged) + return; + + const QString newValue = item->text(); + QtResourceFile *resourceFile = m_aliasItemToResourceFile.value(item); + if (resourceFile) { + m_qrcManager->changeResourceAlias(resourceFile, newValue); + return; + } + + QtResourcePrefix *resourcePrefix = m_prefixItemToResourcePrefix.value(item); + if (resourcePrefix) { + m_qrcManager->changeResourcePrefix(resourcePrefix, newValue); + return; + } + + resourcePrefix = m_languageItemToResourcePrefix.value(item); + if (resourcePrefix) { + m_qrcManager->changeResourceLanguage(resourcePrefix, newValue); + return; + } +} + +QString QtResourceEditorDialogPrivate::getSaveFileNameWithExtension(QWidget *parent, + const QString &title, QString dir, const QString &filter, const QString &extension) const +{ + const QChar dot = QLatin1Char('.'); + + QString saveFile; + while (true) { + saveFile = m_dlgGui->getSaveFileName(parent, title, dir, filter, 0, QFileDialog::DontConfirmOverwrite); + if (saveFile.isEmpty()) + return saveFile; + + const QFileInfo fInfo(saveFile); + if (fInfo.suffix().isEmpty() && !fInfo.fileName().endsWith(dot)) { + saveFile += dot; + saveFile += extension; + } + + const QFileInfo fi(saveFile); + if (!fi.exists()) + break; + + if (warning(title, msgOverwrite(fi.fileName()), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) + break; + + dir = saveFile; + } + return saveFile; +} + +QString QtResourceEditorDialogPrivate::qrcStartDirectory() const +{ + if (!m_currentQrcFile) + return QString(); + const QDir dir = QFileInfo(m_currentQrcFile->path()).dir(); + return dir.exists() ? dir.absolutePath() : QString(); +} + +void QtResourceEditorDialogPrivate::slotNewQrcFile() +{ + const QString qrcPath = getSaveFileNameWithExtension(q_ptr, + QApplication::translate("QtResourceEditorDialog", "New Resource File", 0, QApplication::UnicodeUTF8), + m_firstQrcFileDialog ? qrcStartDirectory() : QString(), + QApplication::translate("QtResourceEditorDialog", "Resource files (*.qrc)", 0, QApplication::UnicodeUTF8), + QLatin1String("qrc")); + if (qrcPath.isEmpty()) + return; + + m_firstQrcFileDialog = false; + if (QtQrcFile *sameQrcFile = m_qrcManager->qrcFileOf(qrcPath)) { + // QMessageBox ??? + QListWidgetItem *item = m_qrcFileToItem.value(sameQrcFile); + m_ui.qrcFileList->setCurrentItem(item); + item->setSelected(true); + return; + } + + QtQrcFile *nextQrcFile = m_qrcManager->nextQrcFile(m_currentQrcFile); + + QtQrcFile *qrcFile = m_qrcManager->insertQrcFile(qrcPath, nextQrcFile, true); + m_ui.qrcFileList->setCurrentItem(m_qrcFileToItem.value(qrcFile)); +} + +void QtResourceEditorDialogPrivate::slotImportQrcFile() +{ + const QString qrcPath = m_dlgGui->getOpenFileName(q_ptr, + QApplication::translate("QtResourceEditorDialog", "Import Resource File", 0, QApplication::UnicodeUTF8), + m_firstQrcFileDialog ? qrcStartDirectory() : QString(), + QApplication::translate("QtResourceEditorDialog", "Resource files (*.qrc)", 0, QApplication::UnicodeUTF8)); + if (qrcPath.isEmpty()) + return; + m_firstQrcFileDialog = false; + if (QtQrcFile *sameQrcFile = m_qrcManager->qrcFileOf(qrcPath)) { + // QMessageBox ??? + QListWidgetItem *item = m_qrcFileToItem.value(sameQrcFile); + m_ui.qrcFileList->setCurrentItem(item); + item->setSelected(true); + return; + } + + QtQrcFile *nextQrcFile = m_qrcManager->nextQrcFile(m_currentQrcFile); + + QtQrcFileData qrcFileData; + loadQrcFile(qrcPath, &qrcFileData); + QtQrcFile *qrcFile = m_qrcManager->importQrcFile(qrcFileData, nextQrcFile); + m_ui.qrcFileList->setCurrentItem(m_qrcFileToItem.value(qrcFile)); +} + +void QtResourceEditorDialogPrivate::slotRemoveQrcFile() +{ + if (!m_currentQrcFile) + return; + + QtQrcFile *currentQrcFile = m_qrcManager->nextQrcFile(m_currentQrcFile); + if (!currentQrcFile) + currentQrcFile = m_qrcManager->prevQrcFile(m_currentQrcFile); + + m_qrcManager->removeQrcFile(m_currentQrcFile); + QListWidgetItem *item = m_qrcFileToItem.value(currentQrcFile); + if (item) { + m_ui.qrcFileList->setCurrentItem(item); + item->setSelected(true); + } +} + +void QtResourceEditorDialogPrivate::slotMoveUpQrcFile() +{ + if (!m_currentQrcFile) + return; + + QtQrcFile *prevQrcFile = m_qrcManager->prevQrcFile(m_currentQrcFile); + if (!prevQrcFile) + return; + + m_qrcManager->moveQrcFile(m_currentQrcFile, prevQrcFile); +} + +void QtResourceEditorDialogPrivate::slotMoveDownQrcFile() +{ + if (!m_currentQrcFile) + return; + + QtQrcFile *nextQrcFile = m_qrcManager->nextQrcFile(m_currentQrcFile); + if (!nextQrcFile) + return; + nextQrcFile = m_qrcManager->nextQrcFile(nextQrcFile); + + m_qrcManager->moveQrcFile(m_currentQrcFile, nextQrcFile); +} + +QtResourceFile *QtResourceEditorDialogPrivate::getCurrentResourceFile() const +{ + QStandardItem *currentItem = m_treeModel->itemFromIndex(m_treeSelection->currentIndex()); + + + QtResourceFile *currentResourceFile = 0; + if (currentItem) { + currentResourceFile = m_pathItemToResourceFile.value(currentItem); + if (!currentResourceFile) + currentResourceFile = m_aliasItemToResourceFile.value(currentItem); + } + return currentResourceFile; +} + +QtResourcePrefix *QtResourceEditorDialogPrivate::getCurrentResourcePrefix() const +{ + QStandardItem *currentItem = m_treeModel->itemFromIndex(m_treeSelection->currentIndex()); + + QtResourcePrefix *currentResourcePrefix = 0; + if (currentItem) { + currentResourcePrefix = m_prefixItemToResourcePrefix.value(currentItem); + if (!currentResourcePrefix) { + currentResourcePrefix = m_languageItemToResourcePrefix.value(currentItem); + if (!currentResourcePrefix) { + QtResourceFile *currentResourceFile = getCurrentResourceFile(); + if (currentResourceFile) + currentResourcePrefix = m_qrcManager->resourcePrefixOf(currentResourceFile); + } + } + } + return currentResourcePrefix; +} + +void QtResourceEditorDialogPrivate::selectTreeRow(QStandardItem *item) +{ + const QModelIndex index = m_treeModel->indexFromItem(item); + m_treeSelection->select(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); + m_treeSelection->setCurrentIndex(index, QItemSelectionModel::Select); +} + +void QtResourceEditorDialogPrivate::slotNewPrefix() +{ + if (!m_currentQrcFile) + return; + + QtResourcePrefix *currentResourcePrefix = getCurrentResourcePrefix(); + QtResourcePrefix *nextResourcePrefix = m_qrcManager->nextResourcePrefix(currentResourcePrefix); + QtResourcePrefix *newResourcePrefix = m_qrcManager->insertResourcePrefix(m_currentQrcFile, + QApplication::translate("QtResourceEditorDialog", "newPrefix", 0, QApplication::UnicodeUTF8), + QString(), nextResourcePrefix); + if (!newResourcePrefix) + return; + + QStandardItem *newItem = m_resourcePrefixToPrefixItem.value(newResourcePrefix); + if (!newItem) + return; + + const QModelIndex index = m_treeModel->indexFromItem(newItem); + selectTreeRow(newItem); + m_ui.resourceTreeView->edit(index); +} + +static inline QString outOfPathWarning(const QString &fname) +{ + return QApplication::translate("QtResourceEditorDialog", + "

Warning: The file

" + "

%1

" + "

is outside of the current resource file's parent directory.

").arg(fname); +} + +static inline QString outOfPathWarningInfo() +{ + return QApplication::translate("QtResourceEditorDialog", + "

To resolve the issue, press:

" + "" + "" + "" + "
Copyto copy the file to the resource file's parent directory.
Copy As...to copy the file into a subdirectory of the resource file's parent directory.
Keepto use its current location.
"); +} + +void QtResourceEditorDialogPrivate::slotAddFiles() +{ + if (!m_currentQrcFile) + return; + + QtResourcePrefix *currentResourcePrefix = getCurrentResourcePrefix(); + QtResourceFile *currentResourceFile = getCurrentResourceFile(); + if (!currentResourcePrefix) + return; + + QString initialPath = m_currentQrcFile->path(); + if (currentResourceFile) { + QFileInfo fi(currentResourceFile->fullPath()); + initialPath = fi.absolutePath(); + } + + const QStringList resourcePaths = m_dlgGui->getOpenImageFileNames(q_ptr, + QApplication::translate("QtResourceEditorDialog", "Add Files", 0, QApplication::UnicodeUTF8), + initialPath); + if (resourcePaths.isEmpty()) + return; + + QtResourceFile *nextResourceFile = m_qrcManager->nextResourceFile(currentResourceFile); + if (!currentResourceFile) { + QList resourceFiles = currentResourcePrefix->resourceFiles(); + if (resourceFiles.count() > 0) + nextResourceFile = resourceFiles.first(); + } + + const QFileInfo fi(m_currentQrcFile->path()); + const QString destDir = fi.absolutePath(); + const QDir dir(fi.absolutePath()); + QStringListIterator itResourcePath(resourcePaths); + while (itResourcePath.hasNext()) { + QString resourcePath = itResourcePath.next(); + QString relativePath = dir.relativeFilePath(resourcePath); + if (relativePath.startsWith(QLatin1String(".."))) { + QMessageBox msgBox(QMessageBox::Warning, + QApplication::translate("QtResourceEditorDialog", "Incorrect Path", 0, QApplication::UnicodeUTF8), + outOfPathWarning(relativePath), QMessageBox::Cancel); + msgBox.setInformativeText(outOfPathWarningInfo()); + QPushButton *copyButton = msgBox.addButton(QApplication::translate("QtResourceEditorDialog", + "Copy", 0, QApplication::UnicodeUTF8), QMessageBox::ActionRole); + QPushButton *copyAsButton = msgBox.addButton(QApplication::translate("QtResourceEditorDialog", + "Copy As...", 0, QApplication::UnicodeUTF8), QMessageBox::ActionRole); + QPushButton *keepButton = msgBox.addButton(QApplication::translate("QtResourceEditorDialog", + "Keep", 0, QApplication::UnicodeUTF8), QMessageBox::ActionRole); + QPushButton *skipButton = msgBox.addButton(QApplication::translate("QtResourceEditorDialog", + "Skip", 0, QApplication::UnicodeUTF8), QMessageBox::ActionRole); + msgBox.setEscapeButton(QMessageBox::Cancel); + msgBox.setDefaultButton(copyButton); + msgBox.exec(); + QString destPath; + if (msgBox.clickedButton() == keepButton) { + // nothing + } else if (msgBox.clickedButton() == copyButton) { + QFileInfo resInfo(resourcePath); + QDir dd(destDir); + destPath = dd.absoluteFilePath(resInfo.fileName()); + if (dd.exists(resInfo.fileName())) { + if (warning(QApplication::translate("QtResourceEditorDialog", "Copy", 0, QApplication::UnicodeUTF8), + msgOverwrite(resInfo.fileName()), + QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel) != QMessageBox::Yes) + continue; + } + resourcePath = copyResourceFile(resourcePath, destPath); // returns empty string in case copy failed or was canceled + } else if (msgBox.clickedButton() == copyAsButton) { + destPath = browseForNewLocation(resourcePath, dir); // returns empty string in case browsing was canceled + if (destPath.isEmpty()) + continue; + resourcePath = copyResourceFile(resourcePath, destPath); // returns empty string in case copy failed or was canceled + } else if (msgBox.clickedButton() == skipButton) { // skipped + continue; + } else { // canceled + return; + } + if (resourcePath.isEmpty()) + continue; + } + relativePath = dir.relativeFilePath(resourcePath); + QtResourceFile *newResourceFile = m_qrcManager->insertResourceFile(currentResourcePrefix, relativePath, QString(), nextResourceFile); + + QStandardItem *newItem = m_resourceFileToPathItem.value(newResourceFile); + if (newItem) + selectTreeRow(newItem); + } +} + +void QtResourceEditorDialogPrivate::slotChangePrefix() +{ + QtResourcePrefix *currentResourcePrefix = getCurrentResourcePrefix(); + if (!currentResourcePrefix) + return; + + QStandardItem *item = m_resourcePrefixToPrefixItem.value(currentResourcePrefix); + QModelIndex index = m_treeModel->indexFromItem(item); + selectTreeRow(item); + m_ui.resourceTreeView->scrollTo(index); + m_ui.resourceTreeView->edit(index); +} + +void QtResourceEditorDialogPrivate::slotChangeLanguage() +{ + QtResourcePrefix *currentResourcePrefix = getCurrentResourcePrefix(); + if (!currentResourcePrefix) + return; + + QStandardItem *item = m_resourcePrefixToLanguageItem.value(currentResourcePrefix); + QModelIndex index = m_treeModel->indexFromItem(item); + selectTreeRow(item); + m_ui.resourceTreeView->scrollTo(index); + m_ui.resourceTreeView->edit(index); +} + +void QtResourceEditorDialogPrivate::slotChangeAlias() +{ + QtResourceFile *currentResourceFile = getCurrentResourceFile(); + if (!currentResourceFile) + return; + + QStandardItem *item = m_resourceFileToAliasItem.value(currentResourceFile); + QModelIndex index = m_treeModel->indexFromItem(item); + selectTreeRow(item); + m_ui.resourceTreeView->scrollTo(index); + m_ui.resourceTreeView->edit(index); +} + +void QtResourceEditorDialogPrivate::slotClonePrefix() +{ + QtResourcePrefix *currentResourcePrefix = getCurrentResourcePrefix(); + if (!currentResourcePrefix) + return; + + bool ok; + QString suffix = QInputDialog::getText(q_ptr, QApplication::translate("QtResourceEditorDialog", "Clone Prefix", 0, QApplication::UnicodeUTF8), + QApplication::translate("QtResourceEditorDialog", "Enter the suffix which you want to add to the names of the cloned files.\n" + "This could for example be a language extension like \"_de\".", 0, QApplication::UnicodeUTF8), + QLineEdit::Normal, QString(), &ok); + if (!ok) + return; + + QtResourcePrefix *newResourcePrefix = m_qrcManager->insertResourcePrefix(m_currentQrcFile, currentResourcePrefix->prefix(), + currentResourcePrefix->language(), m_qrcManager->nextResourcePrefix(currentResourcePrefix)); + if (newResourcePrefix) { + QList files = currentResourcePrefix->resourceFiles(); + QListIterator itFile(files); + while (itFile.hasNext()) { + QtResourceFile *resourceFile = itFile.next(); + QString path = resourceFile->path(); + QFileInfo fi(path); + QDir dir(fi.dir()); + QString oldSuffix = fi.completeSuffix(); + if (!oldSuffix.isEmpty()) + oldSuffix = QLatin1Char('.') + oldSuffix; + const QString newBaseName = fi.baseName() + suffix + oldSuffix; + const QString newPath = QDir::cleanPath(dir.filePath(newBaseName)); + m_qrcManager->insertResourceFile(newResourcePrefix, newPath, + resourceFile->alias()); + } + } +} + +void QtResourceEditorDialogPrivate::slotRemove() +{ + QStandardItem *item = m_treeModel->itemFromIndex(m_treeSelection->currentIndex()); + if (!item) + return; + + QtResourceFile *resourceFile = m_pathItemToResourceFile.value(item); + if (!resourceFile) + resourceFile = m_aliasItemToResourceFile.value(item); + QtResourcePrefix *resourcePrefix = m_prefixItemToResourcePrefix.value(item); + if (!resourcePrefix) + resourcePrefix = m_languageItemToResourcePrefix.value(item); + + QStandardItem *newCurrentItem = 0; + + if (resourceFile) { + QtResourceFile *nextFile = m_qrcManager->nextResourceFile(resourceFile); + if (!nextFile) + nextFile = m_qrcManager->prevResourceFile(resourceFile); + newCurrentItem = m_resourceFileToPathItem.value(nextFile); + if (!newCurrentItem) + newCurrentItem = m_resourcePrefixToPrefixItem.value(m_qrcManager->resourcePrefixOf(resourceFile)); + } + if (!newCurrentItem) { + QtResourcePrefix *nextPrefix = m_qrcManager->nextResourcePrefix(resourcePrefix); + if (!nextPrefix) + nextPrefix = m_qrcManager->prevResourcePrefix(resourcePrefix); + newCurrentItem = m_resourcePrefixToPrefixItem.value(nextPrefix); + } + + selectTreeRow(newCurrentItem); + + if (resourcePrefix) + m_qrcManager->removeResourcePrefix(resourcePrefix); + else if (resourceFile) + m_qrcManager->removeResourceFile(resourceFile); +} + +void QtResourceEditorDialogPrivate::slotMoveUp() +{ + if (QtResourceFile *resourceFile = getCurrentResourceFile()) { + QtResourceFile *prevFile = m_qrcManager->prevResourceFile(resourceFile); + + if (!prevFile) + return; + + m_qrcManager->moveResourceFile(resourceFile, prevFile); + selectTreeRow(m_resourceFileToPathItem.value(resourceFile)); + } else if (QtResourcePrefix *resourcePrefix = getCurrentResourcePrefix()) { + QtResourcePrefix *prevPrefix = m_qrcManager->prevResourcePrefix(resourcePrefix); + + if (!prevPrefix) + return; + + m_qrcManager->moveResourcePrefix(resourcePrefix, prevPrefix); + selectTreeRow(m_resourcePrefixToPrefixItem.value(resourcePrefix)); + } +} + +void QtResourceEditorDialogPrivate::slotMoveDown() +{ + if (QtResourceFile *resourceFile = getCurrentResourceFile()) { + QtResourceFile *nextFile = m_qrcManager->nextResourceFile(resourceFile); + + if (!nextFile) + return; + + m_qrcManager->moveResourceFile(resourceFile, m_qrcManager->nextResourceFile(nextFile)); + selectTreeRow(m_resourceFileToPathItem.value(resourceFile)); + } else if (QtResourcePrefix *resourcePrefix = getCurrentResourcePrefix()) { + QtResourcePrefix *nextPrefix = m_qrcManager->nextResourcePrefix(resourcePrefix); + + if (!nextPrefix) + return; + + m_qrcManager->moveResourcePrefix(resourcePrefix, m_qrcManager->nextResourcePrefix(nextPrefix)); + selectTreeRow(m_resourcePrefixToPrefixItem.value(resourcePrefix)); + } +} + +QString QtResourceEditorDialogPrivate::browseForNewLocation(const QString &resourceFile, const QDir &rootDir) const +{ + QFileInfo fi(resourceFile); + const QString initialPath = rootDir.absoluteFilePath(fi.fileName()); + while (1) { + QString newPath = m_dlgGui->getSaveFileName(q_ptr, + QApplication::translate("QtResourceEditorDialog", "Copy As", 0, QApplication::UnicodeUTF8), + initialPath); + QString relativePath = rootDir.relativeFilePath(newPath); + if (relativePath.startsWith(QLatin1String(".."))) { + if (warning(QApplication::translate("QtResourceEditorDialog", "Copy As", 0, QApplication::UnicodeUTF8), + QApplication::translate("QtResourceEditorDialog", "

The selected file:

" + "

%1

is outside of the current resource file's directory:

%2

" + "

Please select another path within this directory.

", 0, + QApplication::UnicodeUTF8).arg(relativePath).arg(rootDir.absolutePath()), + QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok) != QMessageBox::Ok) + return QString(); + } else { + return newPath; + } + } + + return QString(); +} + +QString QtResourceEditorDialogPrivate::copyResourceFile(const QString &resourceFile, const QString &destPath) const +{ + QFileInfo fi(destPath); + if (fi.exists()) { + while (fi.exists() && !QFile::remove(destPath)) { + if (warning(QApplication::translate("QtResourceEditorDialog", "Copy", 0, QApplication::UnicodeUTF8), + QApplication::translate("QtResourceEditorDialog", "Could not overwrite %1.", 0, QApplication::UnicodeUTF8).arg(fi.fileName()), + QMessageBox::Retry | QMessageBox::Cancel, QMessageBox::Cancel) != QMessageBox::Retry) + return QString(); + } + } + while (!QFile::copy(resourceFile, destPath)) { + if (warning(QApplication::translate("QtResourceEditorDialog", "Copy", 0, QApplication::UnicodeUTF8), + QApplication::translate("QtResourceEditorDialog", "Could not copy\n%1\nto\n%2", + 0, QApplication::UnicodeUTF8).arg(resourceFile).arg(destPath), + QMessageBox::Retry | QMessageBox::Cancel, QMessageBox::Cancel) != QMessageBox::Retry) + return QString(); + } + return destPath; +} +bool QtResourceEditorDialogPrivate::loadQrcFile(const QString &path, QtQrcFileData *qrcFileData) +{ + QString errorMessage; + const bool rc = loadQrcFile(path, qrcFileData, &errorMessage); +// if (!rc) +// warning(QApplication::translate("QtResourceEditorDialog", "Resource File Load Error"), errorMessage); + return rc; +} +bool QtResourceEditorDialogPrivate::loadQrcFile(const QString &path, QtQrcFileData *qrcFileData, QString *errorMessage) +{ + if (!qrcFileData) + return false; + + qrcFileData->qrcPath = path; + + QFile file(path); + if (!file.open(QIODevice::ReadOnly)) { + // there is sufficient hint while loading a form and after opening the editor (qrc marked marked with red and with [missing] text) + //*errorMessage = QApplication::translate("QtResourceEditorDialog", "Unable to open %1 for reading: %2").arg(path).arg(file.errorString()); + return false; + } + + QByteArray dataArray = file.readAll(); + file.close(); + + QDomDocument doc; + int errLine, errCol; + if (!doc.setContent(dataArray, errorMessage, &errLine, &errCol)) { + *errorMessage = QCoreApplication::translate("QtResourceEditorDialog", "A parse error occurred at line %1, column %2 of %3:\n%4").arg(errLine).arg(errCol).arg(path).arg(*errorMessage); + return false; + } + + return loadQrcFileData(doc, path, qrcFileData, errorMessage); +} + +bool QtResourceEditorDialogPrivate::saveQrcFile(const QtQrcFileData &qrcFileData) +{ + QFile file(qrcFileData.qrcPath); + while (!file.open(QIODevice::WriteOnly)) { + QMessageBox msgBox(QMessageBox::Warning, + QApplication::translate("QtResourceEditorDialog", "Save Resource File", 0, QApplication::UnicodeUTF8), + QApplication::translate("QtResourceEditorDialog", "Could not write %1: %2", 0, QApplication::UnicodeUTF8).arg(qrcFileData.qrcPath).arg(file.errorString()), + QMessageBox::Cancel|QMessageBox::Ignore|QMessageBox::Retry); + msgBox.setEscapeButton(QMessageBox::Cancel); + msgBox.setDefaultButton(QMessageBox::Ignore); + switch (msgBox.exec()) { + case QMessageBox::Retry: + break; // nothing + case QMessageBox::Ignore: + return true; + default: + return false; + } + } + + QDomDocument doc = saveQrcFileData(qrcFileData); + + QByteArray dataArray = doc.toByteArray(2); + file.write(dataArray); + + file.close(); + return true; +} + +QtResourceEditorDialog::QtResourceEditorDialog(QDesignerFormEditorInterface *core, QDesignerDialogGuiInterface *dlgGui, QWidget *parent) + : QDialog(parent), d_ptr(new QtResourceEditorDialogPrivate()) +{ + d_ptr->q_ptr = this; + d_ptr->m_ui.setupUi(this); + d_ptr->m_qrcManager = new QtQrcManager(this); + d_ptr->m_dlgGui = dlgGui; + d_ptr->m_core = core; + + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + setWindowTitle(tr("Edit Resources")); + + connect(d_ptr->m_qrcManager, SIGNAL(qrcFileInserted(QtQrcFile*)), + this, SLOT(slotQrcFileInserted(QtQrcFile*))); + connect(d_ptr->m_qrcManager, SIGNAL(qrcFileMoved(QtQrcFile*,QtQrcFile*)), + this, SLOT(slotQrcFileMoved(QtQrcFile*))); + connect(d_ptr->m_qrcManager, SIGNAL(qrcFileRemoved(QtQrcFile*)), + this, SLOT(slotQrcFileRemoved(QtQrcFile*))); + connect(d_ptr->m_qrcManager, SIGNAL(resourcePrefixInserted(QtResourcePrefix*)), + this, SLOT(slotResourcePrefixInserted(QtResourcePrefix*))); + connect(d_ptr->m_qrcManager, SIGNAL(resourcePrefixMoved(QtResourcePrefix*,QtResourcePrefix*)), + this, SLOT(slotResourcePrefixMoved(QtResourcePrefix*))); + connect(d_ptr->m_qrcManager, SIGNAL(resourcePrefixChanged(QtResourcePrefix*,QString)), + this, SLOT(slotResourcePrefixChanged(QtResourcePrefix*))); + connect(d_ptr->m_qrcManager, SIGNAL(resourceLanguageChanged(QtResourcePrefix*,QString)), + this, SLOT(slotResourceLanguageChanged(QtResourcePrefix*))); + connect(d_ptr->m_qrcManager, SIGNAL(resourcePrefixRemoved(QtResourcePrefix*)), + this, SLOT(slotResourcePrefixRemoved(QtResourcePrefix*))); + connect(d_ptr->m_qrcManager, SIGNAL(resourceFileInserted(QtResourceFile*)), + this, SLOT(slotResourceFileInserted(QtResourceFile*))); + connect(d_ptr->m_qrcManager, SIGNAL(resourceFileMoved(QtResourceFile*,QtResourceFile*)), + this, SLOT(slotResourceFileMoved(QtResourceFile*))); + connect(d_ptr->m_qrcManager, SIGNAL(resourceAliasChanged(QtResourceFile*,QString)), + this, SLOT(slotResourceAliasChanged(QtResourceFile*))); + connect(d_ptr->m_qrcManager, SIGNAL(resourceFileRemoved(QtResourceFile*)), + this, SLOT(slotResourceFileRemoved(QtResourceFile*))); + + QIcon upIcon = qdesigner_internal::createIconSet(QString::fromUtf8("up.png")); + QIcon downIcon = qdesigner_internal::createIconSet(QString::fromUtf8("down.png")); + QIcon minusIcon = qdesigner_internal::createIconSet(QString::fromUtf8("minus-16.png")); + QIcon newIcon = qdesigner_internal::createIconSet(QString::fromUtf8("filenew-16.png")); + QIcon openIcon = qdesigner_internal::createIconSet(QString::fromUtf8("fileopen-16.png")); + QIcon removeIcon = qdesigner_internal::createIconSet(QString::fromUtf8("editdelete-16.png")); + QIcon addPrefixIcon = qdesigner_internal::createIconSet(QString::fromUtf8("prefix-add.png")); + + d_ptr->m_newQrcFileAction = new QAction(newIcon, tr("New..."), this); + d_ptr->m_newQrcFileAction->setToolTip(tr("New Resource File")); + d_ptr->m_importQrcFileAction = new QAction(openIcon, tr("Open..."), this); + d_ptr->m_importQrcFileAction->setToolTip(tr("Open Resource File")); + d_ptr->m_removeQrcFileAction = new QAction(removeIcon, tr("Remove"), this); + d_ptr->m_moveUpQrcFileAction = new QAction(upIcon, tr("Move Up"), this); + d_ptr->m_moveDownQrcFileAction = new QAction(downIcon, tr("Move Down"), this); + + d_ptr->m_newPrefixAction = new QAction(addPrefixIcon, tr("Add Prefix"), this); + d_ptr->m_newPrefixAction->setToolTip(tr("Add Prefix")); + d_ptr->m_addResourceFileAction = new QAction(openIcon, tr("Add Files..."), this); + d_ptr->m_changePrefixAction = new QAction(tr("Change Prefix"), this); + d_ptr->m_changeLanguageAction = new QAction(tr("Change Language"), this); + d_ptr->m_changeAliasAction = new QAction(tr("Change Alias"), this); + d_ptr->m_clonePrefixAction = new QAction(tr("Clone Prefix..."), this); + d_ptr->m_removeAction = new QAction(minusIcon, tr("Remove"), this); + d_ptr->m_moveUpAction = new QAction(upIcon, tr("Move Up"), this); + d_ptr->m_moveDownAction = new QAction(downIcon, tr("Move Down"), this); + + d_ptr->m_ui.newQrcButton->setDefaultAction(d_ptr->m_newQrcFileAction); + d_ptr->m_ui.importQrcButton->setDefaultAction(d_ptr->m_importQrcFileAction); + d_ptr->m_ui.removeQrcButton->setDefaultAction(d_ptr->m_removeQrcFileAction); + + d_ptr->m_ui.newResourceButton->setDefaultAction(d_ptr->m_newPrefixAction); + d_ptr->m_ui.addResourceButton->setDefaultAction(d_ptr->m_addResourceFileAction); + d_ptr->m_ui.removeResourceButton->setDefaultAction(d_ptr->m_removeAction); + + connect(d_ptr->m_newQrcFileAction, SIGNAL(triggered()), this, SLOT(slotNewQrcFile())); + connect(d_ptr->m_importQrcFileAction, SIGNAL(triggered()), this, SLOT(slotImportQrcFile())); + connect(d_ptr->m_removeQrcFileAction, SIGNAL(triggered()), this, SLOT(slotRemoveQrcFile())); + connect(d_ptr->m_moveUpQrcFileAction, SIGNAL(triggered()), this, SLOT(slotMoveUpQrcFile())); + connect(d_ptr->m_moveDownQrcFileAction, SIGNAL(triggered()), this, SLOT(slotMoveDownQrcFile())); + + connect(d_ptr->m_newPrefixAction, SIGNAL(triggered()), this, SLOT(slotNewPrefix())); + connect(d_ptr->m_addResourceFileAction, SIGNAL(triggered()), this, SLOT(slotAddFiles())); + connect(d_ptr->m_changePrefixAction, SIGNAL(triggered()), this, SLOT(slotChangePrefix())); + connect(d_ptr->m_changeLanguageAction, SIGNAL(triggered()), this, SLOT(slotChangeLanguage())); + connect(d_ptr->m_changeAliasAction, SIGNAL(triggered()), this, SLOT(slotChangeAlias())); + connect(d_ptr->m_clonePrefixAction, SIGNAL(triggered()), this, SLOT(slotClonePrefix())); + connect(d_ptr->m_removeAction, SIGNAL(triggered()), this, SLOT(slotRemove())); + connect(d_ptr->m_moveUpAction, SIGNAL(triggered()), this, SLOT(slotMoveUp())); + connect(d_ptr->m_moveDownAction, SIGNAL(triggered()), this, SLOT(slotMoveDown())); + + d_ptr->m_ui.qrcFileList->setContextMenuPolicy(Qt::CustomContextMenu); + connect(d_ptr->m_ui.qrcFileList, SIGNAL(customContextMenuRequested(QPoint)), + this, SLOT(slotListWidgetContextMenuRequested(QPoint))); + connect(d_ptr->m_ui.qrcFileList, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), + this, SLOT(slotCurrentQrcFileChanged(QListWidgetItem*))); + + d_ptr->m_treeModel = new QStandardItemModel(this); + d_ptr->m_treeModel->setColumnCount(2); + d_ptr->m_treeModel->setHorizontalHeaderItem(0, new QStandardItem(tr("Prefix / Path"))); + d_ptr->m_treeModel->setHorizontalHeaderItem(1, new QStandardItem(tr("Language / Alias"))); + d_ptr->m_ui.resourceTreeView->setModel(d_ptr->m_treeModel); + d_ptr->m_ui.resourceTreeView->setContextMenuPolicy(Qt::CustomContextMenu); + d_ptr->m_treeSelection = d_ptr->m_ui.resourceTreeView->selectionModel(); + connect(d_ptr->m_ui.resourceTreeView->header(), SIGNAL(sectionDoubleClicked(int)), d_ptr->m_ui.resourceTreeView, SLOT(resizeColumnToContents(int))); + d_ptr->m_ui.resourceTreeView->setTextElideMode(Qt::ElideLeft); + + connect(d_ptr->m_ui.resourceTreeView, SIGNAL(customContextMenuRequested(QPoint)), + this, SLOT(slotTreeViewContextMenuRequested(QPoint))); + connect(d_ptr->m_treeModel, SIGNAL(itemChanged(QStandardItem*)), + this, SLOT(slotTreeViewItemChanged(QStandardItem*))); + connect(d_ptr->m_treeSelection, SIGNAL(currentChanged(QModelIndex,QModelIndex)), + this, SLOT(slotCurrentTreeViewItemChanged(QModelIndex))); + + d_ptr->m_ui.resourceTreeView->setColumnWidth(0, 200); + + d_ptr->slotCurrentTreeViewItemChanged(QModelIndex()); + d_ptr->m_removeQrcFileAction->setEnabled(false); + d_ptr->m_moveUpQrcFileAction->setEnabled(false); + d_ptr->m_moveDownQrcFileAction->setEnabled(false); + + QDesignerSettingsInterface *settings = core->settingsManager(); + settings->beginGroup(QLatin1String(QrcDialogC)); + + d_ptr->m_ui.splitter->restoreState(settings->value(QLatin1String(SplitterPosition)).toByteArray()); + if (settings->contains(QLatin1String(Geometry))) + setGeometry(settings->value(QLatin1String(Geometry)).toRect()); + + settings->endGroup(); +} + +QtResourceEditorDialog::~QtResourceEditorDialog() +{ + QDesignerSettingsInterface *settings = d_ptr->m_core->settingsManager(); + settings->beginGroup(QLatin1String(QrcDialogC)); + + settings->setValue(QLatin1String(SplitterPosition), d_ptr->m_ui.splitter->saveState()); + settings->setValue(QLatin1String(Geometry), geometry()); + settings->endGroup(); +} + +QtResourceModel *QtResourceEditorDialog::model() const +{ + return d_ptr->m_resourceModel; +} + +void QtResourceEditorDialog::setResourceModel(QtResourceModel *model) +{ + d_ptr->m_resourceModel = model; + + QtResourceSet *resourceSet = d_ptr->m_resourceModel->currentResourceSet(); + if (!resourceSet) { + // disable everything but cancel button + return; + } + + d_ptr->m_initialState.clear(); + + // enable qrcBox + + QStringList paths = resourceSet->activeQrcPaths(); + QStringListIterator it(paths); + while (it.hasNext()) { + const QString path = it.next(); + QtQrcFileData qrcFileData; + d_ptr->loadQrcFile(path, &qrcFileData); + d_ptr->m_initialState << qrcFileData; + d_ptr->m_qrcManager->importQrcFile(qrcFileData); + } + if (d_ptr->m_ui.qrcFileList->count() > 0) { + d_ptr->m_ui.qrcFileList->item(0)->setSelected(true); + } +} + +QString QtResourceEditorDialog::selectedResource() const +{ + //QtResourcePrefix *currentResourcePrefix = d_ptr->m_qrcManager->resourcePrefixOf(currentResourceFile); + QtResourcePrefix *currentResourcePrefix = d_ptr->getCurrentResourcePrefix(); + if (!currentResourcePrefix) + return QString(); + + const QChar slash(QLatin1Char('/')); + QString resource = currentResourcePrefix->prefix(); + if (!resource.startsWith(slash)) + resource.prepend(slash); + if (!resource.endsWith(slash)) + resource.append(slash); + resource.prepend(QLatin1Char(':')); + + QtResourceFile *currentResourceFile = d_ptr->getCurrentResourceFile(); + if (!currentResourceFile) + return resource; + + QString resourceEnding = currentResourceFile->path(); + if (!currentResourceFile->alias().isEmpty()) + resourceEnding = currentResourceFile->alias(); + + const QString dotSlash(QLatin1String("./")); + const QString dotDotSlash(QLatin1String("../")); + while (1) { + if (resourceEnding.startsWith(slash)) + resourceEnding = resourceEnding.mid(1); + else if (resourceEnding.startsWith(dotSlash)) + resourceEnding = resourceEnding.mid(dotSlash.count()); + else if (resourceEnding.startsWith(dotDotSlash)) + resourceEnding = resourceEnding.mid(dotDotSlash.count()); + else + break; + } + + resource.append(resourceEnding); + + return resource; +} + +void QtResourceEditorDialog::displayResourceFailures(const QString &logOutput, QDesignerDialogGuiInterface *dlgGui, QWidget *parent) +{ + const QString msg = tr("

Warning: There have been problems while reloading the resources:

%1
").arg(logOutput); + dlgGui->message(parent, QDesignerDialogGuiInterface::ResourceEditorMessage, QMessageBox::Warning, + tr("Resource Warning"), msg); +} + +void QtResourceEditorDialog::accept() +{ + QStringList newQrcPaths; + QList currentState; + + QList qrcFiles = d_ptr->m_qrcManager->qrcFiles(); + QListIterator itQrc(qrcFiles); + while (itQrc.hasNext()) { + QtQrcFile *qrcFile = itQrc.next(); + QtQrcFileData qrcFileData; + d_ptr->m_qrcManager->exportQrcFile(qrcFile, &qrcFileData); + currentState << qrcFileData; + if (qrcFileData == qrcFile->initialState()) { + // nothing + } else { + d_ptr->m_resourceModel->setWatcherEnabled(qrcFileData.qrcPath, false); + bool ok = d_ptr->saveQrcFile(qrcFileData); + d_ptr->m_resourceModel->setWatcherEnabled(qrcFileData.qrcPath, true); + if (!ok) + return; + + d_ptr->m_resourceModel->setModified(qrcFileData.qrcPath); + } + newQrcPaths << qrcFileData.qrcPath; + } + + if (currentState == d_ptr->m_initialState) { + // nothing + } else { + int errorCount; + QString errorMessages; + d_ptr->m_resourceModel->currentResourceSet()->activateQrcPaths(newQrcPaths, &errorCount, &errorMessages); + if (errorCount) + displayResourceFailures(errorMessages, d_ptr->m_dlgGui, this); + } + QDialog::accept(); +} + +QString QtResourceEditorDialog::editResources(QDesignerFormEditorInterface *core, + QtResourceModel *model, + QDesignerDialogGuiInterface *dlgGui, + QWidget *parent) +{ + QtResourceEditorDialog dialog(core, dlgGui, parent); + dialog.setResourceModel(model); + if (dialog.exec() == QDialog::Accepted) + return dialog.selectedResource(); + return QString(); +} + +QT_END_NAMESPACE + +#include "moc_qtresourceeditordialog_p.cpp" +#include "qtresourceeditordialog.moc" diff --git a/src/designer/src/lib/shared/qtresourceeditordialog.ui b/src/designer/src/lib/shared/qtresourceeditordialog.ui new file mode 100644 index 000000000..fa760d9a1 --- /dev/null +++ b/src/designer/src/lib/shared/qtresourceeditordialog.ui @@ -0,0 +1,177 @@ + + QtResourceEditorDialog + + + + 0 + 0 + 469 + 317 + + + + Dialog + + + + + + Qt::Horizontal + + + false + + + + + + + + 0 + 0 + + + + + + + + New File + + + N + + + + + + + Remove File + + + R + + + + + + + Qt::Horizontal + + + QSizePolicy::Ignored + + + + 21 + 20 + + + + + + + + I + + + + + + + + + + + + + + New Resource + + + N + + + + + + + A + + + + + + + Remove Resource or File + + + R + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + QtResourceEditorDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + QtResourceEditorDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/designer/src/lib/shared/qtresourceeditordialog_p.h b/src/designer/src/lib/shared/qtresourceeditordialog_p.h new file mode 100644 index 000000000..eef3bf540 --- /dev/null +++ b/src/designer/src/lib/shared/qtresourceeditordialog_p.h @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QTRESOURCEEDITOR_H +#define QTRESOURCEEDITOR_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class QtResourceModel; +class QDesignerDialogGuiInterface; +class QDesignerFormEditorInterface; + +class QtResourceEditorDialog : public QDialog +{ + Q_OBJECT +public: + QtResourceModel *model() const; + void setResourceModel(QtResourceModel *model); + + QString selectedResource() const; + + static QString editResources(QDesignerFormEditorInterface *core, QtResourceModel *model, + QDesignerDialogGuiInterface *dlgGui, QWidget *parent = 0); + + // Helper to display a message box with rcc logs in case of errors. + static void displayResourceFailures(const QString &logOutput, QDesignerDialogGuiInterface *dlgGui, QWidget *parent = 0); + +public slots: + virtual void accept(); + +private: + QtResourceEditorDialog(QDesignerFormEditorInterface *core, QDesignerDialogGuiInterface *dlgGui, QWidget *parent = 0); + ~QtResourceEditorDialog(); + + QScopedPointer d_ptr; + Q_DECLARE_PRIVATE(QtResourceEditorDialog) + Q_DISABLE_COPY(QtResourceEditorDialog) + + Q_PRIVATE_SLOT(d_func(), void slotQrcFileInserted(QtQrcFile *)) + Q_PRIVATE_SLOT(d_func(), void slotQrcFileMoved(QtQrcFile *)) + Q_PRIVATE_SLOT(d_func(), void slotQrcFileRemoved(QtQrcFile *)) + Q_PRIVATE_SLOT(d_func(), void slotResourcePrefixInserted(QtResourcePrefix *)) + Q_PRIVATE_SLOT(d_func(), void slotResourcePrefixMoved(QtResourcePrefix *)) + Q_PRIVATE_SLOT(d_func(), void slotResourcePrefixChanged(QtResourcePrefix *)) + Q_PRIVATE_SLOT(d_func(), void slotResourceLanguageChanged(QtResourcePrefix *)) + Q_PRIVATE_SLOT(d_func(), void slotResourcePrefixRemoved(QtResourcePrefix *)) + Q_PRIVATE_SLOT(d_func(), void slotResourceFileInserted(QtResourceFile *)) + Q_PRIVATE_SLOT(d_func(), void slotResourceFileMoved(QtResourceFile *)) + Q_PRIVATE_SLOT(d_func(), void slotResourceAliasChanged(QtResourceFile *)) + Q_PRIVATE_SLOT(d_func(), void slotResourceFileRemoved(QtResourceFile *)) + + Q_PRIVATE_SLOT(d_func(), void slotCurrentQrcFileChanged(QListWidgetItem *)) + Q_PRIVATE_SLOT(d_func(), void slotCurrentTreeViewItemChanged(const QModelIndex &)) + Q_PRIVATE_SLOT(d_func(), void slotListWidgetContextMenuRequested(const QPoint &)) + Q_PRIVATE_SLOT(d_func(), void slotTreeViewContextMenuRequested(const QPoint &)) + Q_PRIVATE_SLOT(d_func(), void slotTreeViewItemChanged(QStandardItem *)) + + Q_PRIVATE_SLOT(d_func(), void slotNewQrcFile()) + Q_PRIVATE_SLOT(d_func(), void slotImportQrcFile()) + Q_PRIVATE_SLOT(d_func(), void slotRemoveQrcFile()) + Q_PRIVATE_SLOT(d_func(), void slotMoveUpQrcFile()) + Q_PRIVATE_SLOT(d_func(), void slotMoveDownQrcFile()) + + Q_PRIVATE_SLOT(d_func(), void slotNewPrefix()) + Q_PRIVATE_SLOT(d_func(), void slotAddFiles()) + Q_PRIVATE_SLOT(d_func(), void slotChangePrefix()) + Q_PRIVATE_SLOT(d_func(), void slotChangeLanguage()) + Q_PRIVATE_SLOT(d_func(), void slotChangeAlias()) + Q_PRIVATE_SLOT(d_func(), void slotClonePrefix()) + Q_PRIVATE_SLOT(d_func(), void slotRemove()) + Q_PRIVATE_SLOT(d_func(), void slotMoveUp()) + Q_PRIVATE_SLOT(d_func(), void slotMoveDown()) +}; + +QT_END_NAMESPACE + +#endif + diff --git a/src/designer/src/lib/shared/qtresourcemodel.cpp b/src/designer/src/lib/shared/qtresourcemodel.cpp new file mode 100644 index 000000000..ca2fb7882 --- /dev/null +++ b/src/designer/src/lib/shared/qtresourcemodel.cpp @@ -0,0 +1,650 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtresourcemodel_p.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +enum { debugResourceModel = 0 }; + +// ------------------- QtResourceSetPrivate +class QtResourceSetPrivate +{ + QtResourceSet *q_ptr; + Q_DECLARE_PUBLIC(QtResourceSet) +public: + QtResourceSetPrivate(QtResourceModel *model = 0); + + QtResourceModel *m_resourceModel; +}; + +QtResourceSetPrivate::QtResourceSetPrivate(QtResourceModel *model) : + q_ptr(0), + m_resourceModel(model) +{ +} + +// -------------------- QtResourceModelPrivate +class QtResourceModelPrivate +{ + QtResourceModel *q_ptr; + Q_DECLARE_PUBLIC(QtResourceModel) + Q_DISABLE_COPY(QtResourceModelPrivate) +public: + QtResourceModelPrivate(); + void activate(QtResourceSet *resourceSet, const QStringList &newPaths, int *errorCount = 0, QString *errorMessages = 0); + void removeOldPaths(QtResourceSet *resourceSet, const QStringList &newPaths); + + QMap m_pathToModified; + QMap m_resourceSetToPaths; + QMap m_resourceSetToReload; // while path is recreated it needs to be reregistered + // (it is - in the new current resource set, but when the path was used in + // other resource set + // then later when that resource set is activated it needs to be reregistered) + QMap m_newlyCreated; // all created but not activated yet + // (if was active at some point and it's not now it will not be on that map) + QMap > m_pathToResourceSet; + QtResourceSet *m_currentResourceSet; + + typedef QMap PathDataMap; + PathDataMap m_pathToData; + + QMap m_pathToContents; // qrc path to its contents. + QMap m_fileToQrc; // this map contains the content of active resource set only. + // Activating different resource set changes the contents. + + QFileSystemWatcher *m_fileWatcher; + bool m_fileWatcherEnabled; + QMap m_fileWatchedMap; +private: + void registerResourceSet(QtResourceSet *resourceSet); + void unregisterResourceSet(QtResourceSet *resourceSet); + void setWatcherEnabled(const QString &path, bool enable); + void addWatcher(const QString &path); + void removeWatcher(const QString &path); + + void slotFileChanged(const QString &); + + const QByteArray *createResource(const QString &path, QStringList *contents, int *errorCount, QIODevice &errorDevice) const; + void deleteResource(const QByteArray *data) const; +}; + +QtResourceModelPrivate::QtResourceModelPrivate() : + q_ptr(0), + m_currentResourceSet(0), + m_fileWatcher(0), + m_fileWatcherEnabled(true) +{ +} + +// --------------------- QtResourceSet +QtResourceSet::QtResourceSet() : + d_ptr(new QtResourceSetPrivate) +{ + d_ptr->q_ptr = this; +} + +QtResourceSet::QtResourceSet(QtResourceModel *model) : + d_ptr(new QtResourceSetPrivate(model)) +{ + d_ptr->q_ptr = this; +} + +QtResourceSet::~QtResourceSet() +{ +} + +QStringList QtResourceSet::activeQrcPaths() const +{ + QtResourceSet *that = const_cast(this); + return d_ptr->m_resourceModel->d_ptr->m_resourceSetToPaths.value(that); +} + +void QtResourceSet::activateQrcPaths(const QStringList &paths, int *errorCount, QString *errorMessages) +{ + d_ptr->m_resourceModel->d_ptr->activate(this, paths, errorCount, errorMessages); +} + +bool QtResourceSet::isModified(const QString &path) const +{ + return d_ptr->m_resourceModel->isModified(path); +} + +void QtResourceSet::setModified(const QString &path) +{ + d_ptr->m_resourceModel->setModified(path); +} + +// ------------------- QtResourceModelPrivate +const QByteArray *QtResourceModelPrivate::createResource(const QString &path, QStringList *contents, int *errorCount, QIODevice &errorDevice) const +{ + typedef RCCResourceLibrary::ResourceDataFileMap ResourceDataFileMap; + const QByteArray *rc = 0; + *errorCount = -1; + contents->clear(); + do { + // run RCC + RCCResourceLibrary library; + library.setVerbose(true); + library.setInputFiles(QStringList(path)); + library.setFormat(RCCResourceLibrary::Binary); + + QBuffer buffer; + buffer.open(QIODevice::WriteOnly); + if (!library.readFiles(/* ignore errors*/ true, errorDevice)) + break; + // return code cannot be fully trusted, might still be empty + const ResourceDataFileMap resMap = library.resourceDataFileMap(); + if (!library.output(buffer, errorDevice)) + break; + + *errorCount = library.failedResources().size(); + *contents = resMap.keys(); + + if (resMap.empty()) + break; + + buffer.close(); + rc = new QByteArray(buffer.data()); + } while (false); + + if (debugResourceModel) + qDebug() << "createResource" << path << "returns data=" << rc << " hasWarnings=" << *errorCount; + return rc; +} + +void QtResourceModelPrivate::deleteResource(const QByteArray *data) const +{ + if (data) { + if (debugResourceModel) + qDebug() << "deleteResource"; + delete data; + } +} + +void QtResourceModelPrivate::registerResourceSet(QtResourceSet *resourceSet) +{ + if (!resourceSet) + return; + + // unregister old paths (all because the order of registration is important), later it can be optimized a bit + QStringList toRegister = resourceSet->activeQrcPaths(); + QStringListIterator itRegister(toRegister); + while (itRegister.hasNext()) { + const QString path = itRegister.next(); + if (debugResourceModel) + qDebug() << "registerResourceSet " << path; + const PathDataMap::const_iterator itRcc = m_pathToData.constFind(path); + if (itRcc != m_pathToData.constEnd()) { // otherwise data was not created yet + const QByteArray *data = itRcc.value(); + if (data) { + if (!QResource::registerResource(reinterpret_cast(data->constData()))) { + qWarning() << "** WARNING: Failed to register " << path << " (QResource failure)."; + } else { + QStringList contents = m_pathToContents.value(path); + QStringListIterator itContents(contents); + while (itContents.hasNext()) { + const QString filePath = itContents.next(); + if (!m_fileToQrc.contains(filePath)) // the first loaded resource has higher priority in qt resource system + m_fileToQrc.insert(filePath, path); + } + } + } + } + } +} + +void QtResourceModelPrivate::unregisterResourceSet(QtResourceSet *resourceSet) +{ + if (!resourceSet) + return; + + // unregister old paths (all because the order of registration is importans), later it can be optimized a bit + QStringList toUnregister = resourceSet->activeQrcPaths(); + QStringListIterator itUnregister(toUnregister); + while (itUnregister.hasNext()) { + const QString path = itUnregister.next(); + if (debugResourceModel) + qDebug() << "unregisterResourceSet " << path; + const PathDataMap::const_iterator itRcc = m_pathToData.constFind(path); + if (itRcc != m_pathToData.constEnd()) { // otherwise data was not created yet + const QByteArray *data = itRcc.value(); + if (data) { + if (!QResource::unregisterResource(reinterpret_cast(itRcc.value()->constData()))) + qWarning() << "** WARNING: Failed to unregister " << path << " (QResource failure)."; + } + } + } + m_fileToQrc.clear(); +} + +void QtResourceModelPrivate::activate(QtResourceSet *resourceSet, const QStringList &newPaths, int *errorCountPtr, QString *errorMessages) +{ + if (debugResourceModel) + qDebug() << "activate " << resourceSet; + if (errorCountPtr) + *errorCountPtr = 0; + if (errorMessages) + errorMessages->clear(); + + QBuffer errorStream; + errorStream.open(QIODevice::WriteOnly); + + int errorCount = 0; + int generatedCount = 0; + bool newResourceSetChanged = false; + + if (resourceSet && resourceSet->activeQrcPaths() != newPaths && !m_newlyCreated.contains(resourceSet)) + newResourceSetChanged = true; + + PathDataMap newPathToData = m_pathToData; + + QStringListIterator itPath(newPaths); + while (itPath.hasNext()) { + const QString path = itPath.next(); + if (resourceSet && !m_pathToResourceSet[path].contains(resourceSet)) + m_pathToResourceSet[path].append(resourceSet); + const QMap::iterator itMod = m_pathToModified.find(path); + if (itMod == m_pathToModified.end() || itMod.value()) { // new path or path is already created, but needs to be recreated + QStringList contents; + int qrcErrorCount; + generatedCount++; + const QByteArray *data = createResource(path, &contents, &qrcErrorCount, errorStream); + + newPathToData.insert(path, data); + if (qrcErrorCount) // Count single failed files as sort of 1/2 error + errorCount++; + addWatcher(path); + + m_pathToModified.insert(path, false); + m_pathToContents.insert(path, contents); + newResourceSetChanged = true; + const QMap >::iterator itReload = m_pathToResourceSet.find(path); + if (itReload != m_pathToResourceSet.end()) { + QList resources = itReload.value(); + QListIterator itRes(resources); + while (itRes.hasNext()) { + QtResourceSet *res = itRes.next(); + if (res != resourceSet) { + m_resourceSetToReload[res] = true; + } + } + } + } else { // path is already created, don't need to recreate + } + } + + QList oldData = m_pathToData.values(); + QList newData = newPathToData.values(); + + QList toDelete; + QListIterator itOld(oldData); + if (itOld.hasNext()) { + const QByteArray *array = itOld.next(); + if (array && !newData.contains(array)) + toDelete.append(array); + } + + // Nothing can fail below here? + if (generatedCount) { + if (errorCountPtr) + *errorCountPtr = errorCount; + errorStream.close(); + const QString stderrOutput = QString::fromUtf8(errorStream.data()); + if (debugResourceModel) + qDebug() << "Output: (" << errorCount << ")\n" << stderrOutput; + if (errorMessages) + *errorMessages = stderrOutput; + } + // register + const QMap::iterator itReload = m_resourceSetToReload.find(resourceSet); + if (itReload != m_resourceSetToReload.end()) { + if (itReload.value()) { + newResourceSetChanged = true; + m_resourceSetToReload.insert(resourceSet, false); + } + } + + QStringList oldActivePaths; + if (m_currentResourceSet) + oldActivePaths = m_currentResourceSet->activeQrcPaths(); + + const bool needReregister = (oldActivePaths != newPaths) || newResourceSetChanged; + + QMap::iterator itNew = m_newlyCreated.find(resourceSet); + if (itNew != m_newlyCreated.end()) { + m_newlyCreated.remove(resourceSet); + if (needReregister) + newResourceSetChanged = true; + } + + if (!newResourceSetChanged && !needReregister && (m_currentResourceSet == resourceSet)) { + foreach (const QByteArray *data, toDelete) + deleteResource(data); + + return; // nothing changed + } + + if (needReregister) + unregisterResourceSet(m_currentResourceSet); + + foreach (const QByteArray *data, toDelete) + deleteResource(data); + + m_pathToData = newPathToData; + m_currentResourceSet = resourceSet; + + if (resourceSet) + removeOldPaths(resourceSet, newPaths); + + if (needReregister) + registerResourceSet(m_currentResourceSet); + + emit q_ptr->resourceSetActivated(m_currentResourceSet, newResourceSetChanged); + + // deactivates the paths from old current resource set + // add new paths to the new current resource set + // reloads all paths which are marked as modified from the current resource set; + // activates the paths from current resource set + // emits resourceSetActivated() (don't emit only in case when old resource set is the same as new one + // AND no path was reloaded AND the list of paths is exactly the same) +} + +void QtResourceModelPrivate::removeOldPaths(QtResourceSet *resourceSet, const QStringList &newPaths) +{ + QStringList oldPaths = m_resourceSetToPaths.value(resourceSet); + if (oldPaths != newPaths) { + // remove old + QStringListIterator itOldPaths(oldPaths); + while (itOldPaths.hasNext()) { + QString oldPath = itOldPaths.next(); + if (!newPaths.contains(oldPath)) { + const QMap >::iterator itRemove = m_pathToResourceSet.find(oldPath); + if (itRemove != m_pathToResourceSet.end()) { + const int idx = itRemove.value().indexOf(resourceSet); + if (idx >= 0) + itRemove.value().removeAt(idx); + if (itRemove.value().count() == 0) { + PathDataMap::iterator it = m_pathToData.find(oldPath); + if (it != m_pathToData.end()) + deleteResource(it.value()); + m_pathToResourceSet.erase(itRemove); + m_pathToModified.remove(oldPath); + m_pathToContents.remove(oldPath); + m_pathToData.remove(oldPath); + removeWatcher(oldPath); + } + } + } + } + m_resourceSetToPaths[resourceSet] = newPaths; + } +} + +void QtResourceModelPrivate::setWatcherEnabled(const QString &path, bool enable) +{ + if (!enable) { + m_fileWatcher->removePath(path); + return; + } + + QFileInfo fi(path); + if (fi.exists()) + m_fileWatcher->addPath(path); +} + +void QtResourceModelPrivate::addWatcher(const QString &path) +{ + QMap::ConstIterator it = m_fileWatchedMap.constFind(path); + if (it != m_fileWatchedMap.constEnd() && it.value() == false) + return; + + m_fileWatchedMap.insert(path, true); + if (!m_fileWatcherEnabled) + return; + setWatcherEnabled(path, true); +} + +void QtResourceModelPrivate::removeWatcher(const QString &path) +{ + if (!m_fileWatchedMap.contains(path)) + return; + + m_fileWatchedMap.remove(path); + if (!m_fileWatcherEnabled) + return; + setWatcherEnabled(path, false); +} + +void QtResourceModelPrivate::slotFileChanged(const QString &path) +{ + setWatcherEnabled(path, false); + emit q_ptr->qrcFileModifiedExternally(path); + setWatcherEnabled(path, true); //readd +} + +// ----------------------- QtResourceModel +QtResourceModel::QtResourceModel(QObject *parent) : + QObject(parent), + d_ptr(new QtResourceModelPrivate) +{ + d_ptr->q_ptr = this; + + d_ptr->m_fileWatcher = new QFileSystemWatcher(this); + connect(d_ptr->m_fileWatcher, SIGNAL(fileChanged(QString)), + this, SLOT(slotFileChanged(QString))); +} + +QtResourceModel::~QtResourceModel() +{ + blockSignals(true); + QList resourceList = resourceSets(); + QListIterator it(resourceList); + while (it.hasNext()) + removeResourceSet(it.next()); + blockSignals(false); +} + +QStringList QtResourceModel::loadedQrcFiles() const +{ + return d_ptr->m_pathToModified.keys(); +} + +bool QtResourceModel::isModified(const QString &path) const +{ + QMap::const_iterator it = d_ptr->m_pathToModified.find(path); + if (it != d_ptr->m_pathToModified.constEnd()) + return it.value(); + return true; +} + +void QtResourceModel::setModified(const QString &path) +{ + QMap::const_iterator itMod = d_ptr->m_pathToModified.find(path); + if (itMod == d_ptr->m_pathToModified.constEnd()) + return; + + d_ptr->m_pathToModified[path] = true; + QMap >::const_iterator it = d_ptr->m_pathToResourceSet.constFind(path); + if (it == d_ptr->m_pathToResourceSet.constEnd()) + return; + + QList resourceList = it.value(); + QListIterator itReload(resourceList); + while (itReload.hasNext()) + d_ptr->m_resourceSetToReload.insert(itReload.next(), true); +} + +QList QtResourceModel::resourceSets() const +{ + return d_ptr->m_resourceSetToPaths.keys(); +} + +QtResourceSet *QtResourceModel::currentResourceSet() const +{ + return d_ptr->m_currentResourceSet; +} + +void QtResourceModel::setCurrentResourceSet(QtResourceSet *resourceSet, int *errorCount, QString *errorMessages) +{ + d_ptr->activate(resourceSet, d_ptr->m_resourceSetToPaths.value(resourceSet), errorCount, errorMessages); +} + +QtResourceSet *QtResourceModel::addResourceSet(const QStringList &paths) +{ + QtResourceSet *newResource = new QtResourceSet(this); + d_ptr->m_resourceSetToPaths.insert(newResource, paths); + d_ptr->m_resourceSetToReload.insert(newResource, false); + d_ptr->m_newlyCreated.insert(newResource, true); + QStringListIterator it(paths); + while (it.hasNext()) { + const QString path = it.next(); + d_ptr->m_pathToResourceSet[path].append(newResource); + } + return newResource; +} + +// TODO +void QtResourceModel::removeResourceSet(QtResourceSet *resourceSet) +{ + if (!resourceSet) + return; + if (currentResourceSet() == resourceSet) + setCurrentResourceSet(0); + + // remove rcc files for those paths which are not used in any other resource set + d_ptr->removeOldPaths(resourceSet, QStringList()); + + d_ptr->m_resourceSetToPaths.remove(resourceSet); + d_ptr->m_resourceSetToReload.remove(resourceSet); + d_ptr->m_newlyCreated.remove(resourceSet); + delete resourceSet; +} + +void QtResourceModel::reload(const QString &path, int *errorCount, QString *errorMessages) +{ + setModified(path); + + d_ptr->activate(d_ptr->m_currentResourceSet, d_ptr->m_resourceSetToPaths.value(d_ptr->m_currentResourceSet), errorCount, errorMessages); +} + +void QtResourceModel::reload(int *errorCount, QString *errorMessages) +{ + QMap::iterator it = d_ptr->m_pathToModified.begin(); + QMap::iterator itEnd = d_ptr->m_pathToModified.end(); // will it be valid when I iterate the map and change it??? + while (it != itEnd) { + it = d_ptr->m_pathToModified.insert(it.key(), true); + ++it; + } + + QMap::iterator itReload = d_ptr->m_resourceSetToReload.begin(); + QMap::iterator itReloadEnd = d_ptr->m_resourceSetToReload.end(); + while (itReload != itReloadEnd) { + itReload = d_ptr->m_resourceSetToReload.insert(itReload.key(), true); // empty resourceSets could be omitted here + ++itReload; + } + + d_ptr->activate(d_ptr->m_currentResourceSet, d_ptr->m_resourceSetToPaths.value(d_ptr->m_currentResourceSet), errorCount, errorMessages); +} + +QMap QtResourceModel::contents() const +{ + return d_ptr->m_fileToQrc; +} + +QString QtResourceModel::qrcPath(const QString &file) const +{ + return d_ptr->m_fileToQrc.value(file); +} + +void QtResourceModel::setWatcherEnabled(bool enable) +{ + if (d_ptr->m_fileWatcherEnabled == enable) + return; + + d_ptr->m_fileWatcherEnabled = enable; + + QMapIterator it(d_ptr->m_fileWatchedMap); + if (it.hasNext()) + d_ptr->setWatcherEnabled(it.next().key(), d_ptr->m_fileWatcherEnabled); +} + +bool QtResourceModel::isWatcherEnabled() const +{ + return d_ptr->m_fileWatcherEnabled; +} + +void QtResourceModel::setWatcherEnabled(const QString &path, bool enable) +{ + QMap::Iterator it = d_ptr->m_fileWatchedMap.find(path); + if (it == d_ptr->m_fileWatchedMap.end()) + return; + + if (it.value() == enable) + return; + + it.value() = enable; + + if (!d_ptr->m_fileWatcherEnabled) + return; + + d_ptr->setWatcherEnabled(it.key(), enable); +} + +bool QtResourceModel::isWatcherEnabled(const QString &path) +{ + return d_ptr->m_fileWatchedMap.value(path, false); +} + +QT_END_NAMESPACE + +#include "moc_qtresourcemodel_p.cpp" diff --git a/src/designer/src/lib/shared/qtresourcemodel_p.h b/src/designer/src/lib/shared/qtresourcemodel_p.h new file mode 100644 index 000000000..b1ddcca4a --- /dev/null +++ b/src/designer/src/lib/shared/qtresourcemodel_p.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QTRESOURCEMODEL_H +#define QTRESOURCEMODEL_H + +#include "shared_global_p.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QtResourceModel; + +class QDESIGNER_SHARED_EXPORT QtResourceSet // one instance per one form +{ +public: + QStringList activeQrcPaths() const; + + // activateQrcPaths(): if this QtResourceSet is active it emits resourceSetActivated(); + // otherwise only in case if active QtResource set contains one of + // paths which was marked as modified by this resource set, the signal + // is emitted (with reload = true); + // If new path appears on the list it is automatically added to + // loaded list of QtResourceModel. In addition it is marked as modified in case + // QtResourceModel didn't contain the path. + // If some path is removed from that list (and is not used in any other + // resource set) it is automatically unloaded. The removed file can also be + // marked as modified (later when another resource set which contains + // removed path is activated will be reloaded) + void activateQrcPaths(const QStringList &paths, int *errorCount = 0, QString *errorMessages = 0); + + bool isModified(const QString &path) const; // for all paths in resource model (redundant here, maybe it should be removed from here) + void setModified(const QString &path); // for all paths in resource model (redundant here, maybe it should be removed from here) +private: + QtResourceSet(); + QtResourceSet(QtResourceModel *model); + ~QtResourceSet(); + friend class QtResourceModel; + + QScopedPointer d_ptr; + Q_DECLARE_PRIVATE(QtResourceSet) + Q_DISABLE_COPY(QtResourceSet) +}; + +class QDESIGNER_SHARED_EXPORT QtResourceModel : public QObject // one instance per whole designer +{ + Q_OBJECT +public: + QtResourceModel(QObject *parent = 0); + ~QtResourceModel(); + + QStringList loadedQrcFiles() const; + bool isModified(const QString &path) const; // only for paths which are on loadedQrcFiles() list + void setModified(const QString &path); // only for paths which are on loadedQrcPaths() list + + QList resourceSets() const; + + QtResourceSet *currentResourceSet() const; + void setCurrentResourceSet(QtResourceSet *resourceSet, int *errorCount = 0, QString *errorMessages = 0); + + QtResourceSet *addResourceSet(const QStringList &paths); + void removeResourceSet(QtResourceSet *resourceSet); + + void reload(const QString &path, int *errorCount = 0, QString *errorMessages = 0); + void reload(int *errorCount = 0, QString *errorMessages = 0); + + // Contents of the current resource set (content file to qrc path) + QMap contents() const; + // Find the qrc file belonging to the contained file (from current resource set) + QString qrcPath(const QString &file) const; + + void setWatcherEnabled(bool enable); + bool isWatcherEnabled() const; + + void setWatcherEnabled(const QString &path, bool enable); + bool isWatcherEnabled(const QString &path); + +signals: + void resourceSetActivated(QtResourceSet *resourceSet, bool resourceSetChanged); // resourceSetChanged since last time it was activated! + void qrcFileModifiedExternally(const QString &path); + +private: + friend class QtResourceSet; + + QScopedPointer d_ptr; + Q_DECLARE_PRIVATE(QtResourceModel) + Q_DISABLE_COPY(QtResourceModel) + + Q_PRIVATE_SLOT(d_func(), void slotFileChanged(const QString &)) +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/designer/src/lib/shared/qtresourceview.cpp b/src/designer/src/lib/shared/qtresourceview.cpp new file mode 100644 index 000000000..040027355 --- /dev/null +++ b/src/designer/src/lib/shared/qtresourceview.cpp @@ -0,0 +1,906 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "abstractsettings_p.h" +#include "qtresourceview_p.h" +#include "qtresourcemodel_p.h" +#include "qtresourceeditordialog_p.h" +#include "iconloader_p.h" +#include "filterwidget_p.h" // For FilterWidget + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static const char *elementResourceData = "resource"; +static const char *typeAttribute = "type"; +static const char *typeImage = "image"; +static const char *typeStyleSheet = "stylesheet"; +static const char *typeOther = "other"; +static const char *fileAttribute = "file"; +static const char *SplitterPosition = "SplitterPosition"; +static const char *Geometry = "Geometry"; +static const char *ResourceViewDialogC = "ResourceDialog"; + +// ---------------- ResourceListWidget: A list widget that has drag enabled +class ResourceListWidget : public QListWidget { +public: + ResourceListWidget(QWidget *parent = 0); + +protected: + virtual void startDrag(Qt::DropActions supportedActions); +}; + +ResourceListWidget::ResourceListWidget(QWidget *parent) : + QListWidget(parent) +{ + setDragEnabled(true); +} + +void ResourceListWidget::startDrag(Qt::DropActions supportedActions) +{ + if (supportedActions == Qt::MoveAction) + return; + + QListWidgetItem *item = currentItem(); + if (!item) + return; + + const QString filePath = item->data(Qt::UserRole).toString(); + const QIcon icon = item->icon(); + + QMimeData *mimeData = new QMimeData; + const QtResourceView::ResourceType type = icon.isNull() ? QtResourceView::ResourceOther : QtResourceView::ResourceImage; + mimeData->setText(QtResourceView::encodeMimeData(type , filePath)); + + QDrag *drag = new QDrag(this); + if (!icon.isNull()) { + const QSize size = icon.actualSize(iconSize()); + drag->setPixmap(icon.pixmap(size)); + drag->setHotSpot(QPoint(size.width() / 2, size.height() / 2)); + } + + drag->setMimeData(mimeData); + drag->exec(Qt::CopyAction); +} + +/* TODO + + 1) load the icons in separate thread...Hmm..if Qt is configured with threads.... +*/ + +// ---------------------------- QtResourceViewPrivate +class QtResourceViewPrivate +{ + QtResourceView *q_ptr; + Q_DECLARE_PUBLIC(QtResourceView) +public: + QtResourceViewPrivate(QDesignerFormEditorInterface *core); + + void slotResourceSetActivated(QtResourceSet *resourceSet); + void slotCurrentPathChanged(QTreeWidgetItem *); + void slotCurrentResourceChanged(QListWidgetItem *); + void slotResourceActivated(QListWidgetItem *); + void slotEditResources(); + void slotReloadResources(); + void slotCopyResourcePath(); + void slotListWidgetContextMenuRequested(const QPoint &pos); + void slotFilterChanged(const QString &pattern); + void createPaths(); + QTreeWidgetItem *createPath(const QString &path, QTreeWidgetItem *parent); + void createResources(const QString &path); + void storeExpansionState(); + void applyExpansionState(); + void restoreSettings(); + void saveSettings(); + void updateActions(); + void filterOutResources(); + + QPixmap makeThumbnail(const QPixmap &pix) const; + + QDesignerFormEditorInterface *m_core; + QtResourceModel *m_resourceModel; + QToolBar *m_toolBar; + qdesigner_internal::FilterWidget *m_filterWidget; + QTreeWidget *m_treeWidget; + QListWidget *m_listWidget; + QSplitter *m_splitter; + QMap m_pathToContents; // full path to contents file names (full path to its resource filenames) + QMap m_pathToParentPath; // full path to full parent path + QMap m_pathToSubPaths; // full path to full sub paths + QMap m_pathToItem; + QMap m_itemToPath; + QMap m_resourceToItem; + QMap m_itemToResource; + QAction *m_editResourcesAction; + QAction *m_reloadResourcesAction; + QAction *m_copyResourcePathAction; + + QMap m_expansionState; + + bool m_ignoreGuiSignals; + QString m_settingsKey; + bool m_resourceEditingEnabled; + QString m_filterPattern; +}; + +QtResourceViewPrivate::QtResourceViewPrivate(QDesignerFormEditorInterface *core) : + q_ptr(0), + m_core(core), + m_resourceModel(0), + m_toolBar(new QToolBar), + m_treeWidget(new QTreeWidget), + m_listWidget(new ResourceListWidget), + m_splitter(0), + m_editResourcesAction(0), + m_reloadResourcesAction(0), + m_copyResourcePathAction(0), + m_ignoreGuiSignals(false), + m_resourceEditingEnabled(true) +{ +} + +void QtResourceViewPrivate::restoreSettings() +{ + if (m_settingsKey.isEmpty()) + return; + + QDesignerSettingsInterface *settings = m_core->settingsManager(); + settings->beginGroup(m_settingsKey); + + m_splitter->restoreState(settings->value(QLatin1String(SplitterPosition)).toByteArray()); + settings->endGroup(); +} + +void QtResourceViewPrivate::saveSettings() +{ + if (m_settingsKey.isEmpty()) + return; + + QDesignerSettingsInterface *settings = m_core->settingsManager(); + settings->beginGroup(m_settingsKey); + + settings->setValue(QLatin1String(SplitterPosition), m_splitter->saveState()); + settings->endGroup(); +} + +void QtResourceViewPrivate::slotEditResources() +{ + const QString selectedResource + = QtResourceEditorDialog::editResources(m_core, m_resourceModel, + m_core->dialogGui(), q_ptr); + if (!selectedResource.isEmpty()) + q_ptr->selectResource(selectedResource); +} + +void QtResourceViewPrivate::slotReloadResources() +{ + if (m_resourceModel) { + int errorCount; + QString errorMessages; + m_resourceModel->reload(&errorCount, &errorMessages); + if (errorCount) + QtResourceEditorDialog::displayResourceFailures(errorMessages, m_core->dialogGui(), q_ptr); + } +} + +void QtResourceViewPrivate::slotCopyResourcePath() +{ + const QString path = q_ptr->selectedResource(); + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(path); +} + +void QtResourceViewPrivate::slotListWidgetContextMenuRequested(const QPoint &pos) +{ + QMenu menu(q_ptr); + menu.addAction(m_copyResourcePathAction); + menu.exec(m_listWidget->mapToGlobal(pos)); +} + +void QtResourceViewPrivate::slotFilterChanged(const QString &pattern) +{ + m_filterPattern = pattern; + filterOutResources(); +} + +void QtResourceViewPrivate::storeExpansionState() +{ + QMapIterator it(m_pathToItem); + while (it.hasNext()) { + it.next(); + m_expansionState[it.key()] = it.value()->isExpanded(); + } +} + +void QtResourceViewPrivate::applyExpansionState() +{ + QMapIterator it(m_pathToItem); + while (it.hasNext()) { + it.next(); + it.value()->setExpanded(m_expansionState.value(it.key(), true)); + } +} + +QPixmap QtResourceViewPrivate::makeThumbnail(const QPixmap &pix) const +{ + int w = qMax(48, pix.width()); + int h = qMax(48, pix.height()); + QRect imgRect(0, 0, w, h); + QImage img(w, h, QImage::Format_ARGB32_Premultiplied); + img.fill(0); + if (!pix.isNull()) { + QRect r(0, 0, pix.width(), pix.height()); + r.moveCenter(imgRect.center()); + QPainter p(&img); + p.drawPixmap(r.topLeft(), pix); + } + return QPixmap::fromImage(img); +} + +void QtResourceViewPrivate::updateActions() +{ + bool resourceActive = false; + if (m_resourceModel) + resourceActive = m_resourceModel->currentResourceSet(); + + m_editResourcesAction->setVisible(m_resourceEditingEnabled); + m_editResourcesAction->setEnabled(resourceActive); + m_reloadResourcesAction->setEnabled(resourceActive); + m_filterWidget->setEnabled(resourceActive); +} + +void QtResourceViewPrivate::slotResourceSetActivated(QtResourceSet *resourceSet) +{ + Q_UNUSED(resourceSet) + + updateActions(); + + storeExpansionState(); + const QString currentPath = m_itemToPath.value(m_treeWidget->currentItem()); + const QString currentResource = m_itemToResource.value(m_listWidget->currentItem()); + m_treeWidget->clear(); + m_pathToContents.clear(); + m_pathToParentPath.clear(); + m_pathToSubPaths.clear(); + m_pathToItem.clear(); + m_itemToPath.clear(); + m_listWidget->clear(); + m_resourceToItem.clear(); + m_itemToResource.clear(); + + createPaths(); + applyExpansionState(); + + if (!currentResource.isEmpty()) + q_ptr->selectResource(currentResource); + else if (!currentPath.isEmpty()) + q_ptr->selectResource(currentPath); + filterOutResources(); +} + +void QtResourceViewPrivate::slotCurrentPathChanged(QTreeWidgetItem *item) +{ + if (m_ignoreGuiSignals) + return; + + m_listWidget->clear(); + m_resourceToItem.clear(); + m_itemToResource.clear(); + + if (!item) + return; + + const QString currentPath = m_itemToPath.value(item); + createResources(currentPath); +} + +void QtResourceViewPrivate::slotCurrentResourceChanged(QListWidgetItem *item) +{ + m_copyResourcePathAction->setEnabled(item); + if (m_ignoreGuiSignals) + return; + + emit q_ptr->resourceSelected(m_itemToResource.value(item)); +} + +void QtResourceViewPrivate::slotResourceActivated(QListWidgetItem *item) +{ + if (m_ignoreGuiSignals) + return; + + emit q_ptr->resourceActivated(m_itemToResource.value(item)); +} + +void QtResourceViewPrivate::createPaths() +{ + if (!m_resourceModel) + return; + + // Resource root up until 4.6 was ':', changed to ":/" as of 4.7 + const QString root(QLatin1String(":/")); + + QMap contents = m_resourceModel->contents(); + QMapIterator itContents(contents); + while (itContents.hasNext()) { + const QString filePath = itContents.next().key(); + const QFileInfo fi(filePath); + QString dirPath = fi.absolutePath(); + m_pathToContents[dirPath].append(fi.fileName()); + while (!m_pathToParentPath.contains(dirPath) && dirPath != root) { // create all parent paths + const QFileInfo fd(dirPath); + const QString parentDirPath = fd.absolutePath(); + m_pathToParentPath[dirPath] = parentDirPath; + m_pathToSubPaths[parentDirPath].append(dirPath); + dirPath = parentDirPath; + } + } + + QQueue > pathToParentItemQueue; + pathToParentItemQueue.enqueue(qMakePair(root, static_cast(0))); + while (!pathToParentItemQueue.isEmpty()) { + QPair pathToParentItem = pathToParentItemQueue.dequeue(); + const QString path = pathToParentItem.first; + QTreeWidgetItem *item = createPath(path, pathToParentItem.second); + QStringList subPaths = m_pathToSubPaths.value(path); + QStringListIterator itSubPaths(subPaths); + while (itSubPaths.hasNext()) + pathToParentItemQueue.enqueue(qMakePair(itSubPaths.next(), item)); + } +} + +void QtResourceViewPrivate::filterOutResources() +{ + QMap pathToMatchingContents; // true means the path has any matching contents + QMap pathToVisible; // true means the path has to be shown + + // 1) we go from root path recursively. + // 2) we check every path if it contains at least one matching resource - if empty we add it + // to pathToMatchingContents and pathToVisible with false, if non empty + // we add it with true and change every parent path in pathToVisible to true. + // 3) we hide these items which has pathToVisible value false. + + const bool matchAll = m_filterPattern.isEmpty(); + const QString root(QLatin1String(":/")); + + QQueue pathQueue; + pathQueue.enqueue(root); + while (!pathQueue.isEmpty()) { + const QString path = pathQueue.dequeue(); + + QStringList fileNames = m_pathToContents.value(path); + QStringListIterator it(fileNames); + bool hasContents = matchAll; + if (!matchAll) { // the case filter is not empty - we check if the path contains anything + while (it.hasNext()) { + QString fileName = it.next(); + hasContents = fileName.contains(m_filterPattern, Qt::CaseInsensitive); + if (hasContents) // the path contains at least one resource which matches the filter + break; + } + } + + pathToMatchingContents[path] = hasContents; + pathToVisible[path] = hasContents; + + if (hasContents) { // if the path is going to be shown we need to show all its parent paths + QString parentPath = m_pathToParentPath.value(path); + while (!parentPath.isEmpty()) { + QString p = parentPath; + if (pathToVisible.value(p)) // parent path is already shown, we break the loop + break; + pathToVisible[p] = true; + parentPath = m_pathToParentPath.value(p); + } + } + + QStringList subPaths = m_pathToSubPaths.value(path); // we do the same for children paths + QStringListIterator itSubPaths(subPaths); + while (itSubPaths.hasNext()) + pathQueue.enqueue(itSubPaths.next()); + } + + // we setup here new path and resource to be activated + const QString currentPath = m_itemToPath.value(m_treeWidget->currentItem()); + QString newCurrentPath = currentPath; + QString currentResource = m_itemToResource.value(m_listWidget->currentItem()); + if (!matchAll) { + bool searchForNewPathWithContents = true; + + if (!currentPath.isEmpty()) { // if the currentPath is empty we will search for a new path too + QMap::ConstIterator it = pathToMatchingContents.constFind(currentPath); + if (it != pathToMatchingContents.constEnd() && it.value()) // the current item has contents, we don't need to search for another path + searchForNewPathWithContents = false; + } + + if (searchForNewPathWithContents) { + // we find the first path with the matching contents + QMap::ConstIterator itContents = pathToMatchingContents.constBegin(); + while (itContents != pathToMatchingContents.constEnd()) { + if (itContents.value()) { + newCurrentPath = itContents.key(); // the new path will be activated + break; + } + + itContents++; + } + } + + QFileInfo fi(currentResource); + if (!fi.fileName().contains(m_filterPattern, Qt::CaseInsensitive)) { // the case when the current resource is filtered out + const QStringList fileNames = m_pathToContents.value(newCurrentPath); + QStringListIterator it(fileNames); + while (it.hasNext()) { // we try to select the first matching resource from the newCurrentPath + QString fileName = it.next(); + if (fileName.contains(m_filterPattern, Qt::CaseInsensitive)) { + QDir dirPath(newCurrentPath); + currentResource = dirPath.absoluteFilePath(fileName); // the new resource inside newCurrentPath will be activated + break; + } + } + } + } + + QTreeWidgetItem *newCurrentItem = m_pathToItem.value(newCurrentPath); + if (currentPath != newCurrentPath) + m_treeWidget->setCurrentItem(newCurrentItem); + else + slotCurrentPathChanged(newCurrentItem); // trigger filtering on the current path + + QListWidgetItem *currentResourceItem = m_resourceToItem.value(currentResource); + if (currentResourceItem) { + m_listWidget->setCurrentItem(currentResourceItem); + m_listWidget->scrollToItem(currentResourceItem); + } + + QMapIterator it(pathToVisible); // hide all paths filtered out + while (it.hasNext()) { + const QString path = it.next().key(); + QTreeWidgetItem *item = m_pathToItem.value(path); + if (item) + item->setHidden(!it.value()); + } +} + +QTreeWidgetItem *QtResourceViewPrivate::createPath(const QString &path, QTreeWidgetItem *parent) +{ + QTreeWidgetItem *item = 0; + if (parent) + item = new QTreeWidgetItem(parent); + else + item = new QTreeWidgetItem(m_treeWidget); + m_pathToItem[path] = item; + m_itemToPath[item] = path; + QString substPath; + if (parent) { + QFileInfo di(path); + substPath = di.fileName(); + } else { + substPath = QLatin1String(""); + } + item->setText(0, substPath); + item->setToolTip(0, path); + return item; +} + +void QtResourceViewPrivate::createResources(const QString &path) +{ + const bool matchAll = m_filterPattern.isEmpty(); + + QDir dir(path); + QStringList fileNames = m_pathToContents.value(path); + QStringListIterator it(fileNames); + while (it.hasNext()) { + QString fileName = it.next(); + const bool showProperty = matchAll || fileName.contains(m_filterPattern, Qt::CaseInsensitive); + if (showProperty) { + QString filePath = dir.absoluteFilePath(fileName); + QFileInfo fi(filePath); + if (fi.isFile()) { + QListWidgetItem *item = new QListWidgetItem(fi.fileName(), m_listWidget); + const QPixmap pix = QPixmap(filePath); + if (pix.isNull()) { + item->setToolTip(filePath); + } else { + item->setIcon(QIcon(makeThumbnail(pix))); + const QSize size = pix.size(); + item->setToolTip(QtResourceView::tr("Size: %1 x %2\n%3").arg(size.width()).arg(size.height()).arg(filePath)); + } + item->setFlags(item->flags() | Qt::ItemIsDragEnabled); + item->setData(Qt::UserRole, filePath); + m_itemToResource[item] = filePath; + m_resourceToItem[filePath] = item; + } + } + } +} + +// -------------- QtResourceView + +QtResourceView::QtResourceView(QDesignerFormEditorInterface *core, QWidget *parent) : + QWidget(parent), + d_ptr(new QtResourceViewPrivate(core)) +{ + d_ptr->q_ptr = this; + + QIcon editIcon = QIcon::fromTheme("document-properties", qdesigner_internal::createIconSet(QLatin1String("edit.png"))); + d_ptr->m_editResourcesAction = new QAction(editIcon, tr("Edit Resources..."), this); + d_ptr->m_toolBar->addAction(d_ptr->m_editResourcesAction); + connect(d_ptr->m_editResourcesAction, SIGNAL(triggered()), this, SLOT(slotEditResources())); + d_ptr->m_editResourcesAction->setEnabled(false); + + QIcon refreshIcon = QIcon::fromTheme("view-refresh", qdesigner_internal::createIconSet(QLatin1String("reload.png"))); + d_ptr->m_reloadResourcesAction = new QAction(refreshIcon, tr("Reload"), this); + + d_ptr->m_toolBar->addAction(d_ptr->m_reloadResourcesAction); + connect(d_ptr->m_reloadResourcesAction, SIGNAL(triggered()), this, SLOT(slotReloadResources())); + d_ptr->m_reloadResourcesAction->setEnabled(false); + + QIcon copyIcon = QIcon::fromTheme("edit-copy", qdesigner_internal::createIconSet(QLatin1String("editcopy.png"))); + d_ptr->m_copyResourcePathAction = new QAction(copyIcon, tr("Copy Path"), this); + connect(d_ptr->m_copyResourcePathAction, SIGNAL(triggered()), this, SLOT(slotCopyResourcePath())); + d_ptr->m_copyResourcePathAction->setEnabled(false); + + //d_ptr->m_filterWidget = new qdesigner_internal::FilterWidget(0, qdesigner_internal::FilterWidget::LayoutAlignNone); + d_ptr->m_filterWidget = new qdesigner_internal::FilterWidget(d_ptr->m_toolBar); + d_ptr->m_toolBar->addWidget(d_ptr->m_filterWidget); + connect(d_ptr->m_filterWidget, SIGNAL(filterChanged(QString)), this, SLOT(slotFilterChanged(QString))); + + d_ptr->m_splitter = new QSplitter; + d_ptr->m_splitter->setChildrenCollapsible(false); + d_ptr->m_splitter->addWidget(d_ptr->m_treeWidget); + d_ptr->m_splitter->addWidget(d_ptr->m_listWidget); + + QLayout *layout = new QVBoxLayout(this); + layout->setMargin(0); + layout->setSpacing(0); + layout->addWidget(d_ptr->m_toolBar); + layout->addWidget(d_ptr->m_splitter); + + d_ptr->m_treeWidget->setColumnCount(1); + d_ptr->m_treeWidget->header()->hide(); + d_ptr->m_treeWidget->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding)); + + d_ptr->m_listWidget->setViewMode(QListView::IconMode); + d_ptr->m_listWidget->setResizeMode(QListView::Adjust); + d_ptr->m_listWidget->setIconSize(QSize(48, 48)); + d_ptr->m_listWidget->setGridSize(QSize(64, 64)); + + connect(d_ptr->m_treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), + this, SLOT(slotCurrentPathChanged(QTreeWidgetItem*))); + connect(d_ptr->m_listWidget, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), + this, SLOT(slotCurrentResourceChanged(QListWidgetItem*))); + connect(d_ptr->m_listWidget, SIGNAL(itemActivated(QListWidgetItem*)), + this, SLOT(slotResourceActivated(QListWidgetItem*))); + d_ptr->m_listWidget->setContextMenuPolicy(Qt::CustomContextMenu); + connect(d_ptr->m_listWidget, SIGNAL(customContextMenuRequested(QPoint)), + this, SLOT(slotListWidgetContextMenuRequested(QPoint))); +} + +QtResourceView::~QtResourceView() +{ + if (!d_ptr->m_settingsKey.isEmpty()) + d_ptr->saveSettings(); +} + +bool QtResourceView::event(QEvent *event) +{ + if (event->type() == QEvent::Show) { + d_ptr->m_listWidget->scrollToItem(d_ptr->m_listWidget->currentItem()); + d_ptr->m_treeWidget->scrollToItem(d_ptr->m_treeWidget->currentItem()); + } + return QWidget::event(event); +} + +QtResourceModel *QtResourceView::model() const +{ + return d_ptr->m_resourceModel; +} + +QString QtResourceView::selectedResource() const +{ + QListWidgetItem *item = d_ptr->m_listWidget->currentItem(); + return d_ptr->m_itemToResource.value(item); +} + +void QtResourceView::selectResource(const QString &resource) +{ + if (resource.isEmpty()) + return; + QFileInfo fi(resource); + QDir dir = fi.absoluteDir(); + if (fi.isDir()) + dir = QDir(resource); + QString dirPath = dir.absolutePath(); + QMap::const_iterator it; + while ((it = d_ptr->m_pathToItem.find(dirPath)) == d_ptr->m_pathToItem.constEnd()) { + if (!dir.cdUp()) + break; + dirPath = dir.absolutePath(); + } + if (it != d_ptr->m_pathToItem.constEnd()) { + QTreeWidgetItem *treeItem = it.value(); + d_ptr->m_treeWidget->setCurrentItem(treeItem); + d_ptr->m_treeWidget->scrollToItem(treeItem); + // expand all up to current one is done by qt + // list widget is already propagated (currrent changed was sent by qt) + QListWidgetItem *item = d_ptr->m_resourceToItem.value(resource); + if (item) { + d_ptr->m_listWidget->setCurrentItem(item); + d_ptr->m_listWidget->scrollToItem(item); + } + } +} + +QString QtResourceView::settingsKey() const +{ + return d_ptr->m_settingsKey; +} + +void QtResourceView::setSettingsKey(const QString &key) +{ + if (d_ptr->m_settingsKey == key) + return; + + d_ptr->m_settingsKey = key; + + if (key.isEmpty()) + return; + + d_ptr->restoreSettings(); +} + +void QtResourceView::setResourceModel(QtResourceModel *model) +{ + if (d_ptr->m_resourceModel) { + disconnect(d_ptr->m_resourceModel, SIGNAL(resourceSetActivated(QtResourceSet*,bool)), + this, SLOT(slotResourceSetActivated(QtResourceSet*))); + } + + // clear here + d_ptr->m_treeWidget->clear(); + d_ptr->m_listWidget->clear(); + + d_ptr->m_resourceModel = model; + + if (!d_ptr->m_resourceModel) + return; + + connect(d_ptr->m_resourceModel, SIGNAL(resourceSetActivated(QtResourceSet*,bool)), + this, SLOT(slotResourceSetActivated(QtResourceSet*))); + + // fill new here + d_ptr->slotResourceSetActivated(d_ptr->m_resourceModel->currentResourceSet()); +} + +bool QtResourceView::isResourceEditingEnabled() const +{ + return d_ptr->m_resourceEditingEnabled; +} + +void QtResourceView::setResourceEditingEnabled(bool enable) +{ + d_ptr->m_resourceEditingEnabled = enable; + d_ptr->updateActions(); +} + +void QtResourceView::setDragEnabled(bool dragEnabled) +{ + d_ptr->m_listWidget->setDragEnabled(dragEnabled); +} + +bool QtResourceView::dragEnabled() const +{ + return d_ptr->m_listWidget->dragEnabled(); +} + +QString QtResourceView::encodeMimeData(ResourceType resourceType, const QString &path) +{ + QDomDocument doc; + QDomElement elem = doc.createElement(QLatin1String(elementResourceData)); + switch (resourceType) { + case ResourceImage: + elem.setAttribute(QLatin1String(typeAttribute), QLatin1String(typeImage)); + break; + case ResourceStyleSheet: + elem.setAttribute(QLatin1String(typeAttribute), QLatin1String(typeStyleSheet)); + break; + case ResourceOther: + elem.setAttribute(QLatin1String(typeAttribute), QLatin1String(typeOther)); + break; + } + elem.setAttribute(QLatin1String(fileAttribute), path); + doc.appendChild(elem); + return doc.toString(); +} + +bool QtResourceView::decodeMimeData(const QMimeData *md, ResourceType *t, QString *file) +{ + return md->hasText() ? decodeMimeData(md->text(), t, file) : false; +} + +bool QtResourceView::decodeMimeData(const QString &text, ResourceType *t, QString *file) +{ + + const QString docElementName = QLatin1String(elementResourceData); + static const QString docElementString = QLatin1Char('<') + docElementName; + + if (text.isEmpty() || text.indexOf(docElementString) == -1) + return false; + + QDomDocument doc; + if (!doc.setContent(text)) + return false; + + const QDomElement domElement = doc.documentElement(); + if (domElement.tagName() != docElementName) + return false; + + if (t) { + const QString typeAttr = QLatin1String(typeAttribute); + if (domElement.hasAttribute (typeAttr)) { + const QString typeValue = domElement.attribute(typeAttr, QLatin1String(typeOther)); + if (typeValue == QLatin1String(typeImage)) { + *t = ResourceImage; + } else { + *t = typeValue == QLatin1String(typeStyleSheet) ? ResourceStyleSheet : ResourceOther; + } + } + } + if (file) { + const QString fileAttr = QLatin1String(fileAttribute); + if (domElement.hasAttribute(fileAttr)) { + *file = domElement.attribute(fileAttr, QString()); + } else { + file->clear(); + } + } + return true; +} + +// ---------------------------- QtResourceViewDialogPrivate + +class QtResourceViewDialogPrivate +{ + QtResourceViewDialog *q_ptr; + Q_DECLARE_PUBLIC(QtResourceViewDialog) +public: + QtResourceViewDialogPrivate(QDesignerFormEditorInterface *core); + + void slotResourceSelected(const QString &resource) { setOkButtonEnabled(!resource.isEmpty()); } + void setOkButtonEnabled(bool v) { m_box->button(QDialogButtonBox::Ok)->setEnabled(v); } + + QDesignerFormEditorInterface *m_core; + QtResourceView *m_view; + QDialogButtonBox *m_box; +}; + +QtResourceViewDialogPrivate::QtResourceViewDialogPrivate(QDesignerFormEditorInterface *core) : + q_ptr(0), + m_core(core), + m_view(new QtResourceView(core)), + m_box(new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel)) +{ + m_view->setSettingsKey(QLatin1String(ResourceViewDialogC)); +} + +// ------------ QtResourceViewDialog +QtResourceViewDialog::QtResourceViewDialog(QDesignerFormEditorInterface *core, QWidget *parent) : + QDialog(parent), + d_ptr(new QtResourceViewDialogPrivate(core)) +{ + setWindowTitle(tr("Select Resource")); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + d_ptr->q_ptr = this; + QVBoxLayout *layout = new QVBoxLayout(this); + layout->addWidget(d_ptr->m_view); + layout->addWidget(d_ptr->m_box); + connect(d_ptr->m_box, SIGNAL(accepted()), this, SLOT(accept())); + connect(d_ptr->m_box, SIGNAL(rejected()), this, SLOT(reject())); + connect(d_ptr->m_view, SIGNAL(resourceActivated(QString)), this, SLOT(accept())); + connect(d_ptr->m_view, SIGNAL(resourceSelected(QString)), this, SLOT(slotResourceSelected(QString))); + d_ptr->setOkButtonEnabled(false); + d_ptr->m_view->setResourceModel(core->resourceModel()); + + QDesignerSettingsInterface *settings = core->settingsManager(); + settings->beginGroup(QLatin1String(ResourceViewDialogC)); + + if (settings->contains(QLatin1String(Geometry))) + setGeometry(settings->value(QLatin1String(Geometry)).toRect()); + + settings->endGroup(); +} + +QtResourceViewDialog::~QtResourceViewDialog() +{ + QDesignerSettingsInterface *settings = d_ptr->m_core->settingsManager(); + settings->beginGroup(QLatin1String(ResourceViewDialogC)); + + settings->setValue(QLatin1String(Geometry), geometry()); + + settings->endGroup(); +} + +QString QtResourceViewDialog::selectedResource() const +{ + return d_ptr->m_view->selectedResource(); +} + +void QtResourceViewDialog::selectResource(const QString &path) +{ + d_ptr->m_view->selectResource(path); +} + +bool QtResourceViewDialog::isResourceEditingEnabled() const +{ + return d_ptr->m_view->isResourceEditingEnabled(); +} + +void QtResourceViewDialog::setResourceEditingEnabled(bool enable) +{ + d_ptr->m_view->setResourceEditingEnabled(enable); +} + +QT_END_NAMESPACE + +#include "moc_qtresourceview_p.cpp" diff --git a/src/designer/src/lib/shared/qtresourceview_p.h b/src/designer/src/lib/shared/qtresourceview_p.h new file mode 100644 index 000000000..947df64e4 --- /dev/null +++ b/src/designer/src/lib/shared/qtresourceview_p.h @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of Qt Designer. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QTRESOURCEVIEW_H +#define QTRESOURCEVIEW_H + +#include "shared_global_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +class QtResourceModel; +class QtResourceSet; +class QDesignerFormEditorInterface; +class QMimeData; + +class QDESIGNER_SHARED_EXPORT QtResourceView : public QWidget +{ + Q_OBJECT +public: + explicit QtResourceView(QDesignerFormEditorInterface *core, QWidget *parent = 0); + ~QtResourceView(); + + void setDragEnabled(bool dragEnabled); + bool dragEnabled() const; + + QtResourceModel *model() const; + void setResourceModel(QtResourceModel *model); + + QString selectedResource() const; + void selectResource(const QString &resource); + + QString settingsKey() const; + void setSettingsKey(const QString &key); + + bool isResourceEditingEnabled() const; + void setResourceEditingEnabled(bool enable); + + // Helpers for handling the drag originating in QtResourceView (Xml/text) + enum ResourceType { ResourceImage, ResourceStyleSheet, ResourceOther }; + static QString encodeMimeData(ResourceType resourceType, const QString &path); + + static bool decodeMimeData(const QMimeData *md, ResourceType *t = 0, QString *file = 0); + static bool decodeMimeData(const QString &text, ResourceType *t = 0, QString *file = 0); + +signals: + void resourceSelected(const QString &resource); + void resourceActivated(const QString &resource); + +protected: + bool event(QEvent *event); + +private: + + QScopedPointer d_ptr; + Q_DECLARE_PRIVATE(QtResourceView) + Q_DISABLE_COPY(QtResourceView) + Q_PRIVATE_SLOT(d_func(), void slotResourceSetActivated(QtResourceSet *)) + Q_PRIVATE_SLOT(d_func(), void slotCurrentPathChanged(QTreeWidgetItem *)) + Q_PRIVATE_SLOT(d_func(), void slotCurrentResourceChanged(QListWidgetItem *)) + Q_PRIVATE_SLOT(d_func(), void slotResourceActivated(QListWidgetItem *)) + Q_PRIVATE_SLOT(d_func(), void slotEditResources()) + Q_PRIVATE_SLOT(d_func(), void slotReloadResources()) + Q_PRIVATE_SLOT(d_func(), void slotCopyResourcePath()) + Q_PRIVATE_SLOT(d_func(), void slotListWidgetContextMenuRequested(const QPoint &pos)) + Q_PRIVATE_SLOT(d_func(), void slotFilterChanged(const QString &pattern)) +}; + +class QDESIGNER_SHARED_EXPORT QtResourceViewDialog : public QDialog +{ + Q_OBJECT +public: + explicit QtResourceViewDialog(QDesignerFormEditorInterface *core, QWidget *parent = 0); + virtual ~QtResourceViewDialog(); + + QString selectedResource() const; + void selectResource(const QString &path); + + bool isResourceEditingEnabled() const; + void setResourceEditingEnabled(bool enable); + +private: + QScopedPointer d_ptr; + Q_DECLARE_PRIVATE(QtResourceViewDialog) + Q_DISABLE_COPY(QtResourceViewDialog) + Q_PRIVATE_SLOT(d_func(), void slotResourceSelected(const QString &)) +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/designer/src/lib/shared/richtexteditor.cpp b/src/designer/src/lib/shared/richtexteditor.cpp new file mode 100644 index 000000000..c2cdb2098 --- /dev/null +++ b/src/designer/src/lib/shared/richtexteditor.cpp @@ -0,0 +1,906 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Designer of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "richtexteditor_p.h" +#include "htmlhighlighter_p.h" +#include "iconselector_p.h" +#include "ui_addlinkdialog.h" +#include "abstractsettings_p.h" + +#include "iconloader_p.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static const char RichTextDialogGroupC[] = "RichTextDialog"; +static const char GeometryKeyC[] = "Geometry"; +static const char TabKeyC[] = "Tab"; + +const bool simplifyRichTextDefault = true; + +namespace qdesigner_internal { + +// Richtext simplification filter helpers: Elements to be discarded +static inline bool filterElement(const QStringRef &name) +{ + return name != QLatin1String("meta") && name != QLatin1String("style"); +} + +// Richtext simplification filter helpers: Filter attributes of elements +static inline void filterAttributes(const QStringRef &name, + QXmlStreamAttributes *atts, + bool *paragraphAlignmentFound) +{ + typedef QXmlStreamAttributes::iterator AttributeIt; + + if (atts->isEmpty()) + return; + + // No style attributes for + if (name == QLatin1String("body")) { + atts->clear(); + return; + } + + // Clean out everything except 'align' for 'p' + if (name == QLatin1String("p")) { + for (AttributeIt it = atts->begin(); it != atts->end(); ) { + if (it->name() == QLatin1String("align")) { + ++it; + *paragraphAlignmentFound = true; + } else { + it = atts->erase(it); + } + } + return; + } +} + +// Richtext simplification filter helpers: Check for blank QStringRef. +static inline bool isWhiteSpace(const QStringRef &in) +{ + const int count = in.size(); + for (int i = 0; i < count; i++) + if (!in.at(i).isSpace()) + return false; + return true; +} + +// Richtext simplification filter: Remove hard-coded font settings, +//