bool GemTestCommand::execute(Gem* self, Gem* test) { bool result = false; switch (_id) { case HasFlag: return (test->style() & _arg) != 0; case GemType: return test->gemType() == _arg; case GemFlushMode: return (test->gemClass().flushMode() & _arg) != 0; case Text: return (_text == test->text()); case TextBegins: return test->text().startsWith(_text); case NthChild: { result = false; Gem* origin = test->parentGem(); if (!origin) break; int target = qAbs(_arg); int i = 1; // Counts the order. Gem* it; for (it = _arg > 0? origin->firstGem() : origin->lastGem(); it && it != test; it = _arg > 0? it->nextGem() : it->prevGem(), i++) { if (i == target) { // Didn't match it == test... return false; } } if (!it) break; result = i == target; break; } case NthOrder: { result = false; Gem* origin = test->parentGem(); if (!origin) break; int target = qAbs(_arg); int i = 0; // Counts the order. for (Gem* it = _arg > 0? origin->firstGem() : origin->finalGem(); it && it != origin->nextGem() && it != origin; it = _arg > 0? it->followingGem() : it->precedingGem()) { if (!it->isControl()) i++; if (it == test) { result = true; break; } if (i >= target) return false; } if (!result) break; // Not even found... result = i == target; break; } case IsTop: return test->parent() == NULL; case IsMe: return test == self; case IsMyParent: return test == self->parentGem(); case IsMyAncestor: result = false; for (Gem* it = self->parentGem(); it; it = it->parentGem()) if (it == test) { result = true; break; } break; case IsBreak: return test->isBreak(); case IsLineBreak: return test->isLineBreak(); case IsControl: return test->isControl(); case ExclusiveFlag: return (test->style() & ~_arg) == 0; case ChildCount: return test->count() == _arg; case CellWidth: return test->width() == _arg; default: qFatal("GemTestCommand: Invalid test command."); break; } return result; }
bool GemTest::test(Gem *gem) { Gem *test = gem; // The test pointer. Gem *tryStart; bool result, trying = false, passed; int i; for(GemTestCommand *cmd = _commands.next(); !cmd->isRoot(); cmd = cmd->next()) { // We can skip commands if trying is passed. if(trying && ((passed && cmd->id() != CheckIfPassed) || (!test && cmd->id() != CheckIfPassed && cmd->id() != GoSelf))) continue; result = true; switch(cmd->id()) { case GoSelf: test = gem; break; case GoParent: for(i = 0; test && i < cmd->intArg(); i++) test = test->parentGem(); break; case GoNext: for(i = 0; test && i < cmd->intArg(); i++) test = test->nextGem(); break; case GoPrev: for(i = 0; test && i < cmd->intArg(); i++) test = test->prevGem(); break; case GoFirst: for(i = 0; test && i < cmd->intArg(); i++) test = test->firstGem(); break; case GoLast: for(i = 0; test && i < cmd->intArg(); i++) test = test->lastGem(); break; case GoFollowing: for(i = 0; test && i < cmd->intArg(); i++) test = test->followingGem(); break; case GoPreceding: for(i = 0; test && i < cmd->intArg(); i++) test = test->precedingGem(); break; case GoFinal: test = gem->finalGem(); break; case BeginTry: trying = true; passed = false; tryStart = test; break; case CheckIfPassed: trying = false; result = passed; test = tryStart; // Return to where the test began. break; default: // Are we escalating this check? if(cmd->escalating()) { result = false; for(Gem* it = test->parentGem(); it; it = it->parentGem()) { if(cmd->execute(gem, it)) { result = true; break; } } } else { result = cmd->execute(gem, test); } break; } // You can't fail the BeginTry command. if(cmd->id() == BeginTry) continue; // A null test pointer is an automatic failure. if(!test) { if(!trying) return false; result = false; } // Did it fail? if(trying) { if(result != cmd->negated()) passed = true; // Passed! } else { if(result == cmd->negated()) return false; // Failed! } } if(trying) { qCritical("A 'try..pass' is missing 'pass'."); exit(1); } // All commands were successful. return true; }