public string FindDeck(string value) { // if searching for all decks, skip if (value.Equals("*")) { return("skip"); // deck types } else if (value.Equals("filtered")) { return("c.odid"); } List <long> ids = null; // current deck? if (value.Equals("current", StringComparison.OrdinalIgnoreCase)) { ids = GetChildDeckIds((long)JsonHelper.GetNameNumber(collection.Deck.Current(), "id")); } else if (!value.Contains("*")) { // single deck ids = GetChildDeckIds(collection.Deck.AddOrResuedDeck(value, false)); } else { // wildcard ids = new List <long>(); value = value.Replace("*", ".*"); value = value.Replace("+", "\\+"); foreach (JsonObject d in collection.Deck.All()) { if (Regex.IsMatch(d.GetNamedString("name"), "(?i)" + value)) { foreach (long id in GetChildDeckIds((long)JsonHelper.GetNameNumber(d, "id"))) { if (!ids.Contains(id)) { ids.Add(id); } } } } } if (ids == null || ids.Count == 0) { return(null); } string sids = Utils.Ids2str(ids.ToArray()); return("c.did in " + sids + " or c.odid in " + sids); }
public List <long> DeckIdsForConf(long confId) { List <long> dids = new List <long>(); foreach (JsonObject deck in deckDict.Values) { if (deck.ContainsKey("conf") && (JsonHelper.GetNameNumber(deck, "conf") == confId)) { dids.Add((long)JsonHelper.GetNameNumber(deck, "id")); } } return(dids); }
private string FindModel(string value) { LinkedList <long> ids = new LinkedList <long>(); foreach (JsonObject m in collection.Models.All()) { if (m.GetNamedString("name").Equals(value, StringComparison.OrdinalIgnoreCase)) { ids.AddLast((long)JsonHelper.GetNameNumber(m, "id")); } } return("n.mid in " + Utils.Ids2str(ids.ToArray())); }
/// <summary> /// /// </summary> /// <param name="jObj">Json Deck to rename</param> /// <param name="newName">New name</param> /// <param name="isNeedAddToActive">Is need to add to active deck after rename</param> public string Rename(JsonObject jObj, string newName, bool isNeedAddToActive = true) { //Different with java and python ver, we don't throw exception here and only add "_" //Check for unique name should be done in other function //This is just the last check to ensure we never create a deck with the same name while (AllNames().Contains(newName)) { newName += "_"; } newName = EnsureParents(newName); // make sure we're not nesting under a filtered deck if (newName.Contains(Constant.SUBDECK_SEPERATE)) { string[] parts = newName.Split(new string[] { Constant.SUBDECK_SEPERATE }, StringSplitOptions.None); string[] subParts = new string[parts.Length - 1]; Array.Copy(parts, subParts, subParts.Length); string newParent = String.Join(Constant.SUBDECK_SEPERATE, subParts); if (JsonHelper.GetNameNumber(GetDeckByName(newParent), "dyn") != 0) { throw new DeckRenameException(DeckRenameException.ErrorCode.FILTERED_NOSUBDEKCS); } } //Rename children string oldName = jObj.GetNamedString("name"); string str; foreach (JsonObject grp in All()) { if (grp.GetNamedString("name").StartsWith(oldName + Constant.SUBDECK_SEPERATE)) { str = grp.GetNamedString("name").ReplaceFirst(oldName + Constant.SUBDECK_SEPERATE, newName + Constant.SUBDECK_SEPERATE); grp["name"] = JsonValue.CreateStringValue(str); Save(grp); } } //adjust name jObj["name"] = JsonValue.CreateStringValue(newName); // ensure we have parents again, as we may have renamed parent->child newName = EnsureParents(newName); Save(jObj); // renaming may have altered active deckId order if (isNeedAddToActive) { MaybeAddToActive(); } return(newName); }
public void RestoreToDefault(JsonObject conf) { int oldOrder = (int)JsonHelper.GetNameNumber(conf.GetNamedObject("new"), "order"); JsonObject temp = JsonObject.Parse(defaultConf); temp.Add("id", conf.GetNamedValue("id")); temp.Add("name", conf.GetNamedValue("name")); deckConf.Add((long)JsonHelper.GetNameNumber(conf, "id"), temp); Save(temp); // if it was previously randomized, resort if (oldOrder == 0) { collection.Sched.ResortConf(temp); } }
private static string Limit(Collection collection) { if (IsWholeCollection) { List <long> ids = new List <long>(); foreach (JsonObject d in collection.Deck.All()) { ids.Add((long)JsonHelper.GetNameNumber(d, "id")); } return(Utils.Ids2str(ids)); } else { return(collection.Sched.DeckLimit()); } }
public Dictionary <string, long> Children(long did) { string name; name = Get(did).GetNamedString("name"); Dictionary <string, long> actv = new Dictionary <string, long>(); foreach (JsonObject g in All()) { string deckName = g.GetNamedString("name"); if (deckName.StartsWith(name + Constant.SUBDECK_SEPERATE)) { actv[deckName] = (long)JsonHelper.GetNameNumber(g, "id"); } } return(actv); }
private string FindTemplate(string value) { // were we given an ordinal number? int?num = null; try { num = int.Parse(value) - 1; } catch (FormatException) { num = null; } if (num != null) { return("c.ord = " + num); } // search for template names List <string> lims = new List <string>(); foreach (JsonObject m in collection.Models.All()) { JsonArray tmpls = m.GetNamedArray("tmpls"); for (uint ti = 0; ti < tmpls.Count; ++ti) { JsonObject t = tmpls.GetObjectAt(ti); if (t.GetNamedString("name").Equals(value, StringComparison.OrdinalIgnoreCase)) { if (JsonHelper.GetNameNumber(m, "type") == (double)ModelType.CLOZE) { // if the user has asked for a cloze card, we want // to give all ordinals, so we just limit to the // model instead lims.Add("(n.mid = " + (long)JsonHelper.GetNameNumber(m, "id") + ")"); } else { lims.Add("(n.mid = " + (long)JsonHelper.GetNameNumber(m, "id") + " and c.ord = " + (int)JsonHelper.GetNameNumber(t, "ord") + ")"); } } } } return(String.Join(" or ", lims.ToArray())); }
public JsonObject ConfForDeckId(long did) { JsonObject deck = Get(did, false); if (deck == null) { throw new DeckNotFoundException(); } if (deck.ContainsKey("conf")) { JsonObject conf = GetConf((long)JsonHelper.GetNameNumber(deck, "conf")); conf["dyn"] = JsonValue.CreateNumberValue(0); return(conf); } // dynamic decks have embedded conf return(deck); }
public void Remove(long deckId, bool cardsToo = false, bool childrenToo = true) { JsonObject deck; if (deckId == 1) { // we won't allow the default deck to be deleted, but if it's a // child of an existing deck then it needs to be renamed deck = Get(deckId); if (deck.GetNamedString("name").Contains(Constant.SUBDECK_SEPERATE)) { deck["name"] = JsonValue.CreateStringValue("Default"); Save(deck); } return; } // log the removal regardless of whether we have the deck or not collection.LogRem(new long[] { deckId }, RemovalType.DECK); if (!deckDict.ContainsKey(deckId)) { return; } deck = Get(deckId); if (JsonHelper.GetNameNumber(deck, "dyn") != 0) { // deleting a cramming deck returns cards to their previous deck // rather than deleting the cards collection.Sched.EmptyDyn(deckId); RemoveIfChildrenToo(deckId, childrenToo, cardsToo); } else { RemoveIfChildrenToo(deckId, childrenToo, cardsToo); RemoveIfNoteAndCardsToo(deckId, cardsToo); } deckDict.Remove(deckId); EnsureHaveActiveDeck(deckId); Save(); }
public JsonObject GetTemplate() { JsonObject m = GetModel(); if (JsonHelper.GetNameNumber(m, "type") == (double)ModelType.STD) { try { return(m.GetNamedArray("tmpls").GetObjectAt((uint)ord)); } catch { //This should only happen if user changes this card note type from cloze to standard //and the note of this card contains more than one cloze return(GetModel().GetNamedArray("tmpls").GetObjectAt(0)); } } else { return(GetModel().GetNamedArray("tmpls").GetObjectAt(0)); } }
public List <string> FileNameInMediaFolder(long mid, string strIn, bool includeRemote = false) { List <string> returnList = new List <string>(); List <string> stringList = new List <string>(); JsonObject model = collection.Models.Get(mid); int type = (int)JsonHelper.GetNameNumber(model, "type"); if ((type == (int)ModelType.CLOZE) && strIn.Contains("{{c")) { stringList = ExpandClozes(strIn); } else { stringList.Add(strIn); } string str; foreach (string s in stringList) { str = LaTeX.MungeQA(s, collection); MatchCollection matches; foreach (Regex p in RegExps) { matches = p.Matches(str); foreach (Match m in matches) { string fName = m.Groups["fname"].Value; bool isLocal = !remoteRegex.IsMatch(fName.ToLowerInvariant()); if (isLocal || includeRemote) { returnList.Add(fName); } } } } return(returnList); }
/// <summary> /// An unsorted list of all deck names. /// </summary> /// <param name="dyn"></param> /// <returns></returns> public List <string> AllNames(bool dyn = true) { List <string> list = new List <string>(); if (dyn) { foreach (JsonObject x in deckDict.Values) { list.Add(x.GetNamedString("name")); } } else { foreach (JsonObject x in deckDict.Values) { if (JsonHelper.GetNameNumber(x, "dyn") == 0) { list.Add(x.GetNamedString("name")); } } } return(list); }
private static void Upgrade(Collection col, int ver) { if (ver < 3) { // new deck properties foreach (JsonObject d in col.Deck.All()) { d["dyn"] = JsonValue.CreateNumberValue(0); d["collapsed"] = JsonValue.CreateBooleanValue(false); col.Deck.Save(d); } } if (ver < 4) { col.ModSchemaNoCheck(); List <JsonObject> clozes = new List <JsonObject>(); foreach (JsonObject m in col.Models.All()) { if (!m.GetNamedArray("tmpls").GetObjectAt(0).GetNamedString("qfmt").Contains("{{cloze:")) { m["type"] = JsonValue.CreateNumberValue((int)ModelType.STD); } else { clozes.Add(m); } } foreach (JsonObject m in clozes) { UpgradeClozeModel(col, m); } col.Database.Execute("UPDATE col SET ver = 4"); } if (ver < 5) { col.Database.Execute("UPDATE cards SET odue = 0 WHERE queue = 2"); col.Database.Execute("UPDATE col SET ver = 5"); } if (ver < 6) { col.ModSchemaNoCheck(); foreach (JsonObject m in col.Models.All()) { m["css"] = JsonObject.Parse(Models.defaultModel).GetNamedValue("css"); JsonArray ar = m.GetNamedArray("tmpls"); for (uint i = 0; i < ar.Count; i++) { JsonObject t = ar.GetObjectAt(i); if (!t.ContainsKey("css")) { continue; } m["css"] = JsonValue.CreateStringValue( m.GetNamedString("css") + "\n" + t.GetNamedString("css").Replace(".card ", ".card" + t.GetNamedString("ord") + 1)); t.Remove("css"); } col.Models.Save(m); } col.Database.Execute("UPDATE col SET ver = 6"); } if (ver < 7) { col.ModSchemaNoCheck(); col.Database.Execute("UPDATE cards SET odue = 0 WHERE (type = 1 OR queue = 2) AND NOT odid"); col.Database.Execute("UPDATE col SET ver = 7"); } if (ver < 8) { col.ModSchemaNoCheck(); col.Database.Execute("UPDATE cards SET due = due / 1000 WHERE due > 4294967296"); col.Database.Execute("UPDATE col SET ver = 8"); } if (ver < 9) { col.Database.Execute("UPDATE col SET ver = 9"); } if (ver < 10) { col.Database.Execute("UPDATE cards SET left = left + left * 1000 WHERE queue = 1"); col.Database.Execute("UPDATE col SET ver = 10"); } if (ver < 11) { col.ModSchemaNoCheck(); foreach (JsonObject d in col.Deck.All()) { if (JsonHelper.GetNameNumber(d, "dyn") != 0) { int order = (int)JsonHelper.GetNameNumber(d, "order"); // failed order was removed if (order >= 5) { order -= 1; } JsonArray ja = new JsonArray(); ja.Add(d.GetNamedValue("search")); ja.Add(d.GetNamedValue("limit")); ja.Add(JsonValue.CreateNumberValue(order)); d.Add("terms", new JsonArray()); d.GetNamedArray("terms").Insert(0, ja); d.Remove("search"); d.Remove("limit"); d.Remove("order"); d["resched"] = JsonValue.CreateBooleanValue(true); d["return"] = JsonValue.CreateBooleanValue(true); } else { if (!d.ContainsKey("extendNew")) { d["extendNew"] = JsonValue.CreateNumberValue(10); d["extendRev"] = JsonValue.CreateNumberValue(50); } } col.Deck.Save(d); } foreach (JsonObject c in col.Deck.AllConf()) { JsonObject r = c.GetNamedObject("rev"); r["ivlFct"] = JsonValue.CreateNumberValue(JsonHelper.GetNameNumber(r, "ivlFct", 1)); if (r.ContainsKey("ivlfct")) { r.Remove("ivlfct"); } r["maxIvl"] = JsonValue.CreateNumberValue(36500); col.Deck.Save(c); } foreach (JsonObject m in col.Models.All()) { JsonArray tmpls = m.GetNamedArray("tmpls"); for (uint ti = 0; ti < tmpls.Count; ++ti) { JsonObject t = tmpls.GetObjectAt(ti); t["bqfmt"] = JsonValue.CreateStringValue(""); t["bafmt"] = JsonValue.CreateStringValue(""); } col.Models.Save(m); } col.Database.Execute("update col set ver = 11"); } }
private string FindField(string field, string val) { //We need two expressions to query the cards: One that will use REGEX syntax and another //that should use SQLITE LIKE clause syntax. string sqlVal = val .Replace("%", "\\%") // For SQLITE, we escape all % signs .Replace("*", "%"); // And then convert the * into non-escaped % signs //The following three lines make sure that only _ and * are valid wildcards. string regexVal = Regex.Escape(sqlVal).Replace("\\_", ".").Replace("%", ".*"); //For the pattern, we use the javaVal expression that uses REGEX syntax //Regex pattern = new Regex("(?s)\\Q" + regexVal + "\\E", RegexOptions.Compiled | RegexOptions.IgnoreCase); Regex pattern = new Regex("(?s)^" + regexVal + "$", RegexOptions.Compiled | RegexOptions.IgnoreCase); // find models that have that field Dictionary <long, object[]> mods = new Dictionary <long, object[]>(); foreach (JsonObject m in collection.Models.All()) { JsonArray flds = m.GetNamedArray("flds"); for (uint fi = 0; fi < flds.Count; ++fi) { JsonObject f = flds.GetObjectAt(fi); if (f.GetNamedString("name").Equals(field, StringComparison.OrdinalIgnoreCase)) { mods.Add((long)JsonHelper.GetNameNumber(m, "id"), new object[] { m, JsonHelper.GetNameNumber(f, "ord") }); } } } if (mods.Count == 0) { // nothing has that field return(null); } LinkedList <long> nids = new LinkedList <long>(); // Here we use the sqlVal expression, that is required for LIKE syntax in sqllite. // There is no problem with special characters, because only % and _ are special // characters in this syntax. var list = collection.Database.QueryColumn <NoteTable>( "select id, mid, flds from notes where mid in " + Utils.Ids2str(mods.Keys.ToArray()) + " and flds like ? escape '\\'", new string[] { "%" + sqlVal + "%" }); foreach (NoteTable n in list) { string[] flds = Utils.SplitFields(n.Fields); int ord = Convert.ToInt32(mods[n.Mid][1]); string strg = flds[ord]; if (pattern.IsMatch(strg)) { nids.AddLast(n.Id); } } if (nids.Count == 0) { return("0"); } return("n.id in " + Utils.Ids2str(nids.ToArray())); }
public static int FindReplace(Collection collection, List <long> nids, string src, string dst, bool isRegex, string field, bool fold) { Dictionary <long, int> mmap = new Dictionary <long, int>(); if (field != null) { foreach (JsonObject m in collection.Models.All()) { JsonArray flds = m.GetNamedArray("flds"); for (uint fi = 0; fi < flds.Count; ++fi) { JsonObject f = flds.GetObjectAt(fi); if (f.GetNamedString("name").Equals(field)) { mmap.Add((long)JsonHelper.GetNameNumber(m, "id"), (int)JsonHelper.GetNameNumber(f, "ord")); } } } if (mmap.Count == 0) { return(0); } } // find and gather replacements if (!isRegex) { src = Regex.Escape(src); } if (fold) { src = "(?i)" + src; } Regex regex = new Regex(src, RegexOptions.Compiled); List <object[]> d = new List <object[]>(); string snids = Utils.Ids2str(nids); nids = new List <long>(); var list = collection.Database.QueryColumn <NoteTable>("select id, mid, flds from notes where id in " + snids); foreach (NoteTable n in list) { string flds = n.Fields; string origFlds = flds; // does it match? string[] sflds = Utils.SplitFields(flds); if (field != null) { long mid = n.Mid; if (!mmap.ContainsKey(mid)) { // note doesn't have that field continue; } int ord = mmap[mid]; sflds[ord] = regex.Replace(sflds[ord], dst); } else { for (int i = 0; i < sflds.Length; ++i) { sflds[i] = regex.Replace(sflds[i], dst); } } flds = Utils.JoinFields(sflds); if (!flds.Equals(origFlds)) { long nid = n.Id; nids.Add(nid); d.Add(new object[] { flds, DateTimeOffset.Now.ToUnixTimeSeconds(), collection.Usn, nid }); // order based on query below } } if (d.Count == 0) { return(0); } // replace collection.Database.ExecuteMany("update notes set flds=?,mod=?,usn=? where id=?", d); long[] pnids = nids.ToArray(); collection.UpdateFieldCache(pnids); collection.GenCards(pnids); return(d.Count); }
public List <long> DeckIdsForConf(JsonObject conf) { long confId = (long)JsonHelper.GetNameNumber(conf, "id"); return(DeckIdsForConf(confId)); }
public void UpdateConf(JsonObject jObj) { deckConf[(long)JsonHelper.GetNameNumber(jObj, "id")] = jObj; Save(); }
public void Update(JsonObject jObj) { deckDict[(long)JsonHelper.GetNameNumber(jObj, "id")] = jObj; MaybeAddToActive(); Save(); }
/// <summary> /// Time limit for answering in milliseconds /// </summary> /// <returns></returns> public int TimeLimit() { JsonObject conf = collection.Deck.ConfForDeckId(oDid == 0 ? deckId : oDid); return((int)JsonHelper.GetNameNumber(conf, "maxTaken") * 1000); }
public long Selected() { return((long)JsonHelper.GetNameNumber(collection.Conf, "curDeck")); }
public bool IsDyn(long did) { return(JsonHelper.GetNameNumber(Get(did), "dyn") != 0); }
public bool ShowTimer() { var conf = collection.Deck.ConfForDeckId(oDid == 0 ? deckId : oDid); return(JsonHelper.GetNameNumber(conf, "timer", 1) != 0); }
public bool ShouldShowTimer() { var deck = collection.Deck.ConfForDeckId(oDid == 0 ? deckId : oDid); return(JsonHelper.GetNameNumber(deck, "timer") != 0); }