Skip to content

Commit cc064f7

Browse files
committed
* Fixed issue #97: Files and folders together do not start MENU.
1 parent 4612a17 commit cc064f7

File tree

5 files changed

+86
-59
lines changed

5 files changed

+86
-59
lines changed

CHANGES

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Changes for 0.7.0
66
* Deprecated support for 32-bit Windows.
77
* Fixed issue #91: String encoding in source code.
88
* Fixed issue #96: Problems with Files > 2Gb
9+
* Fixed issue #97: Files and folders together do not start MENU.
910

1011

1112
Changes for 0.6.1

UserManual.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -259,11 +259,11 @@ The `class` attribute validates a menu based on type (class) of the selected fil
259259

260260
If `class` attribute is specified, the classes of the files selected by the user must match for the validation to be successful. To specify multiple classes, one must separate each class with the `;` character. If multiple classes are specified, **at least one** class must match for the validation to be successful.
261261

262-
If multiple files are selected, the class of **each file** must match **at least one** allowed classes for the validation to be successful.
262+
If multiple files are selected, **each file** must match **at least one** allowed class for the validation to be successful.
263263

264264
If `class` attribute is not specified, then the validation is successful.
265265

266-
The `class` attribute supports the following values which are explained in the following table:
266+
The `class` attribute supported values are explained in the following table:
267267

268268
| Values | Meaning |
269269
|-----------------|--------------------------------------------------------------------------------------------------------------------------------------------------------|
@@ -312,9 +312,9 @@ For example, the following set a menu visible only when the user right-click on
312312

313313
The `fileextensions` attribute validates a menu based on the file's extension selected by the user.
314314

315-
If `fileextensions` attribute is specified, the file's extension selected by the user must match for the validation to be successful. To specify multiple file extension, one must separate each extensions with the `;` character. If multiple file extensions are specified, **at least one** extension must match for the validation to be successful.
315+
If `fileextensions` attribute is specified, the file's extension selected by the user must match for the validation to be successful. To specify multiple file extensions, one must separate each extension with the `;` character. If multiple file extensions are specified, **at least one** extension must match for the validation to be successful.
316316

317-
If multiple files are selected, the file extension of each element must match **at least one** allowed file extension for the validation to be successful.
317+
If multiple files are selected, ***each file*** must match **at least one** allowed file extension for the validation to be successful.
318318

319319
If `fileextensions` attribute is not specified, then the validation is successful.
320320

@@ -333,7 +333,7 @@ The `pattern` attribute validates a menu based on a wildcard pattern matching al
333333

334334
If `pattern` attribute is specified, the files selected by the user must match the wildcard pattern for the validation to be successful. To specify multiple patterns, one must separate each pattern value with the `;` character. If multiple patterns are specified, **at least one** pattern must match for the validation to be successful.
335335

336-
If multiple files are selected, the path of each file must match **at least one** pattern for the validation to be successful.
336+
If multiple files are selected, ***each file*** must match **at least one** pattern for the validation to be successful.
337337

338338
If `pattern` attribute is not specified, then the validation is successful.
339339

include/shellanything/Validator.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ namespace shellanything
166166
bool ValidateFileExtensions(const Context & context, const std::string & file_extensions, bool inversed) const;
167167
bool ValidateExists(const Context & context, const std::string & file_exists, bool inversed) const;
168168
bool ValidateClass(const Context & context, const std::string & class_, bool inversed) const;
169-
bool ValidateClassSingle(const Context & context, const std::string & class_, bool inversed) const;
169+
bool ValidateSingleFileMultipleClasses(const std::string & path, const std::string & class_, bool inversed) const;
170+
bool ValidateSingleFileSingleClass(const std::string & path, const std::string & class_, bool inversed) const;
170171
bool ValidatePattern(const Context & context, const std::string & pattern, bool inversed) const;
171172
bool ValidateExprtk(const Context & context, const std::string & exprtk, bool inversed) const;
172173

src/Validator.cpp

Lines changed: 60 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -349,11 +349,11 @@ namespace shellanything
349349
Uppercase(accepted_file_extensions);
350350

351351
//for each file selected
352-
const Context::ElementList & elements = context.GetElements();
353-
for(size_t i=0; i<elements.size(); i++)
352+
const Context::ElementList & context_elements = context.GetElements();
353+
for(size_t i=0; i<context_elements.size(); i++)
354354
{
355-
const std::string & element = elements[i];
356-
std::string current_file_extension = ra::strings::Uppercase(ra::filesystem::GetFileExtention(element));
355+
const std::string & path = context_elements[i];
356+
std::string current_file_extension = ra::strings::Uppercase(ra::filesystem::GetFileExtention(path));
357357

358358
//each file extension must be part of accepted_file_extensions
359359
bool found = HasValue(accepted_file_extensions, current_file_extension);
@@ -392,65 +392,46 @@ namespace shellanything
392392
return true;
393393
}
394394

395-
bool Validator::ValidateClassSingle(const Context & context, const std::string & class_, bool inversed) const
395+
bool Validator::ValidateSingleFileSingleClass(const std::string & path, const std::string & class_, bool inversed) const
396396
{
397-
if (class_.empty())
398-
return true;
399-
400397
PropertyManager & pmgr = PropertyManager::GetInstance();
401398

402399
if (class_ == "file")
403400
{
404-
// Selected elements must be files
405-
bool valid = false;
406-
valid |= (!inversed && context.GetNumFiles() > 0 && context.GetNumDirectories() == 0);
407-
valid |= (inversed && context.GetNumFiles() == 0 && context.GetNumDirectories() > 0);
408-
if (!valid)
401+
// Selected element must be a file
402+
bool is_file = ra::filesystem::FileExistsUtf8(path.c_str());
403+
if (!inversed && !is_file)
404+
return false;
405+
if (inversed && is_file)
409406
return false;
410407
}
411408
else if (class_ == "folder" || class_ == "directory")
412409
{
413-
// Selected elements must be folders
414-
bool valid = false;
415-
valid |= (!inversed && context.GetNumDirectories() > 0 && context.GetNumFiles() == 0);
416-
valid |= (inversed && context.GetNumDirectories() == 0 && context.GetNumFiles() > 0);
417-
if (!valid)
410+
// Selected elements must be a directory
411+
bool is_directory = ra::filesystem::DirectoryExistsUtf8(path.c_str());
412+
if (!inversed && !is_directory)
413+
return false;
414+
if (inversed && is_directory)
418415
return false;
419416
}
420417
else if (class_ == "drive")
421418
{
422419
// Selected elements must be mapped to a drive
423-
bool valid = true;
424-
const Context::ElementList & elements = context.GetElements();
425-
for(size_t i=0; i<elements.size() && valid == true; i++)
426-
{
427-
const std::string & element = elements[i];
428-
std::string drive = GetDriveLetter(element);
429-
if (!inversed && drive.empty()) // All elements must be mapped to a drive
430-
valid = false;
431-
if (inversed && !drive.empty()) // All elements must NOT be mapped to a drive.
432-
valid = false;
433-
}
434-
if (!valid)
420+
std::string drive = GetDriveLetter(path);
421+
if (!inversed && drive.empty()) // All elements must be mapped to a drive
422+
return false;
423+
if (inversed && !drive.empty()) // All elements must NOT be mapped to a drive.
435424
return false;
436425
}
437426
else if (GetDriveClassFromString(class_.c_str()) != DRIVE_CLASS_UNKNOWN)
438427
{
439428
DRIVE_CLASS required_class = GetDriveClassFromString(class_.c_str());
440429

441430
// Selected elements must be of the same drive class
442-
bool valid = true;
443-
const Context::ElementList & elements = context.GetElements();
444-
for(size_t i=0; i<elements.size() && valid == true; i++)
445-
{
446-
const std::string & element = elements[i];
447-
DRIVE_CLASS element_class = GetDriveClassFromPath(element);
448-
if (!inversed && element_class != required_class)
449-
valid = false;
450-
if (inversed && element_class == required_class)
451-
valid = false;
452-
}
453-
if (!valid)
431+
DRIVE_CLASS element_class = GetDriveClassFromPath(path);
432+
if (!inversed && element_class != required_class)
433+
return false;
434+
if (inversed && element_class == required_class)
454435
return false;
455436
}
456437
else
@@ -461,6 +442,24 @@ namespace shellanything
461442
return true;
462443
}
463444

445+
bool Validator::ValidateSingleFileMultipleClasses(const std::string & path, const std::string & class_, bool inversed) const
446+
{
447+
if (class_.empty())
448+
return true;
449+
450+
//split
451+
ra::strings::StringVector classes = ra::strings::Split(class_, ";");
452+
453+
bool valid = false;
454+
for (size_t i = 0; i < classes.size(); i++)
455+
{
456+
const std::string & class_ = classes[i];
457+
valid |= ValidateSingleFileSingleClass(path, class_, inversed);
458+
}
459+
460+
return valid;
461+
}
462+
464463
bool Validator::ValidateClass(const Context & context, const std::string & class_, bool inversed) const
465464
{
466465
if (class_.empty())
@@ -525,14 +524,22 @@ namespace shellanything
525524
// Continue validation for the remaining class elements
526525
if (!classes.empty())
527526
{
528-
bool valid = false;
529-
for(size_t i=0; i<classes.size(); i++)
527+
//join remaining classes into a single string
528+
std::string classes_str = ra::strings::Join(classes, ";");
529+
530+
//for each file selected
531+
const Context::ElementList & context_elements = context.GetElements();
532+
for (size_t i = 0; i < context_elements.size(); i++)
530533
{
531-
const std::string & element = classes[i];
532-
valid |= ValidateClassSingle(context, element, inversed);
534+
const std::string & path = context_elements[i];
535+
536+
//each element must match one of the classes
537+
bool valid = ValidateSingleFileMultipleClasses(path, classes_str, inversed);
538+
if (!inversed && !valid)
539+
return false; //current file extension is not accepted
540+
if (inversed && valid)
541+
return false; //current file extension is not accepted
533542
}
534-
if (!valid)
535-
return false;
536543
}
537544

538545
return true;
@@ -562,14 +569,14 @@ namespace shellanything
562569
Uppercase(patterns);
563570

564571
//for each file selected
565-
const Context::ElementList & elements = context.GetElements();
566-
for(size_t i=0; i<elements.size(); i++)
572+
const Context::ElementList & context_elements = context.GetElements();
573+
for(size_t i=0; i<context_elements.size(); i++)
567574
{
568-
const std::string & element = elements[i];
569-
std::string element_uppercase = ra::strings::Uppercase(element);
575+
const std::string & path = context_elements[i];
576+
std::string path_uppercase = ra::strings::Uppercase(path);
570577

571578
//each element must match one of the patterns
572-
bool match = WildcardMatch(patterns, element_uppercase.c_str());
579+
bool match = WildcardMatch(patterns, path_uppercase.c_str());
573580
if (!inversed && !match)
574581
return false; //current file does not match any patterns
575582
if (inversed && match)

test/TestValidator.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ namespace shellanything { namespace test
302302
ASSERT_FALSE( v.Validate(c) );
303303

304304
//assert 'at least one' class must match
305+
//If multiple classes are specified, at least one class must match for the validation to be successful.
305306
v.SetClass("folder;drive:network;drive:fixed"); // folder and drive:network fails but drive:fixed matches
306307
ASSERT_TRUE( v.Validate(c) );
307308

@@ -361,6 +362,23 @@ namespace shellanything { namespace test
361362
v.SetClass("drive:network");
362363
ASSERT_TRUE( v.Validate(c) );
363364

365+
//Set a mix of files and folders (issue #97, issue97)
366+
//If multiple files are selected, the class of each file must match at least one allowed classes for the validation to be successful.
367+
#ifdef _WIN32
368+
{
369+
Context::ElementList elements;
370+
elements.push_back("C:\\Windows\\System32");
371+
elements.push_back("C:\\Windows\\notepad.exe");
372+
c.SetElements(elements);
373+
}
374+
#else
375+
//TODO: complete with known path to files
376+
#endif
377+
378+
//assert success when using 'file' or 'folder'
379+
v.SetClass("file;directory");
380+
ASSERT_TRUE(v.Validate(c));
381+
364382
}
365383
//--------------------------------------------------------------------------------------------------
366384
TEST_F(TestValidator, testPattern)

0 commit comments

Comments
 (0)