From 6a12a6df5e38cde2eb06dd2ad48f8860d524bb9c Mon Sep 17 00:00:00 2001 From: QualCoder Developer Date: Fri, 13 Oct 2023 17:04:49 +1100 Subject: [PATCH] Add files via upload --- qualcoder/manage_files.py | 58 ++++++++++++++++++++++++---------- qualcoder/manage_references.py | 4 +-- qualcoder/ris.py | 47 ++++++++++++++++----------- 3 files changed, 72 insertions(+), 37 deletions(-) diff --git a/qualcoder/manage_files.py b/qualcoder/manage_files.py index 47c18d85d..481da3a38 100644 --- a/qualcoder/manage_files.py +++ b/qualcoder/manage_files.py @@ -58,6 +58,7 @@ from .html_parser import * from .memo import DialogMemo from .report_codes import DialogReportCodes # for isInstance() +from .ris import Ris from .select_items import DialogSelectItems from .view_av import DialogViewAV, DialogCodeAV # for isinstance update files from .view_image import DialogViewImage, DialogCodeImage # for isinstance update files @@ -306,6 +307,7 @@ def table_menu(self, position): item_text = self.ui.tableWidget.item(row, col).text() # Use these next few lines to use for moving a linked file into or an internal file out of the project folder mediapath = None + risid = None try: id_ = int(self.ui.tableWidget.item(row, self.ID_COLUMN).text()) except AttributeError: @@ -314,6 +316,7 @@ def table_menu(self, position): for s in self.source: if s['id'] == id_: mediapath = s['mediapath'] + risid = s['risid'] # Action cannot be None otherwise may default to one of the actions below depending on column clicked menu = QtWidgets.QMenu() menu.setStyleSheet("QMenu {font-size:" + str(self.app.settings['fontsize']) + "pt} ") @@ -343,6 +346,8 @@ def table_menu(self, position): action_order_by_value_asc = None action_order_by_value_desc = None action_date_picker = None + action_ref_apa = None + action_ref_vancouver = None if col > self.CASE_COLUMN: action_order_by_value_asc = menu.addAction(_("Order ascending")) action_order_by_value_desc = menu.addAction(_("Order descending")) @@ -355,6 +360,9 @@ def table_menu(self, position): result = cur.fetchone() if result is not None and result[0] == "character": action_date_picker = menu.addAction(_("Enter date")) + if self.header_labels[col] in ("Ref_Authors", "Ref_Title", "Ref_Journal", "Ref_Type", "Ref_Year"): + action_ref_apa = menu.addAction(_("Copy reference to clipboard. APA")) + action_ref_vancouver = menu.addAction(_("Copy reference to clipboard. Vancouver")) action_rename = None action_export = None action_delete = None @@ -438,15 +446,31 @@ def table_menu(self, position): if action == action_url: webbrowser.open(item_text) if action == action_date_picker: - ui = DialogMemo(self.app, "Date selector", "", "hide") - ui.ui.textEdit.hide() + ui_memo = DialogMemo(self.app, "Date selector", "", "hide") + ui_memo.ui.textEdit.hide() calendar = QtWidgets.QCalendarWidget() - ui.ui.gridLayout.addWidget(calendar, 0, 0, 1, 1) - ok = ui.exec() + ui_memo.ui.gridLayout.addWidget(calendar, 0, 0, 1, 1) + ok = ui_memo.exec() if ok: selected_date = calendar.selectedDate().toString("yyyy-MM-dd") self.ui.tableWidget.setItem(row, col, QtWidgets.QTableWidgetItem(selected_date)) return + if action == action_ref_apa: + ris_obj = Ris(self.app) + ris_obj.get_references(selected_ris=risid) + apa = ris_obj.refs + if not apa: + return + cb = QtWidgets.QApplication.clipboard() + cb.setText(apa[0]['apa'].replace("\n", " ")) + if action == action_ref_vancouver: + ris_obj = Ris(self.app) + ris_obj.get_references(selected_ris=risid) + vancouver = ris_obj.refs + if not vancouver: + return + cb = QtWidgets.QApplication.clipboard() + cb.setText(vancouver[0]['vancouver'].replace("\n", " ")) def view_original_text_file(self, mediapath): """ View original text file. @@ -773,14 +797,14 @@ def load_file_data(self, order_by=""): self.source = [] cur = self.app.conn.cursor() placeholders = None - # default alphabetic order - sql = "select name, id, fulltext, mediapath, ifnull(memo,''), owner, date, av_text_id from source order by upper(name)" + # Default alphabetic order + sql = "select name, id, fulltext, mediapath, ifnull(memo,''), owner, date, av_text_id, risid from source order by upper(name)" if order_by == "filename desc": sql += " desc" if order_by == "date": - sql = "select name, id, fulltext, mediapath, ifnull(memo,''), owner, date, av_text_id from source order by date, upper(name)" + sql = "select name, id, fulltext, mediapath, ifnull(memo,''), owner, date, av_text_id, risid from source order by date, upper(name)" if order_by == "filetype": - sql = "select name, id, fulltext, mediapath, ifnull(memo,''), owner, date, av_text_id from source order by mediapath" + sql = "select name, id, fulltext, mediapath, ifnull(memo,''), owner, date, av_text_id, risid from source order by mediapath" if order_by == "casename": sql = "select distinct source.name, source.id, source.fulltext, source.mediapath, ifnull(source.memo,''), " sql += "source.owner, source.date, av_text_id " @@ -790,11 +814,11 @@ def load_file_data(self, order_by=""): if order_by[:14] == "attribute asc:": attribute_name = order_by[14:] - # two types of ordering character or numeric + # Two types of ordering character or numeric cur.execute("select valuetype from attribute_type where name=?", [attribute_name]) attr_type = cur.fetchone()[0] sql = "select source.name, source.id, fulltext, mediapath, ifnull(source.memo,''), source.owner, " - sql += "source.date, av_text_id from source join attribute on attribute.id = source.id " + sql += "source.date, av_text_id, risid from source join attribute on attribute.id = source.id " sql += " where attribute.attr_type = 'file' and attribute.name=? " if attr_type == "character": sql += "order by lower(attribute.value) asc " @@ -808,7 +832,7 @@ def load_file_data(self, order_by=""): cur.execute("select valuetype from attribute_type where name=?", [attribute_name]) attr_type = cur.fetchone()[0] sql = "select source.name, source.id, fulltext, mediapath, ifnull(source.memo,''), source.owner, " - sql += "source.date, av_text_id from source join attribute on attribute.id = source.id " + sql += "source.date, av_text_id, risid from source join attribute on attribute.id = source.id " sql += " where attribute.attr_type = 'file' and attribute.name=? " if attr_type == "character": sql += "order by lower(attribute.value) desc " @@ -825,7 +849,7 @@ def load_file_data(self, order_by=""): icon, metadata = self.get_icon_and_metadata(row[1]) self.source.append({'name': row[0], 'id': row[1], 'fulltext': row[2], 'mediapath': row[3], 'memo': row[4], 'owner': row[5], 'date': row[6], - 'av_text_id': row[7], 'metadata': metadata, 'icon': icon, + 'av_text_id': row[7], 'risid': row[8], 'metadata': metadata, 'icon': icon, 'case': self.get_cases_by_filename(row[0]), 'attributes': []}) @@ -852,6 +876,9 @@ def load_file_data(self, order_by=""): if att_name == "Ref_authors": tmp = tmp.replace(";", "\n") s['attributes'].append(tmp) + # Get reference for file, Vancouver and APA style + # TODO + self.fill_table() def get_icon_and_metadata(self, id_): @@ -998,18 +1025,17 @@ def add_attribute(self): Then get the attribute type through a dialog. AddAttribute dialog checks for duplicate attribute name. New attribute is added to the model and database. - Reserved attribute words - usef for imported references: + Reserved attribute words - used for imported references: Ref_Type (Type of Reference) – character variable Ref_Author (authors list) – character Ref_Title – character Ref_Year (of publication) – numeric + Ref_Journal - character """ if self.av_dialog_open is not None: self.av_dialog_open.mediaplayer.stop() self.av_dialog_open = None - '''check_names = self.attribute_names + [{'name': 'Ref_Type'}, {'name': 'Ref_Author'}, {'name': 'Ref_Title'}, - {'name':'Ref_Year'}]''' ui = DialogAddAttribute(self.app) ok = ui.exec() if not ok: @@ -2049,7 +2075,7 @@ def fill_table(self): for offset, attribute in enumerate(data['attributes']): item = QtWidgets.QTableWidgetItem(attribute) self.ui.tableWidget.setItem(row, self.ATTRIBUTE_START_COLUMN + offset, item) - if self.attribute_labels_ordered[offset] in ("Ref_Authors", "Ref_Title", "Ref_Type", "Ref_Year"): + if self.attribute_labels_ordered[offset] in ("Ref_Authors", "Ref_Title", "Ref_Type", "Ref_Year", "Ref_Journal"): item.setFlags(item.flags() ^ QtCore.Qt.ItemFlag.ItemIsEditable) # Resize columns and rows self.ui.tableWidget.hideColumn(self.ID_COLUMN) diff --git a/qualcoder/manage_references.py b/qualcoder/manage_references.py index c60dd9cc9..6ece55751 100644 --- a/qualcoder/manage_references.py +++ b/qualcoder/manage_references.py @@ -505,14 +505,14 @@ def table_refs_menu(self, position): if action == action_copy_to_clipboard: reference_text = self.ui.tableWidget_refs.item(row, 1).text() cb = QtWidgets.QApplication.clipboard() - cb.setText(reference_text) + cb.setText(reference_text.replace("\n", " ")) if action == action_copy_apa_to_clipboard: #reference_text = self.ui.tableWidget_refs.item(row, 1).text() ref_id = self.ui.tableWidget_refs.item(row, REF_ID).text() for ref in self.refs: if int(ref_id) == ref['risid']: cb = QtWidgets.QApplication.clipboard() - cb.setText(ref['apa']) + cb.setText(ref['apa'].replace("\n", " ")) def import_references(self): """ Import RIS formatted references from .ris or .txt files """ diff --git a/qualcoder/ris.py b/qualcoder/ris.py index 50fe7ea3b..6b01973b1 100644 --- a/qualcoder/ris.py +++ b/qualcoder/ris.py @@ -54,7 +54,7 @@ def exception_handler(exception_type, value, tb_obj): class Ris: """ Load ris list of dictionaries. - Format RIS to short display. + Format RIS to Vancouver or APA for display. References in RIS can be poorly created often due to how the researcher created them. """ app = None @@ -64,13 +64,20 @@ def __init__(self, app): sys.excepthook = exception_handler self.app = app - def get_references(self): - """ As list of dictionaries with risid and summary + def get_references(self, selected_ris=None): + """ As list of dictionaries with risid and summary. + """ - cur = self.app.conn.cursor() + self.refs = [] - cur.execute("select distinct risid from ris order by risid") + cur = self.app.conn.cursor() + if not selected_ris: + cur.execute("select distinct risid from ris order by risid") + else: + cur.execute("select distinct risid from ris where risid=?", [selected_ris]) ris_ids_res = cur.fetchall() + if not ris_ids_res: # May be empty if selected_ris is incorrect or no references present + return for ris_id in ris_ids_res: ref = {'risid': ris_id[0]} details = str(ris_id[0]) + " " @@ -142,13 +149,13 @@ def format_vancouver_and_apa(self, ref): issn = None url = None doi = None - vancouver = "" - apa = "" # American Psychological Association refernce style + vancouver = "" # Vancouver reference style, approximately + apa = "" # American Psychological Association reference style # Get the first title based on this order for tag in ("TI", "T1", "ST", "TT"): try: - title = ref[tag] + "\n" + title = f"{ref[tag]}.\n" break except KeyError: pass @@ -162,7 +169,7 @@ def format_vancouver_and_apa(self, ref): authors = authors[1:] + "\n" # Editor if 'ED' in ref: - editor = "Editor: " + ref['ED'] + "\n" + editor = f"Editor: {ref['ED']} \n" # Publication year if 'PY' in ref: published_year = ref['PY'] @@ -172,15 +179,15 @@ def format_vancouver_and_apa(self, ref): if 'PB' in ref: publisher = ref['PB'] if 'PP' in ref: - publisher += " " + ref['PP'] + publisher += f" {ref['PP']}" # ISSN if 'SN' in ref: - issn = "ISSN: " + ref['SN'] + issn = f"ISSN: {ref['SN']}" # Journal name, T2 tag is often used for this for tag in ("JO", "JF", "T2", "JA", "J1", "J2"): try: if periodical_name == "": - periodical_name = ref[tag] + " " + periodical_name = f"{ref[tag]} " continue except KeyError: pass @@ -189,14 +196,14 @@ def format_vancouver_and_apa(self, ref): edition = ref['ET'] # Volume and issue if 'VL' in ref: - volume = " Vol." + ref['VL'] + volume = f" Vol.{ref['VL']}" if volume is None and 'VO' in ref: volume = " Vol." + ref['VO'] if 'IS' in ref: issue = ref['IS'] volume_and_or_issue = "" if volume and issue: - volume_and_or_issue = volume + "(" + issue + ") " + volume_and_or_issue = volume + f"({issue}) " if volume is None and issue: volume_and_or_issue += " " + issue + " " if volume_and_or_issue == "" and edition: @@ -215,9 +222,9 @@ def format_vancouver_and_apa(self, ref): if 'UR' in ref: url = ref['UR'] if 'Y2' in ref: - url += " Accessed: " + ref['Y2'] + url += f" Accessed: {ref['Y2']}" if 'DO' in ref: - doi = "doi: " + ref['DO'] + doi = f"doi: {ref['DO']}" # Wrap up Vancouver style reference vancouver = title + authors @@ -252,9 +259,11 @@ def format_vancouver_and_apa(self, ref): if published_year != "": apa += f"({published_year}). " if title != "": - apa += f"{title}." - apa += f"{periodical_name}, " - apa += f"{volume_and_or_issue}. " + apa += f"{title}" + if periodical_name != "": + apa += f"{periodical_name}, " + if volume_and_or_issue != "": + apa += f"{volume_and_or_issue}. " if pages: apa += f"({pages})" if url is not None: