// Apply JSON diff to clips void Timeline::apply_json_to_clips(Json::Value change) throw(InvalidJSONKey) { // Get key and type of change string change_type = change["type"].asString(); string clip_id = ""; Clip *existing_clip = NULL; // Find id of clip (if any) for (int x = 0; x < change["key"].size(); x++) { // Get each change Json::Value key_part = change["key"][x]; if (key_part.isObject()) { // Check for id if (!key_part["id"].isNull()) { // Set the id clip_id = key_part["id"].asString(); // Find matching clip in timeline (if any) list<Clip*>::iterator clip_itr; for (clip_itr=clips.begin(); clip_itr != clips.end(); ++clip_itr) { // Get clip object from the iterator Clip *c = (*clip_itr); if (c->Id() == clip_id) { existing_clip = c; break; // clip found, exit loop } } break; // id found, exit loop } } } // Check for a more specific key (targetting this clip's effects) // For example: ["clips", {"id:123}, "effects", {"id":432}] if (existing_clip && change["key"].size() == 4 && change["key"][2] == "effects") { // This change is actually targetting a specific effect under a clip (and not the clip) EffectBase *existing_effect = NULL; Json::Value key_part = change["key"][3]; if (key_part.isObject()) { // Check for id if (!key_part["id"].isNull()) { // Set the id string effect_id = key_part["id"].asString(); // Find matching effect in timeline (if any) list<EffectBase*>::iterator effect_itr; for (effect_itr=existing_clip->Effects().begin(); effect_itr != existing_clip->Effects().end(); ++effect_itr) { // Get effect object from the iterator EffectBase *e = (*effect_itr); if (e->Id() == effect_id) { existing_effect = e; // Apply the change to the effect directly apply_json_to_effects(change, existing_effect); return; // effect found, don't update clip } } } } } // Determine type of change operation if (change_type == "insert") { // Create new clip Clip *clip = new Clip(); clip->SetJsonValue(change["value"]); // Set properties of new clip from JSON AddClip(clip); // Add clip to timeline } else if (change_type == "update") { // Update existing clip if (existing_clip) existing_clip->SetJsonValue(change["value"]); // Update clip properties from JSON } else if (change_type == "delete") { // Remove existing clip if (existing_clip) RemoveClip(existing_clip); // Remove clip from timeline } }
// Load Json::JsonValue into this object void Timeline::SetJsonValue(Json::Value root) throw(InvalidFile, ReaderClosed) { // Close timeline before we do anything (this also removes all open and closing clips) Close(); // Set parent data ReaderBase::SetJsonValue(root); if (!root["clips"].isNull()) { // Clear existing clips clips.clear(); // loop through clips for (int x = 0; x < root["clips"].size(); x++) { // Get each clip Json::Value existing_clip = root["clips"][x]; // Create Clip Clip *c = new Clip(); // Load Json into Clip c->SetJsonValue(existing_clip); // Add Clip to Timeline AddClip(c); } } if (!root["effects"].isNull()) { // Clear existing effects effects.clear(); // loop through effects for (int x = 0; x < root["effects"].size(); x++) { // Get each effect Json::Value existing_effect = root["effects"][x]; // Create Effect EffectBase *e = NULL; if (!existing_effect["type"].isNull()) // Init the matching effect object if (existing_effect["type"].asString() == "ChromaKey") e = new ChromaKey(); else if (existing_effect["type"].asString() == "Deinterlace") e = new Deinterlace(); else if (existing_effect["type"].asString() == "Mask") e = new Mask(); else if (existing_effect["type"].asString() == "Negate") e = new Negate(); // Load Json into Effect e->SetJsonValue(existing_effect); // Add Effect to Timeline AddEffect(e); } } }