1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "recentfiles.h"
5#include "globals.h"
6
7#include <QtCore/QDebug>
8#include <QtCore/QFileInfo>
9#include <QtCore/QSettings>
10#include <QtCore/QString>
11#include <QtCore/QStringList>
12
13QT_BEGIN_NAMESPACE
14
15static QString configKey()
16{
17 return settingPath("RecentlyOpenedFiles");
18}
19
20
21RecentFiles::RecentFiles(const int maxEntries)
22 : m_groupOpen(false),
23 m_clone1st(false),
24 m_maxEntries(maxEntries)
25{
26 m_timer.setSingleShot(true);
27 m_timer.setInterval(3 * 60 * 1000);
28 connect(sender: &m_timer, signal: &QTimer::timeout,
29 context: this, slot: &RecentFiles::closeGroup);
30}
31
32/*
33 * The logic is as follows:
34 * - The most recent (i.e., topmost) item can be open ("in flux")
35 * - The item is closed by either a timeout (3 min or so) or a
36 * "terminal action" (e.g., closing all files)
37 * - While the item is open, modifications to the set of open files
38 * will modify that item instead of creating new items
39 * - If the open item is modified to be equal to an existing item,
40 * the existing item is deleted, but will be re-created when the
41 * open item is modified even further
42 * Cases (actions in parentheses are no-ops):
43 * - identical to top item => (do nothing)
44 * - closed, new item => insert at top, (clear marker)
45 * - closed, existing item => move to top, mark for cloning
46 * - open, new item, not marked => replace top, (clear marker)
47 * - open, new item, marked => insert at top, clear marker
48 * - open, existing item, not marked => replace top, delete copy, mark for cloning
49 * - open, existing item, marked => insert at top, delete copy, (mark for cloning)
50 * - closing clears marker
51 */
52void RecentFiles::addFiles(const QStringList &names)
53{
54 if (m_strLists.isEmpty() || names != m_strLists.first()) {
55 if (m_groupOpen && !m_clone1st)
56 // Group being open implies at least one item in the list
57 m_strLists.removeFirst();
58 m_groupOpen = true;
59
60 // We do *not* sort the actual entries, as that would destroy the user's
61 // chosen arrangement. However, we do the searching on sorted lists, so
62 // we throw out (probably) obsolete arrangements.
63 QList<QStringList> sortedLists = m_strLists;
64 for (int i = 0; i < sortedLists.size(); ++i)
65 sortedLists[i].sort();
66 QStringList sortedNames = names;
67 sortedNames.sort();
68
69 int index = sortedLists.indexOf(t: sortedNames);
70 if (index >= 0) {
71 m_strLists.removeAt(i: index);
72 m_clone1st = true;
73 } else {
74 if (m_strLists.size() >= m_maxEntries)
75 m_strLists.removeLast();
76 m_clone1st = false;
77 }
78 m_strLists.prepend(t: names);
79 }
80 m_timer.start();
81}
82
83void RecentFiles::closeGroup()
84{
85 m_timer.stop();
86 m_groupOpen = false;
87}
88
89void RecentFiles::readConfig()
90{
91 m_strLists.clear();
92 QVariant val = QSettings().value(key: configKey());
93 if (val.metaType().id() == QMetaType::QVariantList) {
94 const auto list = val.toList();
95 for (const QVariant &v : list)
96 m_strLists << v.toStringList();
97 }
98}
99
100void RecentFiles::writeConfig() const
101{
102 QList<QVariant> vals;
103 for (const QStringList &sl : m_strLists)
104 vals << sl;
105 QSettings().setValue(key: configKey(), value: vals);
106}
107
108QT_END_NAMESPACE
109

source code of qttools/src/linguist/linguist/recentfiles.cpp