Quick Open: compare project files case-insensitively

Case-insensitive file order in the Quick Open list should be more
intuitive, especially for users of case-insensitive operating systems or
file systems. This new order is consistent with the file order in the
project tree. Quick Open filtering is also case-insensitive.

This change slows down ProjectFile's operator< because case-insensitive
QString comparison is more complex and significantly slower than the
default case-sensitive comparison. The slowdown is somewhat mitigated by
the case-insensitive sort order in FileManagerListJob::startNextJob(),
which makes the initial order of project files closer to sorted and
should improve Timsort performance. This presorting mitigation is not
sufficient to offset the case-insensitive order slowdown in practice,
and so the sorting in ProjectFileDataProvider::projectOpened() takes
much more time now. Of course, if the sort order in
FileManagerListJob::startNextJob() is changed to case-sensitive,
sorting ProjectFile objects case-sensitively becomes substantially
faster than even at the previous commit. But modifying startNextJob() in
this way slows down case-insensitive std::stable_sort-ing of the project
tree in QSortFilterProxyModel (inherited by ProjectProxyModel).

According to the benchmarks, when project files are compared case-
insensitively, Timsort is still much faster than any std or boost
sorting algorithm, and Timmerge is still much faster than

Comparing indexed paths instead of paths for equality in
ProjectFileDataProvider::fileAddedToSet() and
ProjectFileDataProvider::fileRemovedFromSet() should slightly improve
performance of these functions because, at the very least, there is no
pointer indirection in IndexedString::operator==. Note that
item.indexedPath must be initialized in fileRemovedFromSet() because
ProjectFile::indexedPath is now used in ProjectFile's operator<.

The following table compares the average time in milliseconds spent at
each step of ProjectFileDataProvider::projectOpened() at the previous
commit, this commit and at this commit but with the recent commit
"Quick Open: timsort and timmerge project files" reverted.

version\projects         k=>W     W=>k=>q    S=>(L=>W | W=>L)
Collecting               8+147  154+  8+ 21 27+103+158+172+ 99
Sorting (prev. commit)   5+130  133+  5+ 16 19+ 75+129+142+ 75
Sorting (this commit)    9+191  196+  9+ 27 18+102+191+206+101
Sorting (this, no tim*) 16+918  926+ 15+ 58 83+567+905+979+564
Merging (prev. commit)   0+  3    0+  0+  0  0+  3+211+ 41+205
Merging (this commit)    0+  0    0+ 12+ 10  0+  3+757+120+670
Merging (this, no tim*)  0+ 11    0+219+231  0+162+803+321+715
Removing dupl. (prev.)   0+  3    3+  1+ 2   0+  1+ 36+  7+ 32
Removing dupl. (this)    0+  4    4+  3+ 4   0+  1+ 37+  9+ 32

The notations used in this table are described under the similar table
in the recent commit "Quick Open: sort and merge project files".

The "Collecting" and "Removing duplicates" steps are not directly
affected by this commit's changes. The average time spent at the
"Collecting" step is practically the same at all three commits; the
average time spent at the "Removing duplicates" step is practically the
same at this commit and at this commit with tim* reverted. Thus several
identical rows are omitted from the table.

The striking differences between the previous and this commit at the
"Merging" step are partially caused by the different orders of project
files. For example, WebKit files used to precede but now succeed
kdevelop and qt-creator files after sorting because of the case-
insensitive path comparison.

The differences between the previous and this commit at the
"Removing duplicates" step must be caused by the altered distances
between the duplicates and the end of the sorted range due to case

The following table compares performance at the three commits in the
affected BenchQuickOpen::benchProjectFileFilter_addRemoveProject()
benchmark (in milliseconds per iteration).

version\benchmark       addRemoveProject(1000)  addRemoveProject(10000)
previous commit         0.36                    3.0
this commit             0.42                    3.7
this commit, no tim*    0.82                    9.6

The results of benchProjectFileFilter_addRemoveProjects() benchmark
fluctuate so wildly that the performance difference between the previous
and this commit is indiscernible.
1 job for !224 with fix-quickopen-crashes-optimized in 33 minutes and 15 seconds (queued for 77 minutes and 35 seconds)
Status Job ID Name Coverage
passed #91734
linux kf5-qt5 qt5.15