1212 * for more details.
1313 */
1414#include " advancedsettingspagecontroller.h"
15+ #include " common/vfs.h"
16+ #include " folderman.h"
1517
18+ #include " theme.h"
19+
20+ #include < QButtonGroup>
21+ #include < QFileDialog>
22+ #include < QHBoxLayout>
23+ #include < QLabel>
24+ #include < QLineEdit>
25+ #include < QPushButton>
26+ #include < QRadioButton>
27+ #include < QVBoxLayout>
1628#include < QWizardPage>
1729
1830namespace OCC {
1931
32+
2033AdvancedSettingsPageController::AdvancedSettingsPageController (QWizardPage *page, QObject *parent)
2134 : QObject{parent}
2235 , _page(page)
2336{
37+ gatherSyncInfo ();
2438 buildPage ();
2539}
2640
@@ -29,11 +43,183 @@ void AdvancedSettingsPageController::buildPage()
2943 if (!_page)
3044 return ;
3145
32- _page->setTitle (QStringLiteral (" AdvancedSetttingsPage" ));
46+ _buttonGroup = new QButtonGroup (_page);
47+
48+ QLabel *titleLabel = new QLabel (tr (" Advanced settings" ), _page);
49+ QFont titleFont = titleLabel->font ();
50+ titleFont.setPixelSize (20 );
51+ titleFont.setWeight (QFont::DemiBold);
52+ titleLabel->setFont (titleFont);
53+ titleLabel->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Fixed);
54+
55+ QLabel *syncOptionsLabel = new QLabel (tr (" Sync and download options" ), _page);
56+ QLabel *syncRootLabel = new QLabel (tr (" Folder location" ));
57+ QFont sectionFont = syncOptionsLabel->font ();
58+ sectionFont.setPixelSize (16 );
59+ sectionFont.setWeight (QFont::DemiBold);
60+ syncOptionsLabel->setFont (sectionFont);
61+ syncRootLabel->setFont (sectionFont);
62+ syncOptionsLabel->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Fixed);
63+ syncRootLabel->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Fixed);
64+
65+
66+ QVBoxLayout *layout = new QVBoxLayout ();
67+ layout->setContentsMargins (50 , 0 , 50 , 0 );
68+ layout->setSpacing (12 );
69+ layout->addStretch (1 );
70+ layout->addWidget (titleLabel, Qt::AlignLeft);
71+ layout->addSpacing (8 );
72+ layout->addWidget (syncOptionsLabel, Qt::AlignLeft);
73+
74+ if (_vfsIsAvailable) {
75+ QRadioButton *vfsButton = new QRadioButton (tr (" Only sync and dowload files as you use them to save hard drive space" ), _page);
76+ vfsButton->setFocusPolicy (Qt::StrongFocus);
77+ _buttonGroup->addButton (vfsButton, SyncType::USE_VFS);
78+ layout->addWidget (vfsButton, Qt::AlignLeft);
79+ }
80+ if (!_forceVfs) {
81+ QRadioButton *selectiveSyncButton = new QRadioButton (tr (" Sync and download specific folders" ), _page);
82+ selectiveSyncButton->setFocusPolicy (Qt::StrongFocus);
83+ QRadioButton *syncAllButton = new QRadioButton (tr (" Automatically sync and download all current folders and files" ), _page);
84+ syncAllButton->setFocusPolicy (Qt::StrongFocus);
85+ _buttonGroup->addButton (selectiveSyncButton, SyncType::SELECTIVE_SYNC);
86+ _buttonGroup->addButton (syncAllButton, SyncType::SYNC_ALL);
87+ layout->addWidget (selectiveSyncButton, Qt::AlignLeft);
88+ layout->addWidget (syncAllButton, Qt::AlignLeft);
89+ }
90+
91+ Q_ASSERT (_buttonGroup->button (_defaultSyncType));
92+ _buttonGroup->button (_defaultSyncType)->setChecked (true );
93+
94+ _rootDirEdit = new QLineEdit (_page);
95+ _rootDirEdit->setText (_defaultSyncRoot);
96+ _rootDirEdit->setFocusPolicy (Qt::StrongFocus);
97+ // just clear the error if the user starts typing in the text edit
98+ connect (_rootDirEdit, &QLineEdit::textEdited, this , [this ] {
99+ if (!_errorField->text ().isEmpty ())
100+ _errorField->setText ({});
101+ });
102+ connect (_rootDirEdit, &QLineEdit::editingFinished, this , &AdvancedSettingsPageController::onRootDirFieldEdited);
103+
104+ QPushButton *folderButton = new QPushButton (tr (" Choose..." ), _page);
105+ folderButton->setFocusPolicy (Qt::StrongFocus);
106+ connect (folderButton, &QPushButton::clicked, this , &AdvancedSettingsPageController::showFolderPicker);
107+
108+ layout->addSpacing (8 );
109+ layout->addWidget (syncRootLabel, Qt::AlignLeft);
110+
111+ QHBoxLayout *folderPickerLayout = new QHBoxLayout ();
112+ folderPickerLayout->addWidget (_rootDirEdit, Qt::AlignLeft);
113+ folderPickerLayout->addWidget (folderButton);
114+ layout->addLayout (folderPickerLayout);
115+
116+ _errorField = new QLabel (QString (), _page);
117+ QPalette errorPalette = _errorField->palette ();
118+ errorPalette.setColor (QPalette::Text, Qt::red);
119+ _errorField->setPalette (errorPalette);
120+ _errorField->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Fixed);
121+ _errorField->setWordWrap (true );
122+ _errorField->setAlignment (Qt::AlignLeft);
123+ _errorField->setTextInteractionFlags (Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse);
124+ layout->addWidget (_errorField);
125+
126+ layout->addStretch (1 );
127+ _page->setLayout (layout);
128+ }
129+
130+ void AdvancedSettingsPageController::gatherSyncInfo ()
131+ {
132+ _vfsIsAvailable = VfsPluginManager::instance ().bestAvailableVfsMode () == Vfs::WindowsCfApi;
133+ _forceVfs = _vfsIsAvailable && Theme::instance ()->forceVirtualFilesOption ();
134+ if (!_vfsIsAvailable)
135+ _defaultSyncType = SyncType::SYNC_ALL;
136+ else
137+ _defaultSyncType = SyncType::USE_VFS;
138+
139+ _defaultSyncRoot = FolderMan::suggestSyncFolder (FolderMan::NewFolderType::SpacesSyncRoot, {});
33140}
34141
35142bool AdvancedSettingsPageController::validate ()
36143{
144+ // this is a safety net because for unknown reasons, on windows when you hit enter to commit hand edited text
145+ // in the QLineEdit, it ALSO triggers the finish button. No idea but this should block the finish so the user
146+ // can see their last choice failed, and that the root has been reset to the default.
147+ if (_lastHandEditedRootFailed)
148+ return false ;
149+
150+ // normally I don't like taking values directly from the gui but in this case, it would be complete overkill to
151+ // create a dedicated model just for these two values that only need to be collected when the user is done.
152+ AdvancedSettingsResult result;
153+ result._syncRoot = _rootDirEdit->text ();
154+ result._syncType = static_cast <SyncType>(_buttonGroup->checkedId ());
155+ Q_EMIT success (result);
37156 return true ;
38157}
158+
159+ bool AdvancedSettingsPageController::validateSyncRoot (const QString &rootPath)
160+ {
161+ QString errorMessageTemplate = tr (" Invalid local download directory %1: %2" );
162+
163+ if (rootPath == QDir::homePath ()) {
164+ _errorField->setText (errorMessageTemplate.arg (rootPath, tr (" your user directory may not be chosen as the sync root." )));
165+ return false ;
166+ }
167+
168+ if (Utility::isMac ()) {
169+ QString filesystemType = FileSystem::fileSystemForPath (rootPath);
170+ if (filesystemType != QStringLiteral (" apfs" )) {
171+ _errorField->setText (errorMessageTemplate.arg (rootPath, tr (" path is not located on a supported Apple File System." )));
172+ }
173+ }
174+
175+ if (!QDir::isAbsolutePath (rootPath)) {
176+ _errorField->setText (errorMessageTemplate.arg (rootPath, tr (" path must be absolute." )));
177+ return false ;
178+ }
179+
180+ QString invalidPathErrorMessage = FolderMan::checkPathValidityRecursive (rootPath, FolderMan::NewFolderType::SpacesSyncRoot, {});
181+ if (!invalidPathErrorMessage.isEmpty ()) {
182+ _errorField->setText (errorMessageTemplate.arg (rootPath, invalidPathErrorMessage));
183+ return false ;
184+ }
185+
186+ // I'm not testing the case that vfs is actually the chosen mode here as if vfs is available we should just block dirs that don't support it,
187+ // the idea being that eg if they change the mode in the page after they select the dir, or use selective sync with vfs later, at least we know the default
188+ // root they select here will not cause any issues down the road
189+ if (_vfsIsAvailable && !FolderMan::instance ()->checkVfsAvailability (rootPath)) {
190+ _errorField->setText (errorMessageTemplate.arg (rootPath, tr (" selected path does not support using virtual file system." )));
191+ return false ;
192+ }
193+
194+ return true ;
195+ }
196+
197+ void AdvancedSettingsPageController::showFolderPicker ()
198+ {
199+ _errorField->setText ({});
200+ _lastHandEditedRootFailed = false ;
201+
202+ QDir defaultDir (_defaultSyncRoot);
203+ while (!defaultDir.exists ())
204+ defaultDir.cdUp ();
205+ QString chosenRoot = QFileDialog::getExistingDirectory (_page->parentWidget (), tr (" Select sync root" ), defaultDir.path ());
206+
207+ if (chosenRoot.isEmpty ())
208+ return ;
209+
210+ if (validateSyncRoot (chosenRoot))
211+ _rootDirEdit->setText (chosenRoot);
212+ }
213+
214+ void AdvancedSettingsPageController::onRootDirFieldEdited ()
215+ {
216+ QString chosenRoot = _rootDirEdit->text ();
217+ if (!validateSyncRoot (chosenRoot)) {
218+ _rootDirEdit->setText (_defaultSyncRoot);
219+ _lastHandEditedRootFailed = true ;
220+ } else {
221+ _lastHandEditedRootFailed = false ;
222+ _errorField->setText ({});
223+ }
224+ }
39225}
0 commit comments