mirror of
				https://github.com/saitohirga/WSJT-X.git
				synced 2025-10-30 20:40:28 -04:00 
			
		
		
		
	Merge branch 'hotfix-2.0.0-rc5'
This commit is contained in:
		
						commit
						737d2f2bc6
					
				| @ -16,7 +16,7 @@ set (hamlib_LIBRARY_DIRS) | ||||
| 
 | ||||
| # pkg-config? | ||||
| find_path (__hamlib_pc_path NAMES hamlib.pc | ||||
|   PATH_SUFFIXES lib/pkgconfig | ||||
|   PATH_SUFFIXES lib/pkgconfig lib64/pkgconfig | ||||
|   ) | ||||
| if (__hamlib_pc_path) | ||||
|   set (ENV{PKG_CONFIG_PATH} "${__hamlib_pc_path}" "$ENV{PKG_CONFIG_PATH}") | ||||
|  | ||||
| @ -265,6 +265,7 @@ set (wsjt_qt_CXXSRCS | ||||
|   models/DecodeHighlightingModel.cpp | ||||
|   widgets/DecodeHighlightingListView.cpp | ||||
|   models/FoxLog.cpp | ||||
|   widgets/AbstractLogWindow.cpp | ||||
|   widgets/FoxLogWindow.cpp | ||||
|   widgets/CabrilloLogWindow.cpp | ||||
|   item_delegates/CallsignDelegate.cpp | ||||
| @ -382,7 +383,6 @@ set (wsjt_FSRCS | ||||
|   lib/badmsg.f90 | ||||
|   lib/ft8/baseline.f90 | ||||
|   lib/bpdecode40.f90 | ||||
|   lib/bpdecode144.f90 | ||||
|   lib/bpdecode128_90.f90 | ||||
|   lib/ft8/bpdecode174.f90 | ||||
|   lib/ft8/bpdecode174_91.f90 | ||||
| @ -414,7 +414,6 @@ set (wsjt_FSRCS | ||||
|   lib/encode232.f90 | ||||
|   lib/encode4.f90 | ||||
|   lib/encode_msk40.f90 | ||||
|   lib/encode_msk144.f90 | ||||
|   lib/encode_128_90.f90 | ||||
|   lib/ft8/encode174.f90 | ||||
|   lib/ft8/encode174_91.f90 | ||||
| @ -422,7 +421,6 @@ set (wsjt_FSRCS | ||||
|   lib/ephem.f90 | ||||
|   lib/extract.f90 | ||||
|   lib/extract4.f90 | ||||
|   lib/extractmessage144.f90 | ||||
|   lib/extractmessage77.f90 | ||||
|   lib/ft8/extractmessage174.f90 | ||||
|   lib/ft8/extractmessage174_91.f90 | ||||
| @ -497,10 +495,8 @@ set (wsjt_FSRCS | ||||
|   lib/moondopjpl.f90 | ||||
|   lib/morse.f90 | ||||
|   lib/move.f90 | ||||
|   lib/msk144d.f90 | ||||
|   lib/msk40decodeframe.f90 | ||||
|   lib/msk144decodeframe.f90 | ||||
|   lib/msk144sd.f90 | ||||
|   lib/msk40spd.f90 | ||||
|   lib/msk144spd.f90 | ||||
|   lib/msk40sync.f90 | ||||
| @ -519,6 +515,8 @@ set (wsjt_FSRCS | ||||
|   lib/peakdt9.f90 | ||||
|   lib/peakup.f90 | ||||
|   lib/plotsave.f90 | ||||
|   lib/platanh.f90 | ||||
|   lib/pltanh.f90 | ||||
|   lib/polyfit.f90 | ||||
|   lib/prog_args.f90 | ||||
|   lib/ps4.f90 | ||||
| @ -561,7 +559,6 @@ set (wsjt_FSRCS | ||||
|   lib/twkfreq.f90 | ||||
|   lib/ft8/twkfreq1.f90 | ||||
|   lib/twkfreq65.f90 | ||||
|   lib/unpackmsg144.f90 | ||||
|   lib/update_recent_calls.f90 | ||||
|   lib/update_hasharray.f90 | ||||
|   lib/ft8/watterson.f90 | ||||
| @ -1252,14 +1249,9 @@ target_link_libraries (ft8code wsjt_fort wsjt_cxx) | ||||
| add_executable (ft8sim lib/ft8/ft8sim.f90 wsjtx.rc) | ||||
| target_link_libraries (ft8sim wsjt_fort wsjt_cxx) | ||||
| 
 | ||||
| add_executable (msk144sd lib/msk144sd.f90 wsjtx.rc) | ||||
| target_link_libraries (msk144sd wsjt_fort wsjt_cxx) | ||||
| 
 | ||||
| add_executable (msk144sim lib/msk144sim.f90 wsjtx.rc) | ||||
| target_link_libraries (msk144sim wsjt_fort wsjt_cxx) | ||||
| 
 | ||||
| add_executable (msk144d lib/msk144d.f90 wsjtx.rc) | ||||
| target_link_libraries (msk144d wsjt_fort wsjt_cxx) | ||||
| endif(WSJT_BUILD_UTILS) | ||||
| 
 | ||||
| # build the main application | ||||
| @ -1708,11 +1700,11 @@ endif () | ||||
| 
 | ||||
| set (CPACK_DEBIAN_PACKAGE_DESCRIPTION "${PROJECT_DESCRIPTION}") | ||||
| set (CPACK_DEBIAN_PACKAGE_HOMEPAGE "${PROJECT_HOMEPAGE}") | ||||
| set (CPACK_DEBIAN_PACKAGE_DEPENDS "libgfortran3 (>=4.8.2), libqt5serialport5 (>=5.2), libqt5multimedia5-plugins (>=5.2), libqt5widgets5 (>=5.2), libusb-1.0-0, libudev1, libc6 (>=2.19)") | ||||
| set (CPACK_DEBIAN_PACKAGE_DEPENDS "libgfortran3 (>=4.8.2), libqt5serialport5 (>=5.5), libqt5multimedia5-plugins (>=5.5), libqt5widgets5 (>=5.5), libqt5sql5-sqlite (>=5.5), libusb-1.0-0, libudev1, libc6 (>=2.19)") | ||||
| set (CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) | ||||
| 
 | ||||
| set (CPACK_RPM_PACKAGE_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR}) | ||||
| set (CPACK_RPM_PACKAGE_REQUIRES "qt5-qtserialport >= 5.2, qt5-qtmultimedia >= 5.2, qt5-qtsvg, libusb, systemd-udev, glibc >= 2, libgfortran >= 4.8.2") | ||||
| set (CPACK_RPM_PACKAGE_REQUIRES "qt5-qtserialport >= 5.5, qt5-qtmultimedia >= 5.5, qt5-qtsvg, libusb, systemd-udev, glibc >= 2, libgfortran >= 4.8.2") | ||||
| set (CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION /usr/share/pixmaps /usr/share/applications /usr/share/man /usr/share/man1) | ||||
| 
 | ||||
| configure_file ("${PROJECT_SOURCE_DIR}/CMakeCPackOptions.cmake.in" | ||||
|  | ||||
| @ -1091,6 +1091,8 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network | ||||
|   frequencies_.sort (FrequencyList_v2::frequency_column); | ||||
| 
 | ||||
|   ui_->frequencies_table_view->setModel (&next_frequencies_); | ||||
|   ui_->frequencies_table_view->horizontalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents); | ||||
|   ui_->frequencies_table_view->verticalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents); | ||||
|   ui_->frequencies_table_view->sortByColumn (FrequencyList_v2::frequency_column, Qt::AscendingOrder); | ||||
|   ui_->frequencies_table_view->setColumnHidden (FrequencyList_v2::frequency_mhz_column, true); | ||||
| 
 | ||||
| @ -1131,6 +1133,8 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network | ||||
|   //
 | ||||
|   stations_.sort (StationList::band_column); | ||||
|   ui_->stations_table_view->setModel (&next_stations_); | ||||
|   ui_->stations_table_view->horizontalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents); | ||||
|   ui_->stations_table_view->verticalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents); | ||||
|   ui_->stations_table_view->sortByColumn (StationList::band_column, Qt::AscendingOrder); | ||||
| 
 | ||||
|   // stations delegates
 | ||||
| @ -2275,10 +2279,10 @@ void Configuration::impl::delete_selected_macros (QModelIndexList selected_rows) | ||||
| { | ||||
|   // sort in reverse row order so that we can delete without changing
 | ||||
|   // indices underneath us
 | ||||
|   qSort (selected_rows.begin (), selected_rows.end (), [] (QModelIndex const& lhs, QModelIndex const& rhs) | ||||
|          { | ||||
|            return rhs.row () < lhs.row (); // reverse row ordering
 | ||||
|          }); | ||||
|   std::sort (selected_rows.begin (), selected_rows.end (), [] (QModelIndex const& lhs, QModelIndex const& rhs) | ||||
|              { | ||||
|                return rhs.row () < lhs.row (); // reverse row ordering
 | ||||
|              }); | ||||
| 
 | ||||
|   // now delete them
 | ||||
|   Q_FOREACH (auto index, selected_rows) | ||||
|  | ||||
| @ -36,5 +36,7 @@ | ||||
|     <string>NSApplication</string> | ||||
|     <key>NSHighResolutionCapable</key> | ||||
|     <string>True</string> | ||||
|     <key>NSRequiresAquaSystemAppearance</key> | ||||
|     <true/> | ||||
| </dict> | ||||
| </plist> | ||||
|  | ||||
| @ -12,6 +12,31 @@ | ||||
|                                                           | ||||
| Copyright 2001 - 2018 by Joe Taylor, K1JT. | ||||
| 
 | ||||
| 		     Release: WSJT-X 2.0-rc5 | ||||
| 		        November 26, 2018 | ||||
| 		     ----------------------- | ||||
| 
 | ||||
| Release Candidate 5 ("RC5") is stable, works well, and fixes the known | ||||
| problems in RC4.  It is likely that the General Availability (GA) | ||||
| release of WSJT-X 2.0 will be nearly identical to RC5. | ||||
| 
 | ||||
| Changes from WSJT-X 2.0-rc4 include the following: | ||||
| 
 | ||||
|  -  Make the "Auto Seq" checkbox sticky, again | ||||
|  -  Remove the 5-minute mouse timer | ||||
|  -  Correct the "worked before" logic for color highlighting | ||||
|  -  Add "No own call decodes" checkbox in WSPR mode | ||||
|  -  Display and log UTC (not local time) in contest operations | ||||
|  -  Validate contest QSO details before allowing logging | ||||
|  -  Force Aqua theme on macOS to avoid issues with Mojave dark theme | ||||
|  -  Move Fox log Reset action to Fox log window context menu | ||||
|  -  Improve layout of Working Frequencies and Station Information tables | ||||
|  -  Allow deletes and editing in Fox and Contest log windows | ||||
|  -  Add Tool Tips for Fox and Contest log windows | ||||
|  -  Fix a bug causing false AP decodes in JT65 VHF+ operation | ||||
|  -  Fix a bug that could switch unexpectedly from JT65 to JT9 mode | ||||
| 
 | ||||
| 
 | ||||
| 		     Release: WSJT-X 2.0-rc4 | ||||
| 		        November 12, 2018 | ||||
| 		     ----------------------- | ||||
|  | ||||
| @ -2,5 +2,5 @@ | ||||
| set (WSJTX_VERSION_MAJOR 2) | ||||
| set (WSJTX_VERSION_MINOR 0) | ||||
| set (WSJTX_VERSION_PATCH 0) | ||||
| set (WSJTX_RC 4)		 # release candidate number, comment out or zero for development versions | ||||
| set (WSJTX_RC 5)		 # release candidate number, comment out or zero for development versions | ||||
| set (WSJTX_VERSION_IS_RELEASE 0) # set to 1 for final release build | ||||
|  | ||||
| @ -20,6 +20,7 @@ DecodedText::DecodedText (QString const& the_string) | ||||
|   , message_ {string_.mid (column_qsoText + padding_).trimmed ()} | ||||
|   , is_standard_ {false} | ||||
| { | ||||
| //  qDebug () << "DecodedText: the_string:" << the_string << "Nbsp pos:" << the_string.indexOf (QChar::Nbsp);
 | ||||
|   if (message_.length() >= 1) | ||||
|     { | ||||
|        message0_ = message_.left(36); | ||||
|  | ||||
| @ -28,7 +28,7 @@ public: | ||||
| 
 | ||||
|   static QDateTime to_date_time (QVariant const& value) | ||||
|   { | ||||
|     return QDateTime::fromMSecsSinceEpoch (value.toULongLong () * 1000ull); | ||||
|     return QDateTime::fromMSecsSinceEpoch (value.toULongLong () * 1000ull, Qt::UTC); | ||||
|   } | ||||
| 
 | ||||
|   QString displayText (QVariant const& value, QLocale const& locale) const override | ||||
|  | ||||
| @ -1,7 +1,10 @@ | ||||
| #include "ForeignKeyDelegate.hpp" | ||||
| 
 | ||||
| #include <QApplication> | ||||
| #include <QComboBox> | ||||
| 
 | ||||
| #include <QFontMetrics> | ||||
| #include <QSize> | ||||
| #include <QStyleOptionViewItem> | ||||
| #include "CandidateKeyFilter.hpp" | ||||
| 
 | ||||
| ForeignKeyDelegate::ForeignKeyDelegate (QAbstractItemModel const * referenced_model | ||||
| @ -40,3 +43,20 @@ QWidget * ForeignKeyDelegate::createEditor (QWidget * parent | ||||
|   editor->setSizeAdjustPolicy (QComboBox::AdjustToContents); | ||||
|   return editor; | ||||
| } | ||||
| 
 | ||||
| QSize ForeignKeyDelegate::sizeHint (QStyleOptionViewItem const& option, QModelIndex const& index) const | ||||
| { | ||||
|   auto size_hint = QStyledItemDelegate::sizeHint (option, index); | ||||
|   QFontMetrics metrics {option.font}; | ||||
|   QStyleOptionComboBox combo_box_option; | ||||
|   combo_box_option.rect = option.rect; | ||||
|   combo_box_option.state = option.state | QStyle::State_Enabled; | ||||
|   for (auto row = 0; row < candidate_key_filter_->rowCount (); ++row) | ||||
|     { | ||||
|       size_hint = size_hint.expandedTo (qApp->style ()->sizeFromContents (QStyle::CT_ComboBox | ||||
|                                                                           , &combo_box_option | ||||
|                                                                           , {metrics.width (candidate_key_filter_->data (candidate_key_filter_->index (row, 0)).toString ()) | ||||
|                                                                               , metrics.height ()})); | ||||
|     } | ||||
|   return size_hint; | ||||
| } | ||||
|  | ||||
| @ -33,9 +33,10 @@ public: | ||||
|                                , int referencing_key_role = Qt::EditRole); | ||||
|   ~ForeignKeyDelegate (); | ||||
| 
 | ||||
|   QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override; | ||||
| 
 | ||||
| private: | ||||
|   QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override; | ||||
|   QSize sizeHint (QStyleOptionViewItem const&, QModelIndex const&) const override; | ||||
| 
 | ||||
|   QScopedPointer<CandidateKeyFilter> candidate_key_filter_; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -10,12 +10,12 @@ subtypes. | ||||
| i3.n3 Example message                    Bits           Total  Purpose | ||||
| ---------------------------------------------------------------------------------- | ||||
| 0.0   FREE TEXT MSG                      71               71   Free text  | ||||
| 0.1   K1ABC RR73; W9XYZ <KH1/KH7Z> -11   28 28 10 5       71   DXpedition Mode | ||||
| 0.1   K1ABC RR73; W9XYZ <KH1/KH7Z> -12   28 28 10 5       71   DXpedition Mode | ||||
| 0.2   PA3XYZ/P R 590003 IO91NP           28 1 1 3 12 25   70   EU VHF contest | ||||
| 0.3   WA9XYZ KA1ABC R 16A EMA            28 28 1 4 3 7    71   ARRL Field Day | ||||
| 0.4   WA9XYZ KA1ABC R 32A EMA            28 28 1 4 3 7    71   ARRL Field Day | ||||
| 0.5   123456789ABCDEF012                 71               71   Telemetry (18 hex) | ||||
| 0.6   ... tbd    | ||||
| 0.6   K1ABC RR73; CQ W9XYZ EN37          28 28 15         71   Contesting | ||||
| 0.7   ... tbd | ||||
| 
 | ||||
| 1     WA9XYZ/R KA1ABC/R R FN42           28 1 28 1 1 15   74   Standard msg | ||||
|  | ||||
| @ -1,75 +0,0 @@ | ||||
| 
 | ||||
| # Set paths
 | ||||
| EXE_DIR = ..\\..\\wsjtx_install | ||||
| QT_DIR = C:/wsjt-env/Qt5/5.2.1/mingw48_32 | ||||
| FFTW3_DIR = .. | ||||
| 
 | ||||
| INCPATH = -I${QT_DIR}/include/QtCore -I${QT_DIR}/include  | ||||
| 
 | ||||
| # Compilers
 | ||||
| CC = gcc | ||||
| CXX = g++ | ||||
| FC = gfortran | ||||
| AR = ar cr | ||||
| RANLIB = ranlib | ||||
| MKDIR = mkdir -p | ||||
| CP = cp | ||||
| RM = rm -f | ||||
| 
 | ||||
| FFLAGS = -O2 -fbounds-check -Wall -Wno-conversion | ||||
| CFLAGS = -O2 -I.  | ||||
| 
 | ||||
| # Default rules
 | ||||
| %.o: %.c | ||||
| 	${CC} ${CFLAGS} -c $< | ||||
| %.o: %.f | ||||
| 	${FC} ${FFLAGS} -c $< | ||||
| %.o: %.F | ||||
| 	${FC} ${FFLAGS} -c $< | ||||
| %.o: %.f90 | ||||
| 	${FC} ${FFLAGS} -c $< | ||||
| %.o: %.F90 | ||||
| 	${FC} ${FFLAGS} -c $< | ||||
| 
 | ||||
| #all:    jt9code JTMSKcode.exe
 | ||||
| all:	 jtmsk.exe JTMSKsim.exe JTMSKcode.exe fixwav.exe | ||||
| 
 | ||||
| OBJS3 = JTMSKsim.o wavhdr.o gran.o four2a.o db.o | ||||
| JTMSKsim.exe: $(OBJS3) | ||||
| 	$(FC) -o JTMSKsim.exe $(OBJS3) C:\JTSDK\fftw3f\libfftw3f-3.dll | ||||
| 
 | ||||
| OBJS4 = jt9code.o packjt.o fmtmsg.o gen9.o deg2grid.o grid2deg.o \
 | ||||
|       entail.o encode232.o interleave9.o graycode.o igray.o | ||||
| jt9code: $(OBJS4)  | ||||
| 	$(FC) -o jt9code $(OBJS4)  | ||||
| 
 | ||||
| OBJS5 = JTMSKcode.o packjt.o fmtmsg.o genmsk.o deg2grid.o grid2deg.o \
 | ||||
|       entail.o tab.o vit213.o hashing.o nhash.o | ||||
| JTMSKcode.exe: $(OBJS5)  | ||||
| 	$(FC) -o JTMSKcode.exe $(OBJS5)  | ||||
| 
 | ||||
| OBJS6 = jtmsk.o analytic.o four2a.o db.o pctile.o \
 | ||||
|       shell.o tweak1.o syncmsk.o genmsk.o packjt.o fmtmsg.o indexx.o \
 | ||||
|       deg2grid.o grid2deg.o entail.o hashing.o nhash.o tab.o vit213.o \
 | ||||
|       mskdt.o rectify_msk.o timer.o jtmsk_decode.o genmsk_short.o \
 | ||||
|       jtmsk_short.o golay24_table.o hash.o | ||||
| 
 | ||||
| jtmsk.exe: $(OBJS6)  | ||||
| 	$(FC) -o jtmsk.exe $(OBJS6) C:\JTSDK\fftw3f\libfftw3f-3.dll | ||||
| 
 | ||||
| OBJS1 = fixwav.o wavhdr.o | ||||
| fixwav.exe: $(OBJS1) | ||||
| 	$(FC) -o fixwav.exe $(OBJS1) | ||||
| 
 | ||||
| OBJS2 = t2.o four2a.o db.o | ||||
| t2:   $(OBJS2) | ||||
| 	$(FC) -o t2 $(OBJS2) C:\JTSDK\fftw3f\libfftw3f-3.dll | ||||
| 
 | ||||
| OBJS6 = t6.o four2a.o db.o | ||||
| t6:   $(OBJS6) | ||||
| 	$(FC) -o t6 $(OBJS6) C:\JTSDK\fftw3f\libfftw3f-3.dll | ||||
| 
 | ||||
| .PHONY : clean | ||||
| 
 | ||||
| clean: | ||||
| 	$(RM) *.o JTMSKcode JTMSKcode.exe | ||||
| @ -1,111 +0,0 @@ | ||||
| subroutine encode_msk144(message,codeword) | ||||
| ! Encode an 80-bit message and return a 128-bit codeword.  | ||||
| ! The generator matrix has dimensions (48,80).  | ||||
| ! The code is a (128,80) regular ldpc code with column weight 3. | ||||
| ! The code was generated using the PEG algorithm. | ||||
| ! After creating the codeword, the columns are re-ordered according to  | ||||
| ! "colorder" to make the codeword compatible with the parity-check | ||||
| ! matrix stored in Radford Neal's "pchk" format. | ||||
| ! | ||||
| character*20 g(48) | ||||
| integer*1 codeword(128) | ||||
| integer*1 colorder(128) | ||||
| integer*1 gen144(48,80) | ||||
| integer*1 itmp(128) | ||||
| integer*1 message(80) | ||||
| integer*1 pchecks(48) | ||||
| logical first | ||||
| data first/.true./ | ||||
| data g/                  &  !parity-check generator matrix for (128,80) code | ||||
|  "24084000800020008000", & | ||||
|  "b39678f7ccdb1baf5f4c", & | ||||
|  "10001000400408012000", & | ||||
|  "08104000100002010800", & | ||||
|  "dc9c18f61ea0e4b7f05c", & | ||||
|  "42c040160909ca002c00", & | ||||
|  "cc50b52b9a80db0d7f9e", & | ||||
|  "dde5ace80780bae74740", & | ||||
|  "00800080020000890080", & | ||||
|  "01020040010400400040", & | ||||
|  "20008010020000100030", & | ||||
|  "80400008004000040050", & | ||||
|  "a4b397810915126f5604", & | ||||
|  "04040100001040200008", & | ||||
|  "00800006000888000800", & | ||||
|  "00010c00000104040001", & | ||||
|  "cc7cd7d953cdc204eba0", & | ||||
|  "0094abe7dd146beb16ce", & | ||||
|  "5af2aec8c7b051c7544a", & | ||||
|  "14040508801840200088", & | ||||
|  "7392f5e720f8f5a62c1e", & | ||||
|  "503cc2a06bff4e684ec9", & | ||||
|  "5a2efd46f1efbb513b80", & | ||||
|  "ac06e9513fd411f1de03", & | ||||
|  "16a31be3dd3082ca2bd6", & | ||||
|  "28542e0daf62fe1d9332", & | ||||
|  "00210c002001540c0401", & | ||||
|  "0ed90d56f84298706a98", & | ||||
|  "939670f7ecdf9baf4f4c", & | ||||
|  "cfe41dec47a433e66240", & | ||||
|  "16d2179c2d5888222630", & | ||||
|  "408000160108ca002800", & | ||||
|  "808000830a00018900a0", & | ||||
|  "9ae2ed8ef3afbf8c3a52", & | ||||
|  "5aaafd86f3efbfc83b02", & | ||||
|  "f39658f68cdb0baf1f4c", & | ||||
|  "9414bb6495106261366a", & | ||||
|  "71ba18670c08411bf682", & | ||||
|  "7298f1a7217cf5c62e5e", & | ||||
|  "86d7a4864396a981369b", & | ||||
|  "a8042c01ae22fe191362", & | ||||
|  "9235ae108b2d60d0e306", & | ||||
|  "dfe5ade807a03be74640", & | ||||
|  "d2451588e6e27ccd9bc4", & | ||||
|  "12b51ae39d20e2ea3bde", & | ||||
|  "a49387810d95136fd604", & | ||||
|  "467e7578e51d5b3b8a0e", & | ||||
|  "f6ad1ac7cc3aaa3fe580"/ | ||||
| 
 | ||||
| data colorder/0,1,2,3,4,5,6,7,8,9, & | ||||
|               10,11,12,13,14,15,24,26,29,30, & | ||||
|               32,43,44,47,60,77,79,97,101,111, & | ||||
|               96,38,64,53,93,34,59,94,74,90, & | ||||
|               108,123,85,57,70,25,69,62,48,49, & | ||||
|               50,51,52,33,54,55,56,21,58,36, & | ||||
|               16,61,23,63,20,65,66,67,68,46, & | ||||
|               22,71,72,73,31,75,76,45,78,17, & | ||||
|               80,81,82,83,84,42,86,87,88,89, & | ||||
|               39,91,92,35,37,95,19,27,98,99, & | ||||
|               100,28,102,103,104,105,106,107,40,109, & | ||||
|               110,18,112,113,114,115,116,117,118,119, & | ||||
|               120,121,122,41,124,125,126,127/ | ||||
| 
 | ||||
| save first,gen144 | ||||
| 
 | ||||
| if( first ) then ! fill the generator matrix | ||||
|   gen144=0 | ||||
|   do i=1,48 | ||||
|     do j=1,5 | ||||
|       read(g(i)( (j-1)*4+1:(j-1)*4+4 ),"(Z4)") istr | ||||
|         do jj=1,16 | ||||
|           icol=(j-1)*16+jj | ||||
|           if( btest(istr,16-jj) ) gen144(i,icol)=1 | ||||
|         enddo | ||||
|     enddo | ||||
|   enddo | ||||
| first=.false. | ||||
| endif | ||||
| 
 | ||||
| do i=1,48 | ||||
|   nsum=0 | ||||
|   do j=1,80 | ||||
|     nsum=nsum+message(j)*gen144(i,j) | ||||
|   enddo | ||||
|   pchecks(i)=mod(nsum,2) | ||||
| enddo | ||||
| itmp(1:48)=pchecks | ||||
| itmp(49:128)=message(1:80) | ||||
| codeword(colorder+1)=itmp(1:128) | ||||
| 
 | ||||
| return | ||||
| end subroutine encode_msk144 | ||||
| @ -1,51 +0,0 @@ | ||||
| subroutine extractmessage144(decoded,msgreceived,nhashflag,recent_calls,nrecent) | ||||
|   use iso_c_binding, only: c_loc,c_size_t | ||||
|   use packjt | ||||
|   use hashing | ||||
| 
 | ||||
|   character*22 msgreceived | ||||
|   character*12 call1,call2 | ||||
|   character*12 recent_calls(nrecent) | ||||
|   integer*1 decoded(80) | ||||
|   integer*1, target::  i1Dec8BitBytes(10) | ||||
|   integer*1 i1hashdec | ||||
|   integer*4 i4Dec6BitWords(12) | ||||
| 
 | ||||
| ! Collapse 80 decoded bits to 10 bytes. Bytes 1-9 are the message, byte 10 is the hash | ||||
|   do ibyte=1,10 | ||||
|       itmp=0 | ||||
|     do ibit=1,8 | ||||
|       itmp=ishft(itmp,1)+iand(1,decoded((ibyte-1)*8+ibit)) | ||||
|     enddo | ||||
|     i1Dec8BitBytes(ibyte)=itmp | ||||
|   enddo | ||||
| 
 | ||||
| ! Calculate the hash using the first 9 bytes. | ||||
|   ihashdec=nhash(c_loc(i1Dec8BitBytes),int(9,c_size_t),146) | ||||
|   ihashdec=2*iand(ihashdec,255) | ||||
| 
 | ||||
| ! Compare calculated hash with received byte 10 - if they agree, keep the message. | ||||
|   i1hashdec=ihashdec | ||||
|   if( i1hashdec .eq. i1Dec8BitBytes(10) ) then | ||||
| ! Good hash --- unpack 72-bit message | ||||
|     do ibyte=1,12 | ||||
|       itmp=0 | ||||
|       do ibit=1,6 | ||||
|         itmp=ishft(itmp,1)+iand(1,decoded((ibyte-1)*6+ibit)) | ||||
|       enddo | ||||
|       i4Dec6BitWords(ibyte)=itmp | ||||
|     enddo | ||||
|     call unpackmsg144(i4Dec6BitWords,msgreceived,call1,call2) | ||||
|     nhashflag=1 | ||||
|     if( call1(1:2) .ne. 'CQ' .and. call1(1:2) .ne. '  ' ) then | ||||
|       call update_recent_calls(call1,recent_calls,nrecent) | ||||
|     endif | ||||
|     if( call2(1:2) .ne. '  ' ) then | ||||
|       call update_recent_calls(call2,recent_calls,nrecent) | ||||
|     endif | ||||
|   else | ||||
|     msgreceived=' ' | ||||
|     nhashflag=-1 | ||||
|   endif  | ||||
|   return | ||||
|   end subroutine extractmessage144 | ||||
| @ -1,146 +0,0 @@ | ||||
| subroutine genmsk144(msg0,mygrid,ichk,msgsent,i4tone,itype) | ||||
| ! s8 + 48bits + s8 + 80 bits = 144 bits (72ms message duration) | ||||
| ! | ||||
| ! Encode an MSK144 message | ||||
| ! Input: | ||||
| !   - msg0     requested message to be transmitted | ||||
| !   - ichk     if ichk=1, return only msgsent | ||||
| !              if ichk.ge.10000, set imsg=ichk-10000 for short msg | ||||
| !   - msgsent  message as it will be decoded | ||||
| !   - i4tone   array of audio tone values, 0 or 1 | ||||
| !   - itype    message type  | ||||
| !                 1 = standard message  "Call_1 Call_2 Grid/Rpt" | ||||
| !                 2 = type 1 prefix | ||||
| !                 3 = type 1 suffix | ||||
| !                 4 = type 2 prefix | ||||
| !                 5 = type 2 suffix | ||||
| !                 6 = free text (up to 13 characters) | ||||
| !                 7 = short message     "<Call_1 Call2> Rpt" | ||||
| 
 | ||||
|   use iso_c_binding, only: c_loc,c_size_t | ||||
|   use packjt | ||||
|   use hashing | ||||
|   character*22 msg0 | ||||
|   character*22 message                    !Message to be generated | ||||
|   character*22 msgsent                    !Message as it will be received | ||||
|   character*6 mygrid | ||||
|   integer*4 i4Msg6BitWords(13)            !72-bit message as 6-bit words | ||||
|   integer*4 i4tone(144)                   ! | ||||
|   integer*1, target:: i1Msg8BitBytes(10)  !80 bits represented in 10 bytes  | ||||
|   integer*1 codeword(128)                 !Encoded bits before re-ordering | ||||
|   integer*1 msgbits(80)                   !72-bit message + 8-bit hash | ||||
|   integer*1 bitseq(144)                   !Tone #s, data and sync (values 0-1) | ||||
|   integer*1 i1hash(4) | ||||
|   integer*1 s8(8) | ||||
|   real*8 pp(12) | ||||
|   real*8 xi(864),xq(864),pi,twopi | ||||
|   data s8/0,1,1,1,0,0,1,0/ | ||||
|   equivalence (ihash,i1hash) | ||||
|   logical first | ||||
|   data first/.true./ | ||||
|   save | ||||
| 
 | ||||
|   if(first) then | ||||
|     first=.false. | ||||
|     nsym=128 | ||||
|     pi=4.0*atan(1.0) | ||||
|     twopi=8.*atan(1.0) | ||||
|     do i=1,12 | ||||
|       pp(i)=sin((i-1)*pi/12) | ||||
|     enddo | ||||
|   endif | ||||
| 
 | ||||
|   if(msg0(1:1).eq.'@') then                    !Generate a fixed tone | ||||
|      read(msg0(2:5),*,end=1,err=1) nfreq       !at specified frequency | ||||
|      go to 2 | ||||
| 1    nfreq=1000 | ||||
| 2    i4tone(1)=nfreq | ||||
|   else | ||||
|      message=msg0 | ||||
|      do i=1,22 | ||||
|         if(ichar(message(i:i)).eq.0) then | ||||
|            message(i:)='                      ' | ||||
|            exit | ||||
|         endif | ||||
|      enddo | ||||
| 
 | ||||
|      do i=1,22                               !Strip leading blanks | ||||
|         if(message(1:1).ne.' ') exit | ||||
|         message=message(i+1:) | ||||
|      enddo | ||||
| 
 | ||||
|      if(message(1:1).eq.'<') then | ||||
|         call genmsk40(message,msgsent,ichk,i4tone,itype) | ||||
|         if(itype.lt.0) go to 999 | ||||
|         i4tone(41)=-40 | ||||
|         go to 999 | ||||
|      endif | ||||
| 
 | ||||
|      call packmsg(message,i4Msg6BitWords,itype) !Pack into 12 6-bit bytes | ||||
|      call unpackmsg(i4Msg6BitWords,msgsent)     !Unpack to get msgsent | ||||
| 
 | ||||
|      if(ichk.eq.1) go to 999 | ||||
|      i4=0 | ||||
|      ik=0 | ||||
|      im=0 | ||||
|      do i=1,12 | ||||
|        nn=i4Msg6BitWords(i) | ||||
|        do j=1, 6 | ||||
|          ik=ik+1 | ||||
|          i4=i4+i4+iand(1,ishft(nn,j-6)) | ||||
|          i4=iand(i4,255) | ||||
|          if(ik.eq.8) then | ||||
|            im=im+1 | ||||
|            i1Msg8BitBytes(im)=i4 | ||||
|            ik=0 | ||||
|          endif | ||||
|        enddo | ||||
|      enddo | ||||
| 
 | ||||
|      ihash=nhash(c_loc(i1Msg8BitBytes),int(9,c_size_t),146) | ||||
|      ihash=2*iand(ihash,32767)                   !Generate the 8-bit hash | ||||
|      i1Msg8BitBytes(10)=i1hash(1)                !Hash code to byte 10 | ||||
| 
 | ||||
|      mbit=0 | ||||
|      do i=1, 10 | ||||
|        i1=i1Msg8BitBytes(i) | ||||
|          do ibit=1,8 | ||||
|            mbit=mbit+1 | ||||
|            msgbits(mbit)=iand(1,ishft(i1,ibit-8)) | ||||
|          enddo | ||||
|      enddo | ||||
| 
 | ||||
|      call encode_msk144(msgbits,codeword) | ||||
| 
 | ||||
| !Create 144-bit channel vector: | ||||
| !8-bit sync word + 48 bits + 8-bit sync word + 80 bits | ||||
|      bitseq=0  | ||||
|      bitseq(1:8)=s8 | ||||
|      bitseq(9:56)=codeword(1:48) | ||||
|      bitseq(57:64)=s8 | ||||
|      bitseq(65:144)=codeword(49:128) | ||||
|      bitseq=2*bitseq-1 | ||||
| 
 | ||||
|      xq(1:6)=bitseq(1)*pp(7:12)   !first bit is mapped to 1st half-symbol on q | ||||
|      do i=1,71 | ||||
|        is=(i-1)*12+7 | ||||
|        xq(is:is+11)=bitseq(2*i+1)*pp | ||||
|      enddo  | ||||
|      xq(864-5:864)=bitseq(1)*pp(1:6)   !last half symbol | ||||
|      do i=1,72                                     | ||||
|        is=(i-1)*12+1 | ||||
|        xi(is:is+11)=bitseq(2*i)*pp | ||||
|      enddo | ||||
| ! Map I and Q  to tones.  | ||||
|     i4tone=0  | ||||
|     do i=1,72 | ||||
|       i4tone(2*i-1)=(bitseq(2*i)*bitseq(2*i-1)+1)/2; | ||||
|       i4tone(2*i)=-(bitseq(2*i)*bitseq(mod(2*i,144)+1)-1)/2; | ||||
|     enddo | ||||
|   endif | ||||
| 
 | ||||
| ! Flip polarity | ||||
|   i4tone=-i4tone+1 | ||||
| 
 | ||||
| 999 return | ||||
| end subroutine genmsk144 | ||||
| @ -1,66 +0,0 @@ | ||||
| subroutine genmsk_short(msg,msgsent,ichk,itone,itype) | ||||
| 
 | ||||
|   use hashing | ||||
|   character*22 msg,msgsent | ||||
|   character*3 crpt,rpt(0:7) | ||||
|   logical first | ||||
|   integer itone(35) | ||||
|   integer ig24(0:4096-1)                  !Codewords for Golay (24,12) code | ||||
|   integer b11(11) | ||||
|   data b11/1,1,1,0,0,0,1,0,0,1,0/         !Barker 11 code | ||||
|   data rpt /'26 ','27 ','28 ','R26','R27','R28','RRR','73 '/ | ||||
|   data first/.true./ | ||||
|   save first,ig24 | ||||
| 
 | ||||
|   if(first) then | ||||
|      call golay24_table(ig24)             !Define the Golay(24,12) codewords | ||||
|      first=.false. | ||||
|   endif | ||||
| 
 | ||||
|   itype=-1 | ||||
|   msgsent='*** bad message ***' | ||||
|   itone=0 | ||||
|   i1=index(msg,'>') | ||||
|   if(i1.lt.9) go to 900 | ||||
|   call fmtmsg(msg,iz) | ||||
|   crpt=msg(i1+2:i1+5) | ||||
|   do i=0,7 | ||||
|      if(crpt.eq.rpt(i)) go to 10 | ||||
|   enddo | ||||
|   go to 900 | ||||
| 
 | ||||
| 10 irpt=i                               !Report index, 0-7 | ||||
|   if(ichk.lt.10000) then | ||||
|      call hash(msg(2:i1-1),i1-2,ihash)   | ||||
|      ihash=iand(ihash,511)                 !9-bit hash for the two callsigns | ||||
|      ig=8*ihash + irpt                     !12-bit message information | ||||
|   else | ||||
|      ig=ichk-10000 | ||||
|   endif | ||||
|   ncodeword=ig24(ig) | ||||
|   itone(1:11)=b11                       !Insert the Barker-11 code | ||||
|   n=2**24 | ||||
|   do i=12,35                            !Insert codeword into itone array | ||||
|      n=n/2 | ||||
|      itone(i)=0 | ||||
|      if(iand(ncodeword,n).ne.0) itone(i)=1 | ||||
|   enddo  | ||||
|   msgsent=msg | ||||
|   itype=7 | ||||
| 
 | ||||
|   n=count(itone(1:35).eq.0) | ||||
|   if(mod(n,2).ne.0) stop 'Parity error in genmsk_short.' | ||||
| 
 | ||||
| 900 return | ||||
| end subroutine genmsk_short | ||||
| 
 | ||||
| subroutine hash_calls(calls,ih9) | ||||
| 
 | ||||
|   use hashing | ||||
|   character*(*) calls | ||||
|   i1=index(calls,'>') | ||||
|   call hash(calls(2:i1-1),i1-2,ih9) | ||||
|   ih9=iand(ih9,511)                      !9-bit hash for the two callsigns | ||||
| 
 | ||||
|   return | ||||
| end subroutine hash_calls | ||||
| @ -1,175 +0,0 @@ | ||||
| program ldpcsim | ||||
| 
 | ||||
| use, intrinsic :: iso_c_binding | ||||
| use iso_c_binding, only: c_loc,c_size_t | ||||
| use hashing | ||||
| use packjt | ||||
| parameter(NRECENT=10) | ||||
| character*12 recent_calls(NRECENT) | ||||
| character*22 msg,msgsent,msgreceived | ||||
| character*8 arg | ||||
| integer*1, allocatable ::  codeword(:), decoded(:), message(:) | ||||
| integer*1, target:: i1Msg8BitBytes(10) | ||||
| integer*1 i1hash(4) | ||||
| integer*1 msgbits(80) | ||||
| integer*4 i4Msg6BitWords(13) | ||||
| integer ihash | ||||
| integer nerrtot(0:128),nerrdec(0:128) | ||||
| real*8, allocatable ::  lratio(:), rxdata(:), rxavgd(:) | ||||
| real, allocatable :: yy(:), llr(:) | ||||
| equivalence(ihash,i1hash) | ||||
| 
 | ||||
| do i=1,NRECENT | ||||
|   recent_calls(i)='            ' | ||||
| enddo | ||||
| nerrtot=0 | ||||
| nerrdec=0 | ||||
| 
 | ||||
| nargs=iargc() | ||||
| if(nargs.ne.4) then | ||||
|    print*,'Usage: ldpcsim  niter   navg  #trials  s ' | ||||
|    print*,'eg:    ldpcsim    10     1     1000    0.75' | ||||
|    return | ||||
| endif | ||||
| call getarg(1,arg) | ||||
| read(arg,*) max_iterations  | ||||
| call getarg(2,arg) | ||||
| read(arg,*) navg  | ||||
| call getarg(3,arg) | ||||
| read(arg,*) ntrials  | ||||
| call getarg(4,arg) | ||||
| read(arg,*) s | ||||
| 
 | ||||
| ! don't count hash bits as data bits | ||||
| K=72 | ||||
| N=128 | ||||
| rate=real(K)/real(N) | ||||
| 
 | ||||
| write(*,*) "rate: ",rate | ||||
| 
 | ||||
| write(*,*) "niter= ",max_iterations," navg= ",navg," s= ",s | ||||
| 
 | ||||
| allocate ( codeword(N), decoded(K), message(K) ) | ||||
| allocate ( lratio(N), rxdata(N), rxavgd(N), yy(N), llr(N) ) | ||||
| 
 | ||||
| msg="K9AN K1JT EN50" | ||||
|   call packmsg(msg,i4Msg6BitWords,itype) !Pack into 12 6-bit bytes | ||||
|   call unpackmsg(i4Msg6BitWords,msgsent) !Unpack to get msgsent | ||||
|   write(*,*) "message sent ",msgsent | ||||
| 
 | ||||
|   i4=0 | ||||
|   ik=0 | ||||
|   im=0 | ||||
|   do i=1,12 | ||||
|     nn=i4Msg6BitWords(i) | ||||
|     do j=1, 6 | ||||
|       ik=ik+1 | ||||
|       i4=i4+i4+iand(1,ishft(nn,j-6)) | ||||
|       i4=iand(i4,255) | ||||
|       if(ik.eq.8) then | ||||
|         im=im+1 | ||||
| !           if(i4.gt.127) i4=i4-256 | ||||
|         i1Msg8BitBytes(im)=i4 | ||||
|         ik=0 | ||||
|       endif | ||||
|     enddo | ||||
|   enddo | ||||
|   | ||||
|   ihash=nhash(c_loc(i1Msg8BitBytes),int(9,c_size_t),146) | ||||
|   ihash=2*iand(ihash,32767)                   !Generate the 8-bit hash | ||||
|   i1Msg8BitBytes(10)=i1hash(1)                !Hash code to byte 10 | ||||
|   mbit=0 | ||||
|   do i=1, 10 | ||||
|     i1=i1Msg8BitBytes(i) | ||||
|     do ibit=1,8 | ||||
|       mbit=mbit+1 | ||||
|       msgbits(mbit)=iand(1,ishft(i1,ibit-8)) | ||||
|     enddo | ||||
|   enddo | ||||
|   call encode_msk144(msgbits,codeword) | ||||
|   call init_random_seed() | ||||
| 
 | ||||
| write(*,*) "Eb/N0  SNR2500   ngood  nundetected nbadhash  sigma" | ||||
| do idb = 14,-6,-1  | ||||
|   db=idb/2.0-1.0 | ||||
|   sigma=1/sqrt( 2*rate*(10**(db/10.0)) ) | ||||
|   ngood=0 | ||||
|   nue=0 | ||||
|   nbadhash=0 | ||||
| 
 | ||||
|   do itrial=1, ntrials | ||||
|     rxavgd=0d0 | ||||
|     do iav=1,navg | ||||
|       call sgran() | ||||
| ! Create a realization of a noisy received word | ||||
|       do i=1,N | ||||
|         rxdata(i) = 2.0*codeword(i)-1.0 + sigma*gran() | ||||
|       enddo | ||||
|       rxavgd=rxavgd+rxdata | ||||
|     enddo | ||||
|     rxdata=rxavgd | ||||
|     nerr=0 | ||||
|     do i=1,N | ||||
|       if( rxdata(i)*(2*codeword(i)-1.0) .lt. 0 ) nerr=nerr+1 | ||||
|     enddo | ||||
|     nerrtot(nerr)=nerrtot(nerr)+1 | ||||
| 
 | ||||
| ! Correct signal normalization is important for this decoder. | ||||
|     rxav=sum(rxdata)/N | ||||
|     rx2av=sum(rxdata*rxdata)/N | ||||
|     rxsig=sqrt(rx2av-rxav*rxav) | ||||
|     rxdata=rxdata/rxsig | ||||
| ! To match the metric to the channel, s should be set to the noise standard deviation.  | ||||
| ! For now, set s to the value that optimizes decode probability near threshold.  | ||||
| ! The s parameter can be tuned to trade a few tenth's dB of threshold for an order of | ||||
| ! magnitude in UER  | ||||
|     if( s .lt. 0 ) then | ||||
|       ss=sigma | ||||
|     else  | ||||
|       ss=s | ||||
|     endif | ||||
| 
 | ||||
|     llr=2.0*rxdata/(ss*ss) | ||||
|     lratio=exp(llr) | ||||
|     yy=rxdata | ||||
| 
 | ||||
| ! max_iterations is max number of belief propagation iterations | ||||
| !    call ldpc_decode(lratio, decoded, max_iterations, niterations, max_dither, ndither) | ||||
| !    call amsdecode(yy, max_iterations, decoded, niterations) | ||||
| !    call bitflipmsk144(rxdata, decoded, niterations) | ||||
|     call bpdecode144(llr, max_iterations, decoded, niterations) | ||||
| 
 | ||||
| ! If the decoder finds a valid codeword, niterations will be .ge. 0. | ||||
|     if( niterations .ge. 0 ) then | ||||
|       call extractmessage144(decoded,msgreceived,nhashflag,recent_calls,nrecent) | ||||
|       if( nhashflag .ne. 1 ) then | ||||
|         nbadhash=nbadhash+1 | ||||
|       endif | ||||
|       nueflag=0 | ||||
| 
 | ||||
| ! Check the message plus hash against what was sent. | ||||
|       do i=1,K | ||||
|         if( msgbits(i) .ne. decoded(i) ) then | ||||
|           nueflag=1 | ||||
|         endif | ||||
|       enddo | ||||
|       if( nhashflag .eq. 1 .and. nueflag .eq. 0 ) then | ||||
|         ngood=ngood+1 | ||||
|         nerrdec(nerr)=nerrdec(nerr)+1 | ||||
|       else if( nhashflag .eq. 1 .and. nueflag .eq. 1 ) then | ||||
|         nue=nue+1; | ||||
|       endif | ||||
|     endif | ||||
|   enddo | ||||
|   snr2500=db-3.5 | ||||
|   write(*,"(f4.1,4x,f5.1,1x,i8,1x,i8,1x,i8,8x,f5.2)") db,snr2500,ngood,nue,nbadhash,ss | ||||
| 
 | ||||
| enddo | ||||
| 
 | ||||
| open(unit=23,file='nerrhisto.dat',status='unknown') | ||||
| do i=0,128 | ||||
|   write(23,'(i4,2x,i10,i10,f10.2)') i,nerrdec(i),nerrtot(i),real(nerrdec(i))/real(nerrtot(i)+1e-10) | ||||
| enddo | ||||
| close(23) | ||||
| 
 | ||||
| end program ldpcsim | ||||
							
								
								
									
										136
									
								
								lib/msk144d.f90
									
									
									
									
									
								
							
							
						
						
									
										136
									
								
								lib/msk144d.f90
									
									
									
									
									
								
							| @ -1,136 +0,0 @@ | ||||
| program msk144d | ||||
| 
 | ||||
|   ! Test the msk144 decoder for WSJT-X | ||||
| 
 | ||||
|   use options | ||||
|   use timer_module, only: timer | ||||
|   use timer_impl, only: init_timer | ||||
|   use readwav | ||||
| 
 | ||||
|   character c | ||||
|   character*80 line | ||||
|   character*512 datadir | ||||
|   character*500 infile | ||||
|   character*12 mycall,hiscall | ||||
|   character*6 mygrid | ||||
|   character(len=500) optarg | ||||
| 
 | ||||
|   logical :: display_help=.false. | ||||
|   logical*1 bShMsgs | ||||
|   logical*1 btrain | ||||
|   logical*1 bswl | ||||
| 
 | ||||
|   type(wav_header) :: wav | ||||
| 
 | ||||
|   integer*2 id2(30*12000) | ||||
|   integer*2 ichunk(7*1024) | ||||
| 
 | ||||
|   real*8 pcoeffs(5) | ||||
| 
 | ||||
|   type (option) :: long_options(9) = [ & | ||||
|        option ('ndepth',.true.,'c','ndepth',''), &   | ||||
|        option ('dxcall',.true.,'d','hiscall',''), &   | ||||
|        option ('evemode',.true.,'e','Must be used with -s.',''), & | ||||
|        option ('frequency',.true.,'f','rxfreq',''), & | ||||
|        option ('help',.false.,'h','Display this help message',''), & | ||||
|        option ('mycall',.true.,'m','mycall',''), & | ||||
|        option ('nftol',.true.,'n','nftol',''), & | ||||
|        option ('rxequalize',.false.,'r','Rx Equalize',''), & | ||||
|        option ('short',.false.,'s','enable Sh','') & | ||||
|        ] | ||||
|   t0=0.0 | ||||
|   ndepth=3 | ||||
|   ntol=100 | ||||
|   nrxfreq=1500 | ||||
|   mycall='' | ||||
|   mygrid='EN50WC' | ||||
|   hiscall='' | ||||
|   bShMsgs=.false. | ||||
|   btrain=.false. | ||||
|   bswl=.false. | ||||
|   datadir='.' | ||||
|   pcoeffs=0.d0 | ||||
|   | ||||
|   do | ||||
|      call getopt('c:d:ef:hm:n:rs',long_options,c,optarg,narglen,nstat,noffset,nremain,.true.) | ||||
|      if( nstat .ne. 0 ) then | ||||
|         exit | ||||
|      end if | ||||
|      select case (c) | ||||
|      case ('c') | ||||
|         read (optarg(:narglen), *) ndepth  | ||||
|      case ('d') | ||||
|         read (optarg(:narglen), *) hiscall | ||||
|      case ('e') | ||||
|         bswl=.true.  | ||||
|      case ('f') | ||||
|         read (optarg(:narglen), *) nrxfreq | ||||
|      case ('h') | ||||
|         display_help = .true. | ||||
|      case ('m') | ||||
|         read (optarg(:narglen), *) mycall | ||||
|      case ('n') | ||||
|         read (optarg(:narglen), *) ntol | ||||
|      case ('r') | ||||
|         btrain=.true.  | ||||
|      case ('s') | ||||
|         bShMsgs=.true.  | ||||
|      end select | ||||
|   end do | ||||
| 
 | ||||
|   if(display_help .or. nstat.lt.0 .or. nremain.lt.1) then | ||||
|      print *, '' | ||||
|      print *, 'Usage: msk144d [OPTIONS] file1 [file2 ...]' | ||||
|      print *, '' | ||||
|      print *, '       msk144 decode pre-recorded .WAV file(s)' | ||||
|      print *, '' | ||||
|      print *, 'OPTIONS:' | ||||
|      do i = 1, size (long_options) | ||||
|         call long_options(i) % print (6) | ||||
|      end do | ||||
|      go to 999 | ||||
|   endif | ||||
| 
 | ||||
|   call init_timer ('timer.out') | ||||
|   call timer('msk144  ',0) | ||||
|   ndecoded=0 | ||||
|   do ifile=noffset+1,noffset+nremain | ||||
|      call get_command_argument(ifile,optarg,narglen) | ||||
|      infile=optarg(:narglen) | ||||
|      call timer('read    ',0) | ||||
|      call wav%read (infile) | ||||
|      i1=index(infile,'.wav') | ||||
|      if( i1 .eq. 0 ) i1=index(infile,'.WAV') | ||||
|      read(infile(i1-6:i1-1),*,err=998) nutc | ||||
|      inquire(FILE=infile,SIZE=isize) | ||||
|      npts=min((isize-216)/2,360000) | ||||
|      read(unit=wav%lun) id2(1:npts) | ||||
|      close(unit=wav%lun) | ||||
|      call timer('read    ',1) | ||||
| 
 | ||||
|      do i=1,npts-7*1024+1,7*512 | ||||
|        ichunk=id2(i:i+7*1024-1) | ||||
|        tsec=(i-1)/12000.0 | ||||
|        tt=sum(float(abs(id2(i:i+7*512-1)))) | ||||
|        if( tt .ne. 0.0 ) then | ||||
|          call mskrtd(ichunk,nutc,tsec,ntol,nrxfreq,ndepth,mycall,mygrid,hiscall,bShMsgs, & | ||||
|                      btrain,pcoeffs,bswl,datadir,line) | ||||
|          if( index(line,"&") .ne. 0 .or.   & | ||||
|               index(line,"^") .ne. 0 .or.   & | ||||
|               index(line,"!") .ne. 0 .or.   & | ||||
|               index(line,"@") .ne. 0 ) then  | ||||
|            write(*,*) line | ||||
|          endif | ||||
|        endif | ||||
|      enddo  | ||||
|   enddo | ||||
| 
 | ||||
|   call timer('msk144  ',1) | ||||
|   call timer('msk144  ',101) | ||||
|   go to 999 | ||||
| 
 | ||||
| 998 print*,'Cannot read from file:' | ||||
|   print*,infile | ||||
| 
 | ||||
| 999 continue | ||||
| end program msk144d | ||||
							
								
								
									
										197
									
								
								lib/msk144sd.f90
									
									
									
									
									
								
							
							
						
						
									
										197
									
								
								lib/msk144sd.f90
									
									
									
									
									
								
							| @ -1,197 +0,0 @@ | ||||
| program msk144sd | ||||
| ! | ||||
| ! A simple decoder for slow msk144. | ||||
| ! Can be used as a (slow) brute-force multi-decoder by looping | ||||
| ! over a set of carrier frequencies. | ||||
| ! | ||||
|   use options | ||||
|   use timer_module, only: timer | ||||
|   use timer_impl, only: init_timer | ||||
|   use readwav | ||||
| 
 | ||||
|   parameter (NRECENT=10) | ||||
|   parameter (NSPM=864) | ||||
|   parameter (NPATTERNS=4) | ||||
| 
 | ||||
|   character ch | ||||
|   character*80 line | ||||
|   character*500 infile | ||||
|   character*12 mycall,hiscall | ||||
|   character*6 mygrid | ||||
|   character(len=500) optarg | ||||
|   character*22 msgreceived | ||||
|   character*12 recent_calls(NRECENT) | ||||
| 
 | ||||
|   complex cdat(30*375) | ||||
|   complex c(NSPM) | ||||
|   complex ct(NSPM) | ||||
| 
 | ||||
|   real softbits(144) | ||||
|   real xmc(NPATTERNS) | ||||
| 
 | ||||
|   logical :: display_help=.false. | ||||
| 
 | ||||
|   type(wav_header) :: wav | ||||
| 
 | ||||
|   integer iavmask(8) | ||||
|   integer iavpatterns(8,NPATTERNS) | ||||
|   integer npkloc(10) | ||||
| 
 | ||||
|   integer*2 id2(30*12000) | ||||
|   integer*2 ichunk(7*1024) | ||||
|    | ||||
|   data iavpatterns/ & | ||||
|        1,1,1,1,0,0,0,0, & | ||||
|        0,1,1,1,1,0,0,0, & | ||||
|        0,0,1,1,1,1,0,0, & | ||||
|        1,1,1,1,1,1,0,0/ | ||||
|   data xmc/2.0,4.5,2.5,3.0/ | ||||
| 
 | ||||
|   type (option) :: long_options(2) = [ & | ||||
|        option ('frequency',.true.,'f','rxfreq',''), & | ||||
|        option ('help',.false.,'h','Display this help message','') & | ||||
|        ] | ||||
|   t0=0.0 | ||||
|   ntol=100 | ||||
|   nrxfreq=1500 | ||||
|   | ||||
|   do | ||||
|      call getopt('f:h',long_options,ch,optarg,narglen,nstat,noffset,nremain,.true.) | ||||
|      if( nstat .ne. 0 ) then | ||||
|         exit | ||||
|      end if | ||||
|      select case (ch) | ||||
|      case ('f') | ||||
|         read (optarg(:narglen), *) nrxfreq | ||||
|      case ('h') | ||||
|         display_help = .true. | ||||
|      end select | ||||
|   end do | ||||
| 
 | ||||
|   if(display_help .or. nstat.lt.0 .or. nremain.lt.1) then | ||||
|      print *, '' | ||||
|      print *, 'Usage: msk144sd [OPTIONS] file1 [file2 ...]' | ||||
|      print *, '' | ||||
|      print *, '       decode pre-recorded .WAV file(s)' | ||||
|      print *, '' | ||||
|      print *, 'OPTIONS:' | ||||
|      do i = 1, size (long_options) | ||||
|         call long_options(i) % print (6) | ||||
|      end do | ||||
|      go to 999 | ||||
|   endif | ||||
| 
 | ||||
|   call init_timer ('timer.out') | ||||
|   call timer('msk144  ',0) | ||||
|   ndecoded=0 | ||||
|   do ifile=noffset+1,noffset+nremain | ||||
|      call get_command_argument(ifile,optarg,narglen) | ||||
|      infile=optarg(:narglen) | ||||
|      call timer('read    ',0) | ||||
|      call wav%read (infile) | ||||
|      i1=index(infile,'.wav') | ||||
|      if( i1 .eq. 0 ) i1=index(infile,'.WAV') | ||||
|      read(infile(i1-6:i1-1),*,err=998) nutc | ||||
|      inquire(FILE=infile,SIZE=isize) | ||||
|      npts=min((isize-216)/2,360000) | ||||
|      read(unit=wav%lun) id2(1:npts) | ||||
|      close(unit=wav%lun) | ||||
|      call timer('read    ',1) | ||||
| 
 | ||||
| !   do if=1,89  ! brute force multi-decoder | ||||
|      fo=nrxfreq | ||||
| !     fo=(if-1)*25.0+300.0 | ||||
|      call msksddc(id2,npts,fo,cdat) | ||||
|      np=npts/32 | ||||
|      ntol=200  ! actual ntol is ntol/32=6.25 Hz. Detection window is 12.5 Hz wide | ||||
|      fc=1500.0 | ||||
|      call msk144spd(cdat,np,ntol,ndecodesuccess,msgreceived,fc,fest,tdec,navg,ct, & | ||||
|                     softbits,recent_calls,nrecent) | ||||
|      nsnr=0  ! need an snr estimate | ||||
|      if( ndecodesuccess .eq. 1 ) then | ||||
|        fest=fo+fest-fc   ! fudging because spd thinks input signal is at 1500 Hz | ||||
|        goto 900  | ||||
|      endif | ||||
| ! If short ping decoder doesn't find a decode  | ||||
|      npat=NPATTERNS | ||||
|      do iavg=1,npat | ||||
|        iavmask=iavpatterns(1:8,iavg) | ||||
|        navg=sum(iavmask) | ||||
|        deltaf=4.0/real(navg)  ! search increment for frequency sync | ||||
|        npeaks=4 | ||||
|        ntol=200 | ||||
|        fc=1500.0 | ||||
|        call msk144sync(cdat(1:6*NSPM),6,ntol,deltaf,iavmask,npeaks,fc,           & | ||||
|           fest,npkloc,nsyncsuccess,xmax,c) | ||||
|        if( nsyncsuccess .eq. 0 ) cycle | ||||
| 
 | ||||
|        do ipk=1,npeaks | ||||
|          do is=1,3    | ||||
|            ic0=npkloc(ipk) | ||||
|            if(is.eq.2) ic0=max(1,ic0-1) | ||||
|            if(is.eq.3) ic0=min(NSPM,ic0+1) | ||||
|            ct=cshift(c,ic0-1) | ||||
|            call msk144decodeframe(ct,softbits,msgreceived,ndecodesuccess,      & | ||||
|                                   recent_calls,nrecent) | ||||
|            if(ndecodesuccess .gt. 0) then | ||||
|               tdec=tsec+xmc(iavg)*tframe | ||||
|               fest=fo+(fest-fc)/32.0    | ||||
|               goto 900 | ||||
|            endif | ||||
|          enddo                         !Slicer dither | ||||
|        enddo                            !Peak loop  | ||||
|      enddo | ||||
| 
 | ||||
| !   enddo | ||||
| 900 continue | ||||
|     if( ndecodesuccess .gt. 0 ) then | ||||
|        write(*,1020) nutc,nsnr,tdec,nint(fest),' % ',msgreceived,navg | ||||
| 1020   format(i6.6,i4,f5.1,i5,a3,a22,i4) | ||||
|     endif | ||||
|   enddo | ||||
| 
 | ||||
|   call timer('msk144  ',1) | ||||
|   call timer('msk144  ',101) | ||||
|   go to 999 | ||||
| 
 | ||||
| 998 print*,'Cannot read from file:' | ||||
|   print*,infile | ||||
| 
 | ||||
| 999 continue | ||||
| end program msk144sd | ||||
| 
 | ||||
| subroutine msksddc(id2,npts,fc,cdat) | ||||
| 
 | ||||
| ! The msk144 detector/demodulator/decoder will decode signals | ||||
| ! with carrier frequency, fc, in the range fN/4 +/- 0.03333*fN.  | ||||
| ! | ||||
| ! For slow MSK144 with nslow=32:  | ||||
| !  fs=12000/32=375 Hz, fN=187.5 Hz | ||||
| ! | ||||
| ! This routine accepts input samples with fs=12000 Hz. It | ||||
| ! downconverts and decimates by 32 to center a signal with input carrier | ||||
| ! frequency fc at new carrier frequency 1500/32=46.875 Hz. | ||||
| ! The analytic signal is returned. | ||||
|   | ||||
|   parameter (NFFT1=30*12000,NFFT2=30*375) | ||||
|   integer*2 id2(npts) | ||||
|   complex cx(0:NFFT1) | ||||
|   complex cdat(30*375) | ||||
| 
 | ||||
|   dt=1.0/12000.0 | ||||
|   df=1.0/(NFFT1*dt) | ||||
|   icenter=int(fc/df+0.5) | ||||
|   i46p875=int(46.875/df+0.5) | ||||
|   ishift=icenter-i46p875 | ||||
|   cx=cmplx(0.0,0.0) | ||||
|   cx(1:npts)=id2 | ||||
|   call four2a(cx,NFFT1,1,-1,1) | ||||
|   cx=cshift(cx,ishift) | ||||
|   cx(1)=0.5*cx(1) | ||||
|   cx(2*i46p875+1:)=cmplx(0.0,0.0) | ||||
|   call four2a(cx,NFFT2,1,1,1) | ||||
|   cdat(1:npts/32)=cx(0:npts/32-1)/NFFT1 | ||||
|   return | ||||
| 
 | ||||
| end subroutine msksddc | ||||
| 
 | ||||
| @ -13,10 +13,10 @@ program msk144sim | ||||
|   integer itone(144)                   !Message bits | ||||
| 
 | ||||
|   nargs=iargc() | ||||
|   if(nargs.ne.6) then | ||||
|      print*,'Usage:   msk144sim       message      freq width nslow snr nfiles' | ||||
|      print*,'Example: msk144sim "K1ABC W9XYZ EN37" 1500  0.12   1    2    1' | ||||
|      print*,'         msk144sim "K1ABC W9XYZ EN37" 1500  2.5   32   15    1' | ||||
|   if(nargs.ne.5) then | ||||
|      print*,'Usage:   msk144sim       message      freq width snr nfiles' | ||||
|      print*,'Example: msk144sim "K1ABC W9XYZ EN37" 1500  0.12   2    1' | ||||
|      print*,'         msk144sim "K1ABC W9XYZ EN37" 1500  2.5   15    1' | ||||
|      go to 999 | ||||
|   endif | ||||
|   call getarg(1,msg) | ||||
| @ -25,10 +25,8 @@ program msk144sim | ||||
|   call getarg(3,arg) | ||||
|   read(arg,*) width | ||||
|   call getarg(4,arg) | ||||
|   read(arg,*) nslow | ||||
|   call getarg(5,arg) | ||||
|   read(arg,*) snrdb | ||||
|   call getarg(6,arg) | ||||
|   call getarg(5,arg) | ||||
|   read(arg,*) nfiles | ||||
| 
 | ||||
| !sig is the peak amplitude of the ping.  | ||||
| @ -50,9 +48,9 @@ program msk144sim | ||||
| 
 | ||||
|   twopi=8.d0*atan(1.d0) | ||||
|   nsym=144 | ||||
|   nsps=6*nslow | ||||
|   nsps=6 | ||||
|   if( itone(41) .lt. 0 ) nsym=40 | ||||
|   baud=2000.d0/nslow | ||||
|   baud=2000.d0 | ||||
|   dphi0=twopi*(freq-0.25d0*baud)/12000.d0 | ||||
|   dphi1=twopi*(freq+0.25d0*baud)/12000.d0 | ||||
|   phi=0.0 | ||||
| @ -79,7 +77,7 @@ program msk144sim | ||||
|      go to 999 | ||||
|   endif | ||||
| 
 | ||||
|   if(nslow.eq.1) call makepings(pings,NMAX,width,sig) | ||||
|   call makepings(pings,NMAX,width,sig) | ||||
| 
 | ||||
| !  call sgran() | ||||
|   do ifile=1,nfiles                  !Loop over requested number of files | ||||
| @ -92,8 +90,7 @@ program msk144sim | ||||
|      fac=sqrt(6000.0/2500.0) | ||||
|      do i=0,NMAX-1 | ||||
|         xx=gran() | ||||
|         if(nslow.eq.1) wave(i)=pings(i)*waveform(i) + fac*xx | ||||
|         if(nslow.gt.1) wave(i)=sig*waveform(i) + fac*xx | ||||
|         wave(i)=pings(i)*waveform(i) + fac*xx | ||||
|         iwave(i)=30.0*wave(i) | ||||
|      enddo | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										24
									
								
								lib/platanh.f90
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								lib/platanh.f90
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| subroutine platanh(x,y) | ||||
|   isign=+1 | ||||
|   z=x | ||||
|   if( x.lt.0 ) then | ||||
|     isign=-1 | ||||
|     z=abs(x) | ||||
|   endif | ||||
|   if( z.le. 0.664 ) then | ||||
|     y=x/0.83 | ||||
|     return | ||||
|   elseif( z.le. 0.9217 ) then | ||||
|     y=isign*(z-0.4064)/0.322 | ||||
|     return | ||||
|   elseif( z.le. 0.9951 ) then | ||||
|     y=isign*(z-0.8378)/0.0524 | ||||
|     return | ||||
|   elseif( z.le. 0.9998 ) then | ||||
|     y=isign*(z-0.9914)/0.0012 | ||||
|     return | ||||
|   else | ||||
|     y=isign*7.0 | ||||
|     return | ||||
|   endif | ||||
| end subroutine platanh | ||||
							
								
								
									
										24
									
								
								lib/pltanh.f90
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								lib/pltanh.f90
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,24 @@ | ||||
| subroutine pltanh(x,y) | ||||
|   isign=+1 | ||||
|   z=x | ||||
|   if( x.lt.0 ) then | ||||
|     isign=-1 | ||||
|     z=abs(x) | ||||
|   endif | ||||
|   if( z.le. 0.8 ) then | ||||
|     y=0.83*x | ||||
|     return | ||||
|   elseif( z.le. 1.6 ) then | ||||
|     y=isign*(0.322*z+0.4064) | ||||
|     return   | ||||
|   elseif( z.le. 3.0 ) then | ||||
|     y=isign*(0.0524*z+0.8378) | ||||
|     return | ||||
|   elseif( z.lt. 7.0 ) then | ||||
|     y=isign*(0.0012*z+0.9914) | ||||
|     return | ||||
|   else | ||||
|     y=isign*0.9998 | ||||
|     return | ||||
|   endif | ||||
| end subroutine pltanh | ||||
| @ -57,8 +57,9 @@ subroutine sync65(nfa,nfb,naggressive,ntol,nqsym,ca,ncand,nrobust,   & | ||||
|      freq=i*df | ||||
|      itry=0 | ||||
| !     if(naggressive.gt.0 .and. ntol.lt.1000 .and. ccfmax.ge.thresh0) then | ||||
|      if(naggressive.gt.0 .and. ccfmax.ge.thresh0) then | ||||
|         if(i.ne.ipk) cycle | ||||
| !     if(naggressive.gt.0 .and. ccfmax.ge.thresh0) then | ||||
|      if(bVHF) then | ||||
|         if(i.ne.ipk .or. ccfmax.lt.thresh0) cycle | ||||
|         itry=1 | ||||
|         ncand=ncand+1 | ||||
|      else | ||||
|  | ||||
| @ -1,117 +0,0 @@ | ||||
|  subroutine unpackmsg144(dat,msg,c1,c2) | ||||
| ! special unpackmsg for MSK144 - returns call1 and call2 to enable | ||||
| ! maintenance of a recent-calls-heard list | ||||
| 
 | ||||
|    use packjt | ||||
|    parameter (NBASE=37*36*10*27*27*27) | ||||
|    parameter (NGBASE=180*180) | ||||
|    integer dat(12) | ||||
|    character c1*12,c2*12,grid*4,msg*22,grid6*6,psfx*4,junk2*4 | ||||
|    logical cqnnn | ||||
| 
 | ||||
|    cqnnn=.false. | ||||
|    nc1=ishft(dat(1),22) + ishft(dat(2),16) + ishft(dat(3),10)+         & | ||||
|         ishft(dat(4),4) + iand(ishft(dat(5),-2),15) | ||||
| 
 | ||||
|    nc2=ishft(iand(dat(5),3),26) + ishft(dat(6),20) +                   & | ||||
|         ishft(dat(7),14) + ishft(dat(8),8) + ishft(dat(9),2) +         & | ||||
|         iand(ishft(dat(10),-4),3) | ||||
| 
 | ||||
|    ng=ishft(iand(dat(10),15),12) + ishft(dat(11),6) + dat(12) | ||||
| 
 | ||||
|    if(ng.ge.32768) then | ||||
|       call unpacktext(nc1,nc2,ng,msg) | ||||
|       c1(1:12)=' ' | ||||
|       c2(1:12)=' ' | ||||
|       go to 100 | ||||
|    endif | ||||
| 
 | ||||
|    call unpackcall(nc1,c1,iv2,psfx) | ||||
|    if(iv2.eq.0) then | ||||
|  ! This is an "original JT65" message | ||||
|       if(nc1.eq.NBASE+1) c1='CQ    ' | ||||
|       if(nc1.eq.NBASE+2) c1='QRZ   ' | ||||
|       nfreq=nc1-NBASE-3 | ||||
|       if(nfreq.ge.0 .and. nfreq.le.999) then | ||||
|          write(c1,1002) nfreq | ||||
|  1002    format('CQ ',i3.3) | ||||
|          cqnnn=.true. | ||||
|       endif | ||||
|    endif | ||||
| 
 | ||||
|    call unpackcall(nc2,c2,junk1,junk2) | ||||
|    call unpackgrid(ng,grid) | ||||
| 
 | ||||
|    if(iv2.gt.0) then | ||||
|  ! This is a JT65v2 message | ||||
|       do i=1,4 | ||||
|          if(ichar(psfx(i:i)).eq.0) psfx(i:i)=' ' | ||||
|       enddo | ||||
| 
 | ||||
|       n1=len_trim(psfx) | ||||
|       n2=len_trim(c2) | ||||
|       if(iv2.eq.1) msg='CQ '//psfx(:n1)//'/'//c2(:n2)//' '//grid | ||||
|       if(iv2.eq.2) msg='QRZ '//psfx(:n1)//'/'//c2(:n2)//' '//grid | ||||
|       if(iv2.eq.3) msg='DE '//psfx(:n1)//'/'//c2(:n2)//' '//grid | ||||
|       if(iv2.eq.4) msg='CQ '//c2(:n2)//'/'//psfx(:n1)//' '//grid | ||||
|       if(iv2.eq.5) msg='QRZ '//c2(:n2)//'/'//psfx(:n1)//' '//grid | ||||
|       if(iv2.eq.6) msg='DE '//c2(:n2)//'/'//psfx(:n1)//' '//grid | ||||
|       if(iv2.eq.7) msg='DE '//c2(:n2)//' '//grid | ||||
|       if(iv2.eq.8) msg=' ' | ||||
|       go to 100 | ||||
|    else | ||||
| 
 | ||||
|    endif | ||||
| 
 | ||||
|    grid6=grid//'ma' | ||||
|    call grid2k(grid6,k) | ||||
|    if(k.ge.1 .and. k.le.450)   call getpfx2(k,c1) | ||||
|    if(k.ge.451 .and. k.le.900) call getpfx2(k,c2) | ||||
| 
 | ||||
|    i=index(c1,char(0)) | ||||
|    if(i.ge.3) c1=c1(1:i-1)//'            ' | ||||
|    i=index(c2,char(0)) | ||||
|    if(i.ge.3) c2=c2(1:i-1)//'            ' | ||||
| 
 | ||||
|    msg='                      ' | ||||
|    j=0 | ||||
|    if(cqnnn) then | ||||
|       msg=c1//'          ' | ||||
|       j=7                                  !### ??? ### | ||||
|       go to 10 | ||||
|    endif | ||||
| 
 | ||||
|    do i=1,12 | ||||
|       j=j+1 | ||||
|       msg(j:j)=c1(i:i) | ||||
|       if(c1(i:i).eq.' ') go to 10 | ||||
|    enddo | ||||
|    j=j+1 | ||||
|    msg(j:j)=' ' | ||||
| 
 | ||||
|  10 do i=1,12 | ||||
|       if(j.le.21) j=j+1 | ||||
|       msg(j:j)=c2(i:i) | ||||
|       if(c2(i:i).eq.' ') go to 20 | ||||
|    enddo | ||||
|    if(j.le.21) j=j+1 | ||||
|    msg(j:j)=' ' | ||||
| 
 | ||||
|  20 if(k.eq.0) then | ||||
|       do i=1,4 | ||||
|          if(j.le.21) j=j+1 | ||||
|          msg(j:j)=grid(i:i) | ||||
|       enddo | ||||
|       if(j.le.21) j=j+1 | ||||
|       msg(j:j)=' ' | ||||
|    endif | ||||
| 
 | ||||
|  100 continue | ||||
|    if(msg(1:6).eq.'CQ9DX ') msg(3:3)=' ' | ||||
|    if(msg(1:2).eq.'E9' .and.                                          & | ||||
|         msg(3:3).ge.'A' .and. msg(3:3).le.'Z' .and.                   & | ||||
|         msg(4:4).ge.'A' .and. msg(4:4).le.'Z' .and.                   & | ||||
|         msg(5:5).eq.' ') msg='CQ '//msg(3:) | ||||
| 
 | ||||
|    return | ||||
|  end subroutine unpackmsg144 | ||||
| @ -1,18 +1,34 @@ | ||||
| #include "WorkedBefore.hpp" | ||||
| 
 | ||||
| #include <functional> | ||||
| #include <boost/functional/hash.hpp> | ||||
| #include <boost/multi_index_container.hpp> | ||||
| #include <boost/multi_index/hashed_index.hpp> | ||||
| #include <boost/multi_index/ordered_index.hpp> | ||||
| #include <boost/multi_index/key_extractors.hpp> | ||||
| #include <QChar> | ||||
| #include <QString> | ||||
| #include <QByteArray> | ||||
| #include <QStandardPaths> | ||||
| #include <QDir> | ||||
| #include <QFile> | ||||
| #include <QTextStream> | ||||
| #include <QDebug> | ||||
| #include "qt_helpers.hpp" | ||||
| #include "pimpl_impl.hpp" | ||||
| 
 | ||||
| using namespace boost::multi_index; | ||||
| 
 | ||||
| // hash function for QString members in hashed indexes
 | ||||
| inline | ||||
| std::size_t hash_value (QString const& s) | ||||
| { | ||||
|   return std::hash<QString> {} (s); | ||||
| } | ||||
| 
 | ||||
| //
 | ||||
| // worked before set element
 | ||||
| //
 | ||||
| struct worked_entry | ||||
| { | ||||
|   explicit worked_entry (QString const& call, QString const& grid, QString const& band | ||||
| @ -39,7 +55,52 @@ struct worked_entry | ||||
|   int ITU_zone_; | ||||
| }; | ||||
| 
 | ||||
| // less then predidate for the Continent enum class
 | ||||
| bool operator == (worked_entry const& lhs, worked_entry const& rhs) | ||||
| { | ||||
|   return | ||||
|     lhs.continent_ == rhs.continent_  // check 1st as it is fast
 | ||||
|     && lhs.CQ_zone_ == rhs.CQ_zone_   // ditto
 | ||||
|     && lhs.ITU_zone_ == rhs.ITU_zone_ // ditto
 | ||||
|     && lhs.call_ == rhs.call_         // check the rest in decreasing
 | ||||
|     && lhs.grid_ == rhs.grid_         // domain size order to shortcut
 | ||||
|     && lhs.country_ == rhs.country_   // differences as quickly as possible
 | ||||
|     && lhs.band_ == rhs.band_ | ||||
|     && lhs.mode_ == rhs.mode_; | ||||
| } | ||||
| 
 | ||||
| std::size_t hash_value (worked_entry const& we) | ||||
| { | ||||
|   std::size_t seed {0}; | ||||
|   boost::hash_combine (seed, we.call_); | ||||
|   boost::hash_combine (seed, we.grid_); | ||||
|   boost::hash_combine (seed, we.band_); | ||||
|   boost::hash_combine (seed, we.mode_); | ||||
|   boost::hash_combine (seed, we.country_); | ||||
|   boost::hash_combine (seed, we.continent_); | ||||
|   boost::hash_combine (seed, we.CQ_zone_); | ||||
|   boost::hash_combine (seed, we.ITU_zone_); | ||||
|   return seed; | ||||
| } | ||||
| 
 | ||||
| #if !defined (QT_NO_DEBUG_STREAM) | ||||
| QDebug operator << (QDebug dbg, worked_entry const& e) | ||||
| { | ||||
|   QDebugStateSaver saver {dbg}; | ||||
|   dbg.nospace () << "worked_entry(" | ||||
|                  << e.call_ << ", " | ||||
|                  << e.grid_ << ", " | ||||
|                  << e.band_ << ", " | ||||
|                  << e.mode_ << ", " | ||||
|                  << e.country_ << ", " | ||||
|                  << e.continent_ << ", " | ||||
|                  << e.CQ_zone_ << ", " | ||||
|                  << e.ITU_zone_ << ')'; | ||||
|   return dbg; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| // less then predidate for the Continent enum class, needed for
 | ||||
| // ordered indexes
 | ||||
| struct Continent_less | ||||
| { | ||||
|   bool operator () (AD1CCty::Continent lhs, AD1CCty::Continent rhs) const | ||||
| @ -48,7 +109,7 @@ struct Continent_less | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| // tags
 | ||||
| // index tags
 | ||||
| struct call_mode_band {}; | ||||
| struct call_band {}; | ||||
| struct grid_mode_band {}; | ||||
| @ -62,85 +123,92 @@ struct CQ_zone_band {}; | ||||
| struct ITU_zone_mode_band {}; | ||||
| struct ITU_zone_band {}; | ||||
| 
 | ||||
| // set with multiple ordered unique indexes that allow for efficient
 | ||||
| // determination of various categories of worked before status
 | ||||
| // set with multiple ordered unique indexes that allow for optimally
 | ||||
| // efficient determination of various categories of worked before
 | ||||
| // status
 | ||||
| typedef multi_index_container< | ||||
|   worked_entry, | ||||
|   indexed_by< | ||||
|     // basic unordered set constraint - we don't need duplicate worked entries
 | ||||
|     hashed_unique<identity<worked_entry>>, | ||||
| 
 | ||||
|     //
 | ||||
|     // The following indexes are used to discover worked before stuff.
 | ||||
|     //
 | ||||
|     // They are ordered so as to support partial lookups and
 | ||||
|     // non-unique because container inserts must be valid for all
 | ||||
|     // indexes.
 | ||||
|     //
 | ||||
| 
 | ||||
|     // call+mode+band
 | ||||
|     ordered_unique<tag<call_mode_band>, | ||||
|                    composite_key<worked_entry, | ||||
|                                  member<worked_entry, QString, &worked_entry::call_>, | ||||
|                                  member<worked_entry, QString, &worked_entry::mode_>, | ||||
|                                  member<worked_entry, QString, &worked_entry::band_> > >, | ||||
|     ordered_non_unique<tag<call_mode_band>, | ||||
|                        composite_key<worked_entry, | ||||
|                                      member<worked_entry, QString, &worked_entry::call_>, | ||||
|                                      member<worked_entry, QString, &worked_entry::mode_>, | ||||
|                                      member<worked_entry, QString, &worked_entry::band_> > >, | ||||
|     // call+band
 | ||||
|     ordered_unique<tag<call_band>, | ||||
|                    composite_key<worked_entry, | ||||
|                                  member<worked_entry, QString, &worked_entry::call_>, | ||||
|                                  member<worked_entry, QString, &worked_entry::band_> > >, | ||||
|     ordered_non_unique<tag<call_band>, | ||||
|                        composite_key<worked_entry, | ||||
|                                      member<worked_entry, QString, &worked_entry::call_>, | ||||
|                                      member<worked_entry, QString, &worked_entry::band_> > >, | ||||
|     // grid+mode+band
 | ||||
|     ordered_unique<tag<grid_mode_band>, | ||||
|                    composite_key<worked_entry, | ||||
|                                  member<worked_entry, QString, &worked_entry::grid_>, | ||||
|                                  member<worked_entry, QString, &worked_entry::mode_>, | ||||
|                                  member<worked_entry, QString, &worked_entry::band_> > >, | ||||
|     ordered_non_unique<tag<grid_mode_band>, | ||||
|                        composite_key<worked_entry, | ||||
|                                      member<worked_entry, QString, &worked_entry::grid_>, | ||||
|                                      member<worked_entry, QString, &worked_entry::mode_>, | ||||
|                                      member<worked_entry, QString, &worked_entry::band_> > >, | ||||
|     // grid+band
 | ||||
|     ordered_unique<tag<grid_band>, | ||||
|                    composite_key<worked_entry, | ||||
|                                  member<worked_entry, QString, &worked_entry::grid_>, | ||||
|                                  member<worked_entry, QString, &worked_entry::band_> > >, | ||||
|     ordered_non_unique<tag<grid_band>, | ||||
|                        composite_key<worked_entry, | ||||
|                                      member<worked_entry, QString, &worked_entry::grid_>, | ||||
|                                      member<worked_entry, QString, &worked_entry::band_> > >, | ||||
|     // country+mode+band
 | ||||
|     ordered_unique<tag<entity_mode_band>, | ||||
|                    composite_key<worked_entry, | ||||
|                                  member<worked_entry, QString, &worked_entry::country_>, | ||||
|                                  member<worked_entry, QString, &worked_entry::mode_>, | ||||
|                                  member<worked_entry, QString, &worked_entry::band_> > >, | ||||
|     ordered_non_unique<tag<entity_mode_band>, | ||||
|                        composite_key<worked_entry, | ||||
|                                      member<worked_entry, QString, &worked_entry::country_>, | ||||
|                                      member<worked_entry, QString, &worked_entry::mode_>, | ||||
|                                      member<worked_entry, QString, &worked_entry::band_> > >, | ||||
|     // country+band
 | ||||
|     ordered_unique<tag<entity_band>, | ||||
|                    composite_key<worked_entry, | ||||
|                                  member<worked_entry, QString, &worked_entry::country_>, | ||||
|                                  member<worked_entry, QString, &worked_entry::band_> > >, | ||||
|     ordered_non_unique<tag<entity_band>, | ||||
|                        composite_key<worked_entry, | ||||
|                                      member<worked_entry, QString, &worked_entry::country_>, | ||||
|                                      member<worked_entry, QString, &worked_entry::band_> > >, | ||||
|     // continent+mode+band
 | ||||
|     ordered_unique<tag<continent_mode_band>, | ||||
|                    composite_key<worked_entry, | ||||
|                                  member<worked_entry, AD1CCty::Continent, &worked_entry::continent_>, | ||||
|                                  member<worked_entry, QString, &worked_entry::mode_>, | ||||
|                                  member<worked_entry, QString, &worked_entry::band_> >, | ||||
|                    composite_key_compare< | ||||
|                                    Continent_less, | ||||
|                                    std::less<QString>, | ||||
|                                    std::less<QString> > >, | ||||
|     ordered_non_unique<tag<continent_mode_band>, | ||||
|                        composite_key<worked_entry, | ||||
|                                      member<worked_entry, AD1CCty::Continent, &worked_entry::continent_>, | ||||
|                                      member<worked_entry, QString, &worked_entry::mode_>, | ||||
|                                      member<worked_entry, QString, &worked_entry::band_> >, | ||||
|                        composite_key_compare<Continent_less, std::less<QString>, std::less<QString> > >, | ||||
|     // continent+band
 | ||||
|     ordered_unique<tag<continent_band>, | ||||
|                    composite_key<worked_entry, | ||||
|                                  member<worked_entry, AD1CCty::Continent, &worked_entry::continent_>, | ||||
|                                  member<worked_entry, QString, &worked_entry::band_> >, | ||||
|                    composite_key_compare< | ||||
|                                    Continent_less, | ||||
|                                    std::less<QString> > >, | ||||
|     ordered_non_unique<tag<continent_band>, | ||||
|                        composite_key<worked_entry, | ||||
|                                      member<worked_entry, AD1CCty::Continent, &worked_entry::continent_>, | ||||
|                                      member<worked_entry, QString, &worked_entry::band_> >, | ||||
|                        composite_key_compare<Continent_less, std::less<QString> > >, | ||||
|     // CQ-zone+mode+band
 | ||||
|     ordered_unique<tag<CQ_zone_mode_band>, | ||||
|                    composite_key<worked_entry, | ||||
|                                  member<worked_entry, int, &worked_entry::CQ_zone_>, | ||||
|                                  member<worked_entry, QString, &worked_entry::mode_>, | ||||
|                                  member<worked_entry, QString, &worked_entry::band_> > >, | ||||
|     ordered_non_unique<tag<CQ_zone_mode_band>, | ||||
|                        composite_key<worked_entry, | ||||
|                                      member<worked_entry, int, &worked_entry::CQ_zone_>, | ||||
|                                      member<worked_entry, QString, &worked_entry::mode_>, | ||||
|                                      member<worked_entry, QString, &worked_entry::band_> > >, | ||||
|     // CQ-zone+band
 | ||||
|     ordered_unique<tag<CQ_zone_band>, | ||||
|                    composite_key<worked_entry, | ||||
|                                  member<worked_entry, int, &worked_entry::CQ_zone_>, | ||||
|                                  member<worked_entry, QString, &worked_entry::band_> > >, | ||||
|     ordered_non_unique<tag<CQ_zone_band>, | ||||
|                        composite_key<worked_entry, | ||||
|                                      member<worked_entry, int, &worked_entry::CQ_zone_>, | ||||
|                                      member<worked_entry, QString, &worked_entry::band_> > >, | ||||
|     // ITU-zone+mode+band
 | ||||
|     ordered_unique<tag<ITU_zone_mode_band>, | ||||
|                    composite_key<worked_entry, | ||||
|                                  member<worked_entry, int, &worked_entry::ITU_zone_>, | ||||
|                                  member<worked_entry, QString, &worked_entry::mode_>, | ||||
|                                  member<worked_entry, QString, &worked_entry::band_> > >, | ||||
|     ordered_non_unique<tag<ITU_zone_mode_band>, | ||||
|                        composite_key<worked_entry, | ||||
|                                      member<worked_entry, int, &worked_entry::ITU_zone_>, | ||||
|                                      member<worked_entry, QString, &worked_entry::mode_>, | ||||
|                                      member<worked_entry, QString, &worked_entry::band_> > >, | ||||
|     // ITU-zone+band
 | ||||
|     ordered_unique<tag<ITU_zone_band>, | ||||
|                    composite_key<worked_entry, | ||||
|                                  member<worked_entry, int, &worked_entry::ITU_zone_>, | ||||
|                                  member<worked_entry, QString, &worked_entry::band_> > > > | ||||
|   > worked_type; | ||||
|     ordered_non_unique<tag<ITU_zone_band>, | ||||
|                        composite_key<worked_entry, | ||||
|                                      member<worked_entry, int, &worked_entry::ITU_zone_>, | ||||
|                                      member<worked_entry, QString, &worked_entry::band_> > > > | ||||
|   > worked_before_database_type; | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
| @ -188,7 +256,7 @@ public: | ||||
| 
 | ||||
|   QString path_; | ||||
|   AD1CCty prefixes_; | ||||
|   worked_type worked_; | ||||
|   worked_before_database_type worked_; | ||||
| }; | ||||
| 
 | ||||
| WorkedBefore::WorkedBefore () | ||||
| @ -196,7 +264,7 @@ WorkedBefore::WorkedBefore () | ||||
|   QFile inputFile {m_->path_}; | ||||
|   if (inputFile.open (QFile::ReadOnly)) | ||||
|     { | ||||
|       QTextStream in(&inputFile); | ||||
|       QTextStream in {&inputFile}; | ||||
|       QString buffer; | ||||
|       bool pre_read {false}; | ||||
|       int end_position {-1}; | ||||
|  | ||||
							
								
								
									
										36
									
								
								main.cpp
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								main.cpp
									
									
									
									
									
								
							| @ -52,6 +52,38 @@ namespace | ||||
|       qsrand (seed);            // this is good for rand() as well
 | ||||
|     } | ||||
|   } seeding; | ||||
| 
 | ||||
|   // We  can't use  the GUI  after QApplication::exit()  is called  so
 | ||||
|   // uncaught exceptions can  get lost on Windows  systems where there
 | ||||
|   // is    no    console    terminal,     so    here    we    override
 | ||||
|   // QApplication::notify() and  wrap the base  class call with  a try
 | ||||
|   // block to catch and display exceptions in a message box.
 | ||||
|   class ExceptionCatchingApplication final | ||||
|     : public QApplication | ||||
|   { | ||||
|   public: | ||||
|     explicit ExceptionCatchingApplication (int& argc, char * * argv) | ||||
|       : QApplication {argc, argv} | ||||
|     { | ||||
|     } | ||||
|     bool notify (QObject * receiver, QEvent * e) override | ||||
|     { | ||||
|       try | ||||
|         { | ||||
|           return QApplication::notify (receiver, e); | ||||
|         } | ||||
|       catch (std::exception const& e) | ||||
|         { | ||||
|           MessageBox::critical_message (nullptr, translate ("main", "Fatal error"), e.what ()); | ||||
|           throw; | ||||
|         } | ||||
|       catch (...) | ||||
|         { | ||||
|           MessageBox::critical_message (nullptr, translate ("main", "Unexpected fatal error")); | ||||
|           throw; | ||||
|         } | ||||
|     } | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) | ||||
| @ -68,7 +100,7 @@ int main(int argc, char *argv[]) | ||||
|   // Multiple instances communicate with jt9 via this
 | ||||
|   QSharedMemory mem_jt9; | ||||
| 
 | ||||
|   QApplication a(argc, argv); | ||||
|   ExceptionCatchingApplication a(argc, argv); | ||||
|   try | ||||
|     { | ||||
|       setlocale (LC_NUMERIC, "C"); // ensure number forms are in
 | ||||
| @ -339,12 +371,10 @@ int main(int argc, char *argv[]) | ||||
|     } | ||||
|   catch (std::exception const& e) | ||||
|     { | ||||
|       MessageBox::critical_message (nullptr, a.translate ("main", "Fatal error"), e.what ()); | ||||
|       std::cerr << "Error: " << e.what () << '\n'; | ||||
|     } | ||||
|   catch (...) | ||||
|     { | ||||
|       MessageBox::critical_message (nullptr, a.translate ("main", "Unexpected fatal error")); | ||||
|       std::cerr << "Unexpected fatal error\n"; | ||||
|       throw;			// hoping the runtime might tell us more about the exception
 | ||||
|     } | ||||
|  | ||||
| @ -52,7 +52,7 @@ CabrilloLog::impl::impl (Configuration const * configuration) | ||||
|   SQL_error_check (export_query_, &QSqlQuery::prepare, | ||||
|                    "SELECT frequency, \"when\", exchange_sent, call, exchange_rcvd FROM cabrillo_log ORDER BY \"when\""); | ||||
|    | ||||
|   setEditStrategy (QSqlTableModel::OnManualSubmit); | ||||
|   setEditStrategy (QSqlTableModel::OnRowChange); | ||||
|   setTable ("cabrillo_log"); | ||||
|   setHeaderData (fieldIndex ("frequency"), Qt::Horizontal, tr ("Freq(kHz)")); | ||||
|   setHeaderData (fieldIndex ("when"), Qt::Horizontal, tr ("Date & Time(UTC)")); | ||||
| @ -73,24 +73,49 @@ CabrilloLog::~CabrilloLog () | ||||
| { | ||||
| } | ||||
| 
 | ||||
| QAbstractItemModel * CabrilloLog::model () | ||||
| QSqlTableModel * CabrilloLog::model () | ||||
| { | ||||
|   return &*m_; | ||||
| } | ||||
| 
 | ||||
| void CabrilloLog::add_QSO (Frequency frequency, QDateTime const& when, QString const& call | ||||
| namespace | ||||
| { | ||||
|   void set_value_maybe_null (QSqlRecord& record, QString const& name, QString const& value) | ||||
|   { | ||||
|     if (value.size ()) | ||||
|       { | ||||
|         record.setValue (name, value); | ||||
|       } | ||||
|     else | ||||
|       { | ||||
|         record.setNull (name); | ||||
|       } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| bool CabrilloLog::add_QSO (Frequency frequency, QDateTime const& when, QString const& call | ||||
|                            , QString const& exchange_sent, QString const& exchange_received) | ||||
| { | ||||
|   ConditionalTransaction transaction {*m_}; | ||||
|   auto record = m_->record (); | ||||
|   record.setValue ("frequency", frequency / 1000ull); // kHz
 | ||||
|   record.setValue ("when", when.toMSecsSinceEpoch () / 1000ull); | ||||
|   record.setValue ("call", call); | ||||
|   record.setValue ("exchange_sent", exchange_sent); | ||||
|   record.setValue ("exchange_rcvd", exchange_received); | ||||
|   record.setValue ("band", m_->configuration_->bands ()->find (frequency)); | ||||
|   SQL_error_check (*m_, &QSqlTableModel::insertRecord, -1, record); | ||||
|   transaction.submit (); | ||||
|   if (!when.isNull ()) | ||||
|     { | ||||
|       record.setValue ("when", when.toMSecsSinceEpoch () / 1000ull); | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       record.setNull ("when"); | ||||
|     } | ||||
|   set_value_maybe_null (record, "call", call); | ||||
|   set_value_maybe_null (record, "exchange_sent", exchange_sent); | ||||
|   set_value_maybe_null (record, "exchange_rcvd", exchange_received); | ||||
|   set_value_maybe_null (record, "band", m_->configuration_->bands ()->find (frequency)); | ||||
|   auto ok = m_->insertRecord (-1, record); | ||||
|   if (ok) | ||||
|     { | ||||
|       m_->select ();            // to refresh views
 | ||||
|     } | ||||
|   return ok; | ||||
| } | ||||
| 
 | ||||
| bool CabrilloLog::dupe (Frequency frequency, QString const& call) const | ||||
| @ -106,9 +131,12 @@ void CabrilloLog::reset () | ||||
| { | ||||
|   if (m_->rowCount ()) | ||||
|     { | ||||
|       m_->setEditStrategy (QSqlTableModel::OnManualSubmit); | ||||
|       ConditionalTransaction transaction {*m_}; | ||||
|       SQL_error_check (*m_, &QSqlTableModel::removeRows, 0, m_->rowCount (), QModelIndex {}); | ||||
|       transaction.submit (); | ||||
|       m_->select ();            // to refresh views
 | ||||
|       m_->setEditStrategy (QSqlTableModel::OnRowChange); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @ -128,7 +156,7 @@ void CabrilloLog::export_qsos (QTextStream& stream) const | ||||
|       frequency = frequency > 50000000ull ? frequency / 1000ull : frequency; | ||||
|       stream << QString {"QSO: %1 DG %2 %3 %4 %5 %6\n"} | ||||
|                       .arg (frequency, 5) | ||||
|                       .arg (QDateTime::fromMSecsSinceEpoch (m_->export_query_.value (when_index).toULongLong () * 1000ull).toString ("yyyy-MM-dd hhmm")) | ||||
|                          .arg (QDateTime::fromMSecsSinceEpoch (m_->export_query_.value (when_index).toULongLong () * 1000ull, Qt::UTC).toString ("yyyy-MM-dd hhmm")) | ||||
|                       .arg (my_call, -12) | ||||
|                       .arg (m_->export_query_.value (sent_index).toString (), -13) | ||||
|                       .arg (m_->export_query_.value (call_index).toString (), -12) | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
| class Configuration; | ||||
| class QDateTime; | ||||
| class QString; | ||||
| class QAbstractItemModel; | ||||
| class QSqlTableModel; | ||||
| class QTextStream; | ||||
| 
 | ||||
| class CabrilloLog final | ||||
| @ -21,11 +21,11 @@ public: | ||||
|   ~CabrilloLog (); | ||||
| 
 | ||||
|   // returns false if insert fails
 | ||||
|   void add_QSO (Frequency, QDateTime const&, QString const& call | ||||
|   bool add_QSO (Frequency, QDateTime const&, QString const& call | ||||
|                 , QString const& report_sent, QString const& report_received); | ||||
|   bool dupe (Frequency, QString const& call) const; | ||||
| 
 | ||||
|   QAbstractItemModel * model (); | ||||
|   QSqlTableModel * model (); | ||||
|   void reset (); | ||||
|   void export_qsos (QTextStream&) const; | ||||
| 
 | ||||
|  | ||||
| @ -43,7 +43,7 @@ FoxLog::impl::impl () | ||||
|   SQL_error_check (dupe_query_, &QSqlQuery::prepare, | ||||
|                    "SELECT COUNT(*) FROM fox_log WHERE call = :call AND band = :band"); | ||||
| 
 | ||||
|   setEditStrategy (QSqlTableModel::OnManualSubmit); | ||||
|   setEditStrategy (QSqlTableModel::OnRowChange); | ||||
|   setTable ("fox_log"); | ||||
|   setHeaderData (fieldIndex ("when"), Qt::Horizontal, tr ("Date & Time(UTC)")); | ||||
|   setHeaderData (fieldIndex ("call"), Qt::Horizontal, tr ("Call")); | ||||
| @ -62,7 +62,7 @@ FoxLog::~FoxLog () | ||||
| { | ||||
| } | ||||
| 
 | ||||
| QAbstractItemModel * FoxLog::model () | ||||
| QSqlTableModel * FoxLog::model () | ||||
| { | ||||
|   return &*m_; | ||||
| } | ||||
| @ -86,21 +86,26 @@ bool FoxLog::add_QSO (QDateTime const& when, QString const& call, QString const& | ||||
|                       , QString const& report_sent, QString const& report_received | ||||
|                       , QString const& band) | ||||
| { | ||||
|   ConditionalTransaction transaction {*m_}; | ||||
|   auto record = m_->record (); | ||||
|   record.setValue ("when", when.toMSecsSinceEpoch () / 1000); | ||||
|   record.setValue ("call", call); | ||||
|   if (!when.isNull ()) | ||||
|     { | ||||
|       record.setValue ("when", when.toMSecsSinceEpoch () / 1000); | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       record.setNull ("when"); | ||||
|     } | ||||
|   set_value_maybe_null (record, "call", call); | ||||
|   set_value_maybe_null (record, "grid", grid); | ||||
|   set_value_maybe_null (record, "report_sent", report_sent); | ||||
|   set_value_maybe_null (record, "report_rcvd", report_received); | ||||
|   record.setValue ("band", band); | ||||
|   SQL_error_check (*m_, &QSqlTableModel::insertRecord, -1, record); | ||||
|   if (!transaction.submit (false)) | ||||
|   set_value_maybe_null (record, "band", band); | ||||
|   auto ok = m_->insertRecord (-1, record); | ||||
|   if (ok) | ||||
|     { | ||||
|       transaction.revert (); | ||||
|       return false; | ||||
|       m_->select ();            // to refresh views
 | ||||
|     } | ||||
|   return true; | ||||
|   return ok; | ||||
| } | ||||
| 
 | ||||
| bool FoxLog::dupe (QString const& call, QString const& band) const | ||||
| @ -116,8 +121,11 @@ void FoxLog::reset () | ||||
| { | ||||
|   if (m_->rowCount ()) | ||||
|     { | ||||
|       m_->setEditStrategy (QSqlTableModel::OnManualSubmit); | ||||
|       ConditionalTransaction transaction {*m_}; | ||||
|       SQL_error_check (*m_, &QSqlTableModel::removeRows, 0, m_->rowCount (), QModelIndex {}); | ||||
|       transaction.submit (); | ||||
|       m_->select ();            // to refresh views
 | ||||
|       m_->setEditStrategy (QSqlTableModel::OnRowChange); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -6,7 +6,7 @@ | ||||
| 
 | ||||
| class QDateTime; | ||||
| class QString; | ||||
| class QAbstractItemModel; | ||||
| class QSqlTableModel; | ||||
| 
 | ||||
| class FoxLog final | ||||
|   : private boost::noncopyable | ||||
| @ -21,7 +21,7 @@ public: | ||||
|                 , QString const& band); | ||||
|   bool dupe (QString const& call, QString const& band) const; | ||||
| 
 | ||||
|   QAbstractItemModel * model (); | ||||
|   QSqlTableModel * model (); | ||||
|   void reset (); | ||||
| 
 | ||||
| private: | ||||
|  | ||||
| @ -3,6 +3,7 @@ | ||||
| #include <cstdlib> | ||||
| #include <utility> | ||||
| #include <limits> | ||||
| #include <algorithm> | ||||
| 
 | ||||
| #include <QMetaType> | ||||
| #include <QAbstractTableModel> | ||||
| @ -350,14 +351,6 @@ bool FrequencyList_v2::remove (Item f) | ||||
|   return m_->removeRow (row); | ||||
| } | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
|   bool row_is_higher (QModelIndex const& lhs, QModelIndex const& rhs) | ||||
|   { | ||||
|     return lhs.row () > rhs.row (); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| bool FrequencyList_v2::removeDisjointRows (QModelIndexList rows) | ||||
| { | ||||
|   bool result {true}; | ||||
| @ -371,7 +364,10 @@ bool FrequencyList_v2::removeDisjointRows (QModelIndexList rows) | ||||
|     } | ||||
| 
 | ||||
|   // reverse sort by row
 | ||||
|   qSort (rows.begin (), rows.end (), row_is_higher); | ||||
|   std::sort (rows.begin (), rows.end (), [] (QModelIndex const& lhs, QModelIndex const& rhs) | ||||
|              { | ||||
|                return rhs.row () < lhs.row (); // reverse row ordering
 | ||||
|              }); | ||||
|   Q_FOREACH (auto index, rows) | ||||
|     { | ||||
|       if (result && !m_->removeRow (index.row ())) | ||||
|  | ||||
| @ -139,14 +139,6 @@ bool StationList::remove (Station s) | ||||
|   return removeRow (row); | ||||
| } | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
|   bool row_is_higher (QModelIndex const& lhs, QModelIndex const& rhs) | ||||
|   { | ||||
|     return lhs.row () > rhs.row (); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| bool StationList::removeDisjointRows (QModelIndexList rows) | ||||
| { | ||||
|   bool result {true}; | ||||
| @ -160,7 +152,10 @@ bool StationList::removeDisjointRows (QModelIndexList rows) | ||||
|     } | ||||
| 
 | ||||
|   // reverse sort by row
 | ||||
|   qSort (rows.begin (), rows.end (), row_is_higher); | ||||
|   std::sort (rows.begin (), rows.end (), [] (QModelIndex const& lhs, QModelIndex const& rhs) | ||||
|              { | ||||
|                return rhs.row () < lhs.row (); // reverse row ordering
 | ||||
|              }); | ||||
|   Q_FOREACH (auto index, rows) | ||||
|     { | ||||
|       if (result && !m_->removeRow (index.row ())) | ||||
|  | ||||
| @ -25,37 +25,56 @@ class ConditionalTransaction final | ||||
| { | ||||
| public: | ||||
|   explicit ConditionalTransaction (QSqlTableModel& model) | ||||
|     : model_ {model} | ||||
|     : model_ (model) | ||||
|     , submitted_ {false} | ||||
|   { | ||||
|     model_.database ().transaction (); | ||||
|   } | ||||
| 
 | ||||
|   bool submit (bool throw_on_error = true) | ||||
|   { | ||||
|     Q_ASSERT (model_.isDirty ()); | ||||
|     bool ok {true}; | ||||
|     if (throw_on_error) | ||||
|       { | ||||
|         SQL_error_check (model_, &QSqlTableModel::submitAll); | ||||
|         SQL_error_check (model_ | ||||
|                          , QSqlTableModel::OnManualSubmit == model_.editStrategy () | ||||
|                          ? &QSqlTableModel::submitAll | ||||
|                          : &QSqlTableModel::submit); | ||||
|       } | ||||
|     else | ||||
|       { | ||||
|         ok = model_.submitAll (); | ||||
|         ok = QSqlTableModel::OnManualSubmit == model_.editStrategy () | ||||
|           ? model_.submitAll () : model_.submit (); | ||||
|       } | ||||
|     submitted_ = submitted_ || ok; | ||||
|     return ok; | ||||
|   } | ||||
| 
 | ||||
|   void revert () | ||||
|   { | ||||
|     Q_ASSERT (model_.isDirty ()); | ||||
|     model_.revertAll (); | ||||
|     if (QSqlTableModel::OnManualSubmit == model_.editStrategy ()) | ||||
|       { | ||||
|         model_.revertAll (); | ||||
|       } | ||||
|     else | ||||
|       { | ||||
|         model_.revert (); | ||||
|       } | ||||
|   } | ||||
| 
 | ||||
|   ~ConditionalTransaction () | ||||
|   { | ||||
|     if (model_.isDirty ()) | ||||
|       { | ||||
|         // abandon un-submitted changes to the model
 | ||||
|         model_.revertAll (); | ||||
|         if (QSqlTableModel::OnManualSubmit == model_.editStrategy ()) | ||||
|           { | ||||
|             model_.revertAll (); | ||||
|           } | ||||
|         else | ||||
|           { | ||||
|             model_.revert (); | ||||
|           } | ||||
|       } | ||||
|     auto database = model_.database (); | ||||
|     if (submitted_) | ||||
| @ -67,6 +86,7 @@ public: | ||||
|         database.rollback (); | ||||
|       } | ||||
|   } | ||||
| 
 | ||||
| private: | ||||
|   QSqlTableModel& model_; | ||||
|   bool submitted_; | ||||
|  | ||||
| @ -4,6 +4,7 @@ | ||||
| #include <stdexcept> | ||||
| 
 | ||||
| #include <QString> | ||||
| #include <QChar> | ||||
| #include <QMetaObject> | ||||
| #include <QHostAddress> | ||||
| #include <QDataStream> | ||||
| @ -77,6 +78,26 @@ public: | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| namespace std | ||||
| { | ||||
|   // std::hash<> specialization for QString based on the dbj2
 | ||||
|   // algorithm http://www.cse.yorku.ca/~oz/hash.html because qHash()
 | ||||
|   // is poor on 64-bit platforms due to being a 32-bit hash value
 | ||||
|   template<> | ||||
|   struct hash<QString> | ||||
|   { | ||||
|     std::size_t operator () (QString const& s) const noexcept | ||||
|     { | ||||
|       std::size_t hash {5381}; | ||||
|       for (int i = 0; i < s.size (); ++i) | ||||
|         { | ||||
|           hash = ((hash << 5) + hash) + ((s.at (i).row () << 8) | s.at (i).cell ()); | ||||
|         } | ||||
|       return hash; | ||||
|     } | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| // Register some useful Qt types with QMetaType
 | ||||
| Q_DECLARE_METATYPE (QHostAddress); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										133
									
								
								widgets/AbstractLogWindow.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								widgets/AbstractLogWindow.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,133 @@ | ||||
| #include "AbstractLogWindow.hpp" | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <QSettings> | ||||
| #include <QString> | ||||
| #include <QTableView> | ||||
| #include <QHeaderView> | ||||
| #include <QAction> | ||||
| #include <QSqlTableModel> | ||||
| #include <QItemSelectionModel> | ||||
| #include <QItemSelection> | ||||
| #include "Configuration.hpp" | ||||
| #include "SettingsGroup.hpp" | ||||
| #include "MessageBox.hpp" | ||||
| #include "models/FontOverrideModel.hpp" | ||||
| #include "pimpl_impl.hpp" | ||||
| 
 | ||||
| class AbstractLogWindow::impl final | ||||
| { | ||||
| public: | ||||
|   impl (AbstractLogWindow * self, QString const& settings_key, QSettings * settings | ||||
|         , Configuration const * configuration) | ||||
|     : self_ {self} | ||||
|     , settings_key_ {settings_key} | ||||
|     , settings_ {settings} | ||||
|     , configuration_ {configuration} | ||||
|     , log_view_ {nullptr} | ||||
|   { | ||||
|   } | ||||
| 
 | ||||
|   void delete_QSOs (); | ||||
| 
 | ||||
|   AbstractLogWindow * self_; | ||||
|   QString settings_key_; | ||||
|   QSettings * settings_; | ||||
|   Configuration const * configuration_; | ||||
|   QTableView * log_view_; | ||||
|   FontOverrideModel model_; | ||||
| }; | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
|   bool row_is_higher (QModelIndex const& lhs, QModelIndex const& rhs) | ||||
|   { | ||||
|     return lhs.row () > rhs.row (); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void AbstractLogWindow::impl::delete_QSOs () | ||||
| { | ||||
|   auto selection_model = log_view_->selectionModel (); | ||||
|   selection_model->select (selection_model->selection (), QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); | ||||
|   auto row_indexes = selection_model->selectedRows (); | ||||
| 
 | ||||
|   if (row_indexes.size () | ||||
|       && MessageBox::Yes == MessageBox::query_message (self_ | ||||
|                                                        , tr ("Confirm Delete") | ||||
|                                                        , tr ("Are you sure you want to delete the %n " | ||||
|                                                              "selected QSO(s) from the log", "" | ||||
|                                                              , row_indexes.size ()))) | ||||
|     { | ||||
|       // We must work with source model indexes because we don't want row
 | ||||
|       // removes to invalidate model indexes we haven't yet processed. We
 | ||||
|       // achieve that by processing them in decending row order.
 | ||||
|       for (auto& row_index : row_indexes) | ||||
|         { | ||||
|           row_index = model_.mapToSource (row_index); | ||||
|         } | ||||
| 
 | ||||
|       // reverse sort by row
 | ||||
|       std::sort (row_indexes.begin (), row_indexes.end (), row_is_higher); | ||||
|       for (auto index : row_indexes) | ||||
|         { | ||||
|           auto row = model_.mapFromSource (index).row (); | ||||
|           model_.removeRow (row); | ||||
|           self_->log_model_changed (); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| AbstractLogWindow::AbstractLogWindow (QString const& settings_key, QSettings * settings | ||||
|                                       , Configuration const * configuration | ||||
|                                       , QWidget * parent) | ||||
|   : QWidget {parent} | ||||
|   , m_ {this, settings_key, settings, configuration} | ||||
| { | ||||
|   // ensure view scrolls to latest new row
 | ||||
|   connect (&m_->model_, &QAbstractItemModel::rowsInserted, [this] (QModelIndex const& /*parent*/, int /*first*/, int /*last*/) { | ||||
|       if (m_->log_view_) m_->log_view_->scrollToBottom (); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| AbstractLogWindow::~AbstractLogWindow () | ||||
| { | ||||
|   SettingsGroup g {m_->settings_, m_->settings_key_}; | ||||
|   m_->settings_->setValue ("window/geometry", saveGeometry ()); | ||||
| } | ||||
| 
 | ||||
| void AbstractLogWindow::set_log_view (QTableView * log_view) | ||||
| { | ||||
|   // do this here because we know the UI must be setup before this
 | ||||
|   SettingsGroup g {m_->settings_, m_->settings_key_}; | ||||
|   restoreGeometry (m_->settings_->value ("window/geometry").toByteArray ()); | ||||
|   m_->log_view_ = log_view; | ||||
|   m_->log_view_->setContextMenuPolicy (Qt::ActionsContextMenu); | ||||
|   m_->log_view_->setAlternatingRowColors (true); | ||||
|   m_->log_view_->setSelectionBehavior (QAbstractItemView::SelectRows); | ||||
|   m_->log_view_->setSelectionMode (QAbstractItemView::ExtendedSelection); | ||||
|   m_->model_.setSourceModel (m_->log_view_->model ()); | ||||
|   m_->log_view_->setModel (&m_->model_); | ||||
|   m_->log_view_->setColumnHidden (0, true); | ||||
|   auto horizontal_header = log_view->horizontalHeader (); | ||||
|   horizontal_header->setSectionResizeMode (QHeaderView::ResizeToContents); | ||||
|   horizontal_header->setSectionsMovable (true); | ||||
|   m_->log_view_->verticalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents); | ||||
|   set_log_view_font (m_->configuration_->decoded_text_font ()); | ||||
|   m_->log_view_->scrollToBottom (); | ||||
| 
 | ||||
|   // actions
 | ||||
|   auto delete_action = new QAction {tr ("&Delete ..."), m_->log_view_}; | ||||
|   m_->log_view_->insertAction (nullptr, delete_action); | ||||
|   connect (delete_action, &QAction::triggered, [this] (bool /*checked*/) { | ||||
|       m_->delete_QSOs (); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| void AbstractLogWindow::set_log_view_font (QFont const& font) | ||||
| { | ||||
|   // m_->log_view_->setFont (font);
 | ||||
|   // m_->log_view_->horizontalHeader ()->setFont (font);
 | ||||
|   // m_->log_view_->verticalHeader ()->setFont (font);
 | ||||
|   m_->model_.set_font (font); | ||||
| } | ||||
							
								
								
									
										41
									
								
								widgets/AbstractLogWindow.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								widgets/AbstractLogWindow.hpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | ||||
| #ifndef ABSTRACT_LOG_WINDOW_HPP_ | ||||
| #define ABSTRACT_LOG_WINDOW_HPP_ | ||||
| 
 | ||||
| #include <QWidget> | ||||
| #include "pimpl_h.hpp" | ||||
| 
 | ||||
| class QString; | ||||
| class QSettings; | ||||
| class Configuration; | ||||
| class QTableView; | ||||
| class QFont; | ||||
| 
 | ||||
| //
 | ||||
| // AbstractLogWindow - Base class for log view windows
 | ||||
| //
 | ||||
| // QWidget that manages the common functionality shared by windows
 | ||||
| // that include a QSO log view.
 | ||||
| //
 | ||||
| class AbstractLogWindow | ||||
|   : public QWidget | ||||
| { | ||||
| public: | ||||
|   AbstractLogWindow (QString const& settings_key, QSettings * settings | ||||
|                      , Configuration const * configuration | ||||
|                      , QWidget * parent = nullptr); | ||||
|   virtual ~AbstractLogWindow () = 0; | ||||
| 
 | ||||
|   // set the QTableView that shows the log records, must have its
 | ||||
|   // model set before calling this
 | ||||
|   void set_log_view (QTableView *); | ||||
| 
 | ||||
|   void set_log_view_font (QFont const&); | ||||
| 
 | ||||
| private: | ||||
|   virtual void log_model_changed (int row = -1) = 0; | ||||
| 
 | ||||
|   class impl; | ||||
|   pimpl<impl> m_; | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
| @ -1,77 +1,87 @@ | ||||
| #include "CabrilloLogWindow.hpp" | ||||
| 
 | ||||
| #include <QSettings> | ||||
| #include <QApplication> | ||||
| #include <QDateTime> | ||||
| #include <QDir> | ||||
| #include <QStyledItemDelegate> | ||||
| #include <QDateTimeEdit> | ||||
| #include <QPainter> | ||||
| 
 | ||||
| #include "SettingsGroup.hpp" | ||||
| #include <QIdentityProxyModel> | ||||
| #include <QSqlTableModel> | ||||
| #include "Configuration.hpp" | ||||
| #include "models/Bands.hpp" | ||||
| #include "item_delegates/ForeignKeyDelegate.hpp" | ||||
| #include "item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp" | ||||
| #include "item_delegates/CallsignDelegate.hpp" | ||||
| #include "item_delegates/MaidenheadLocatorDelegate.hpp" | ||||
| #include "widgets/MessageBox.hpp" | ||||
| #include "qt_helpers.hpp" | ||||
| #include "pimpl_impl.hpp" | ||||
| 
 | ||||
| #include "ui_CabrilloLogWindow.h" | ||||
| 
 | ||||
| CabrilloLogWindow::CabrilloLogWindow (QSettings * settings, Configuration const * configuration | ||||
|                             , QAbstractItemModel * cabrillo_log_model, QWidget * parent) | ||||
|   : QWidget {parent} | ||||
|   , settings_ {settings} | ||||
|   , configuration_ {configuration} | ||||
|   , ui_ {new Ui::CabrilloLogWindow} | ||||
| namespace | ||||
| { | ||||
|   cabrillo_log_model_.setSourceModel (cabrillo_log_model); | ||||
|   setWindowTitle (QApplication::applicationName () + " - Cabrillo Log"); | ||||
|   ui_->setupUi (this); | ||||
|   read_settings (); | ||||
|   change_font (configuration_->decoded_text_font ()); | ||||
|   ui_->log_table_view->setModel (&cabrillo_log_model_); | ||||
|   ui_->log_table_view->setColumnHidden (0, true); | ||||
|   ui_->log_table_view->setItemDelegateForColumn (2, new DateTimeAsSecsSinceEpochDelegate {this}); | ||||
|   ui_->log_table_view->setItemDelegateForColumn (3, new CallsignDelegate {this}); | ||||
|   ui_->log_table_view->setItemDelegateForColumn (6, new ForeignKeyDelegate {configuration_->bands (), &cabrillo_log_model_, 0, 6, this}); | ||||
|   ui_->log_table_view->setSelectionMode (QTableView::SingleSelection); | ||||
|   auto horizontal_header = ui_->log_table_view->horizontalHeader (); | ||||
|   horizontal_header->setStretchLastSection (true); | ||||
|   horizontal_header->setSectionResizeMode (QHeaderView::ResizeToContents); | ||||
|   horizontal_header->setSectionsMovable (true); | ||||
|   horizontal_header->moveSection (6, 1); // band to first column
 | ||||
|   ui_->log_table_view->scrollToBottom (); | ||||
|   class FormatProxyModel final | ||||
|     : public QIdentityProxyModel | ||||
|   { | ||||
|   public: | ||||
|     explicit FormatProxyModel (QObject * parent = nullptr) | ||||
|       : QIdentityProxyModel {parent} | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|   // ensure view scrolls to latest new row
 | ||||
|   connect (&cabrillo_log_model_, &QAbstractItemModel::rowsInserted, [this] (QModelIndex const& /*parent*/, int /*first*/, int /*last*/) { | ||||
|       ui_->log_table_view->scrollToBottom (); | ||||
|     }); | ||||
|     QVariant data (QModelIndex const& index, int role) const override | ||||
|     { | ||||
|       if (Qt::TextAlignmentRole == role && index.isValid ()) | ||||
|         { | ||||
|           switch (index.column ()) | ||||
|             { | ||||
|             case 1: | ||||
|             case 6: | ||||
|               return Qt::AlignRight + Qt::AlignVCenter; | ||||
|             default: | ||||
|               break; | ||||
|             } | ||||
|         } | ||||
|       return QIdentityProxyModel::data (index, role); | ||||
|     } | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| class CabrilloLogWindow::impl final | ||||
| { | ||||
| public: | ||||
|   explicit impl (QSqlTableModel * log_model) | ||||
|     : log_model_ {log_model} | ||||
|   { | ||||
|   } | ||||
| 
 | ||||
|   QSqlTableModel * log_model_; | ||||
|   FormatProxyModel format_model_; | ||||
|   Ui::CabrilloLogWindow ui_; | ||||
| }; | ||||
| 
 | ||||
| CabrilloLogWindow::CabrilloLogWindow (QSettings * settings, Configuration const * configuration | ||||
|                             , QSqlTableModel * cabrillo_log_model, QWidget * parent) | ||||
|   : AbstractLogWindow {"Cabrillo Log Window", settings, configuration, parent} | ||||
|   , m_{cabrillo_log_model} | ||||
| { | ||||
|   setWindowTitle (QApplication::applicationName () + " - Cabrillo Log"); | ||||
|   m_->ui_.setupUi (this); | ||||
|   m_->format_model_.setSourceModel (m_->log_model_); | ||||
|   m_->ui_.log_table_view->setModel (&m_->format_model_); | ||||
|   set_log_view (m_->ui_.log_table_view); | ||||
|   m_->ui_.log_table_view->setItemDelegateForColumn (2, new DateTimeAsSecsSinceEpochDelegate {this}); | ||||
|   m_->ui_.log_table_view->setItemDelegateForColumn (3, new CallsignDelegate {this}); | ||||
|   m_->ui_.log_table_view->setItemDelegateForColumn (6, new ForeignKeyDelegate {configuration->bands (), m_->log_model_, 0, 6, this}); | ||||
|   m_->ui_.log_table_view->horizontalHeader ()->moveSection (6, 1); // band to first column
 | ||||
| } | ||||
| 
 | ||||
| CabrilloLogWindow::~CabrilloLogWindow () | ||||
| { | ||||
|   write_settings (); | ||||
| } | ||||
| 
 | ||||
| void CabrilloLogWindow::read_settings () | ||||
| void CabrilloLogWindow::log_model_changed (int row) | ||||
| { | ||||
|   SettingsGroup g {settings_, "Cabrillo Log Window"}; | ||||
|   restoreGeometry (settings_->value ("window/geometery").toByteArray ()); | ||||
| } | ||||
| 
 | ||||
| void CabrilloLogWindow::write_settings () const | ||||
| { | ||||
|   SettingsGroup g {settings_, "Cabrillo Log Window"}; | ||||
|   settings_->setValue ("window/geometery", saveGeometry ()); | ||||
| } | ||||
| 
 | ||||
| void CabrilloLogWindow::change_font (QFont const& font) | ||||
| { | ||||
|   // ui_->log_table_view->setFont (font);
 | ||||
|   // ui_->log_table_view->horizontalHeader ()->setFont (font);
 | ||||
|   // ui_->log_table_view->verticalHeader ()->setFont (font);
 | ||||
|   cabrillo_log_model_.set_font (font); | ||||
|   if (row >= 0) | ||||
|     { | ||||
|       m_->log_model_->selectRow (row); | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       m_->log_model_->select (); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,39 +1,27 @@ | ||||
| #ifndef CABRILLO_LOG_WINDOW_HPP_ | ||||
| #define CABRILLO_LOG_WINDOW_HPP_ | ||||
| 
 | ||||
| #include <QWidget> | ||||
| #include <QScopedPointer> | ||||
| #include <QIdentityProxyModel> | ||||
| #include "models/FontOverrideModel.hpp" | ||||
| #include "AbstractLogWindow.hpp" | ||||
| #include "pimpl_h.hpp" | ||||
| 
 | ||||
| class QSettings; | ||||
| class Configuration; | ||||
| class QFont; | ||||
| class QDateTime; | ||||
| class QAbstractItemModel; | ||||
| namespace Ui | ||||
| { | ||||
|   class CabrilloLogWindow; | ||||
| } | ||||
| class QSqlTableModel; | ||||
| 
 | ||||
| class CabrilloLogWindow final | ||||
|   : public QWidget | ||||
|   : public AbstractLogWindow | ||||
| { | ||||
| public: | ||||
|   explicit CabrilloLogWindow (QSettings *, Configuration const *, QAbstractItemModel * cabrillo_log_model | ||||
|                          , QWidget * parent = nullptr); | ||||
|   explicit CabrilloLogWindow (QSettings *, Configuration const *, QSqlTableModel * cabrillo_log_model | ||||
|                               , QWidget * parent = nullptr); | ||||
|   ~CabrilloLogWindow (); | ||||
| 
 | ||||
|   void change_font (QFont const&); | ||||
| 
 | ||||
| private: | ||||
|   void read_settings (); | ||||
|   void write_settings () const; | ||||
|   void log_model_changed (int row) override; | ||||
| 
 | ||||
|   QSettings * settings_; | ||||
|   Configuration const * configuration_; | ||||
|   FontOverrideModel cabrillo_log_model_; | ||||
|   QScopedPointer<Ui::CabrilloLogWindow> ui_; | ||||
|   class impl; | ||||
|   pimpl<impl> m_; | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -2,12 +2,27 @@ | ||||
| <ui version="4.0"> | ||||
|  <class>CabrilloLogWindow</class> | ||||
|  <widget class="QWidget" name="CabrilloLogWindow"> | ||||
|   <property name="geometry"> | ||||
|    <rect> | ||||
|     <x>0</x> | ||||
|     <y>0</y> | ||||
|     <width>493</width> | ||||
|     <height>210</height> | ||||
|    </rect> | ||||
|   </property> | ||||
|   <property name="windowTitle"> | ||||
|    <string>Contest Log</string> | ||||
|   </property> | ||||
|   <layout class="QVBoxLayout" name="verticalLayout"> | ||||
|    <item> | ||||
|     <widget class="QTableView" name="log_table_view"/> | ||||
|     <widget class="QTableView" name="log_table_view"> | ||||
|      <property name="toolTip"> | ||||
|       <string><html><head/><body><p>Right-click here for available actions.</p></body></html></string> | ||||
|      </property> | ||||
|      <attribute name="horizontalHeaderStretchLastSection"> | ||||
|       <bool>true</bool> | ||||
|      </attribute> | ||||
|     </widget> | ||||
|    </item> | ||||
|   </layout> | ||||
|  </widget> | ||||
|  | ||||
| @ -76,7 +76,7 @@ void ExportCabrillo::save_log () | ||||
|   auto fname = QFileDialog::getSaveFileName (this | ||||
|                                              , tr ("Save Log File") | ||||
|                                              , configuration_->writeable_data_dir ().absolutePath () | ||||
|                                              , tr ("Cabrillo Log (*.log)")); | ||||
|                                              , tr ("Cabrillo Log (*.cbr)")); | ||||
|   if (fname.size ()) | ||||
|     { | ||||
|       QFile f {fname}; | ||||
|  | ||||
| @ -1,96 +1,97 @@ | ||||
| #include "FoxLogWindow.hpp" | ||||
| 
 | ||||
| #include <QSettings> | ||||
| #include <QApplication> | ||||
| #include <QDateTime> | ||||
| #include <QSqlTableModel> | ||||
| #include <QAction> | ||||
| #include <QFile> | ||||
| #include <QDir> | ||||
| #include <QStyledItemDelegate> | ||||
| #include <QDateTimeEdit> | ||||
| #include <QPainter> | ||||
| 
 | ||||
| #include "SettingsGroup.hpp" | ||||
| #include "Configuration.hpp" | ||||
| #include "MessageBox.hpp" | ||||
| #include "models/Bands.hpp" | ||||
| #include "item_delegates/ForeignKeyDelegate.hpp" | ||||
| #include "item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp" | ||||
| #include "item_delegates/CallsignDelegate.hpp" | ||||
| #include "item_delegates/MaidenheadLocatorDelegate.hpp" | ||||
| #include "widgets/MessageBox.hpp" | ||||
| #include "qt_helpers.hpp" | ||||
| #include "pimpl_impl.hpp" | ||||
| 
 | ||||
| #include "ui_FoxLogWindow.h" | ||||
| #include "moc_FoxLogWindow.cpp" | ||||
| 
 | ||||
| class FoxLogWindow::impl final | ||||
| { | ||||
| public: | ||||
|   explicit impl (QSqlTableModel * log_model) | ||||
|     : log_model_ {log_model} | ||||
|   { | ||||
|   } | ||||
| 
 | ||||
|   QSqlTableModel * log_model_; | ||||
|   Ui::FoxLogWindow ui_; | ||||
| }; | ||||
| 
 | ||||
| FoxLogWindow::FoxLogWindow (QSettings * settings, Configuration const * configuration | ||||
|                             , QAbstractItemModel * fox_log_model, QWidget * parent) | ||||
|   : QWidget {parent} | ||||
|   , settings_ {settings} | ||||
|   , configuration_ {configuration} | ||||
|   , ui_ {new Ui::FoxLogWindow} | ||||
|                             , QSqlTableModel * fox_log_model, QWidget * parent) | ||||
|   : AbstractLogWindow {"Fox Log Window", settings, configuration, parent} | ||||
|   , m_ {fox_log_model} | ||||
| { | ||||
|   fox_log_model_.setSourceModel (fox_log_model); | ||||
|   setWindowTitle (QApplication::applicationName () + " - Fox Log"); | ||||
|   ui_->setupUi (this); | ||||
|   read_settings (); | ||||
|   change_font (configuration_->decoded_text_font ()); | ||||
|   ui_->log_table_view->setModel (&fox_log_model_); | ||||
|   ui_->log_table_view->setColumnHidden (0, true); | ||||
|   ui_->log_table_view->setItemDelegateForColumn (1, new DateTimeAsSecsSinceEpochDelegate {this}); | ||||
|   ui_->log_table_view->setItemDelegateForColumn (2, new CallsignDelegate {this}); | ||||
|   ui_->log_table_view->setItemDelegateForColumn (3, new MaidenheadLocatorDelegate {this}); | ||||
|   ui_->log_table_view->setItemDelegateForColumn (6, new ForeignKeyDelegate {configuration_->bands (), &fox_log_model_, 0, 6, this}); | ||||
|   ui_->log_table_view->setSelectionMode (QTableView::SingleSelection); | ||||
|   auto horizontal_header = ui_->log_table_view->horizontalHeader (); | ||||
|   horizontal_header->setStretchLastSection (true); | ||||
|   horizontal_header->setSectionResizeMode (QHeaderView::ResizeToContents); | ||||
|   horizontal_header->setSectionsMovable (true); | ||||
|   horizontal_header->moveSection (6, 1); // move band to first column
 | ||||
|   ui_->rate_label->setNum (0); | ||||
|   ui_->queued_label->setNum (0); | ||||
|   ui_->callers_label->setNum (0); | ||||
|   ui_->log_table_view->scrollToBottom (); | ||||
|   m_->ui_.setupUi (this); | ||||
|   m_->ui_.log_table_view->setModel (m_->log_model_); | ||||
|   set_log_view (m_->ui_.log_table_view); | ||||
|   m_->ui_.log_table_view->setItemDelegateForColumn (1, new DateTimeAsSecsSinceEpochDelegate {this}); | ||||
|   m_->ui_.log_table_view->setItemDelegateForColumn (2, new CallsignDelegate {this}); | ||||
|   m_->ui_.log_table_view->setItemDelegateForColumn (3, new MaidenheadLocatorDelegate {this}); | ||||
|   m_->ui_.log_table_view->setItemDelegateForColumn (6, new ForeignKeyDelegate {configuration->bands (), m_->log_model_, 0, 6, this}); | ||||
|   m_->ui_.log_table_view->horizontalHeader ()->moveSection (6, 1); // move band to first column
 | ||||
|   m_->ui_.rate_label->setNum (0); | ||||
|   m_->ui_.queued_label->setNum (0); | ||||
|   m_->ui_.callers_label->setNum (0); | ||||
| 
 | ||||
|   // ensure view scrolls to latest new row
 | ||||
|   connect (&fox_log_model_, &QAbstractItemModel::rowsInserted, [this] (QModelIndex const& /*parent*/, int /*first*/, int /*last*/) { | ||||
|       ui_->log_table_view->scrollToBottom (); | ||||
|   // actions
 | ||||
|   auto reset_action = new QAction {tr ("&Reset ..."), m_->ui_.log_table_view}; | ||||
|   m_->ui_.log_table_view->insertAction (nullptr, reset_action); | ||||
|   connect (reset_action, &QAction::triggered, [this, configuration] (bool /*checked*/) { | ||||
|       if (MessageBox::Yes == MessageBox::query_message( this | ||||
|                                                         , tr ("Confirm Reset") | ||||
|                                                         , tr ("Are you sure you want to erase file FoxQSO.txt " | ||||
|                                                               "and start a new Fox log?"))) | ||||
|         { | ||||
|           QFile f{configuration->writeable_data_dir ().absoluteFilePath ("FoxQSO.txt")}; | ||||
|           f.remove (); | ||||
|           Q_EMIT reset_log_model (); | ||||
|         } | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| FoxLogWindow::~FoxLogWindow () | ||||
| { | ||||
|   write_settings (); | ||||
| } | ||||
| 
 | ||||
| void FoxLogWindow::read_settings () | ||||
| { | ||||
|   SettingsGroup g {settings_, "Fox Log Window"}; | ||||
|   restoreGeometry (settings_->value ("window/geometery").toByteArray ()); | ||||
| } | ||||
| 
 | ||||
| void FoxLogWindow::write_settings () const | ||||
| { | ||||
|   SettingsGroup g {settings_, "Fox Log Window"}; | ||||
|   settings_->setValue ("window/geometery", saveGeometry ()); | ||||
| } | ||||
| 
 | ||||
| void FoxLogWindow::change_font (QFont const& font) | ||||
| { | ||||
|   // ui_->log_table_view->setFont (font);
 | ||||
|   // ui_->log_table_view->horizontalHeader ()->setFont (font);
 | ||||
|   // ui_->log_table_view->verticalHeader ()->setFont (font);
 | ||||
|   fox_log_model_.set_font (font); | ||||
| } | ||||
| 
 | ||||
| void FoxLogWindow::callers (int n) | ||||
| { | ||||
|   ui_->callers_label->setNum (n); | ||||
|   m_->ui_.callers_label->setNum (n); | ||||
| } | ||||
| 
 | ||||
| void FoxLogWindow::queued (int n) | ||||
| { | ||||
|   ui_->queued_label->setNum (n); | ||||
|   m_->ui_.queued_label->setNum (n); | ||||
| } | ||||
| 
 | ||||
| void FoxLogWindow::rate (int n) | ||||
| { | ||||
|   ui_->rate_label->setNum (n); | ||||
|   m_->ui_.rate_label->setNum (n); | ||||
| } | ||||
| 
 | ||||
| void FoxLogWindow::log_model_changed (int row) | ||||
| { | ||||
|   if (row >= 0) | ||||
|     { | ||||
|       m_->log_model_->selectRow (row); | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       m_->log_model_->select (); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,42 +1,35 @@ | ||||
| #ifndef FOX_LOG_WINDOW_HPP_ | ||||
| #define FOX_LOG_WINDOW_HPP_ | ||||
| 
 | ||||
| #include <QWidget> | ||||
| #include <QScopedPointer> | ||||
| #include <QIdentityProxyModel> | ||||
| #include "models/FontOverrideModel.hpp" | ||||
| #include "AbstractLogWindow.hpp" | ||||
| #include "pimpl_h.hpp" | ||||
| 
 | ||||
| class QSettings; | ||||
| class Configuration; | ||||
| class QFont; | ||||
| class QDateTime; | ||||
| class QAbstractItemModel; | ||||
| namespace Ui | ||||
| { | ||||
|   class FoxLogWindow; | ||||
| } | ||||
| class QSqlTableModel; | ||||
| 
 | ||||
| class FoxLogWindow final | ||||
|   : public QWidget | ||||
|   : public AbstractLogWindow | ||||
| { | ||||
|   Q_OBJECT | ||||
| 
 | ||||
| public: | ||||
|   explicit FoxLogWindow (QSettings *, Configuration const *, QAbstractItemModel * fox_log_model | ||||
|   explicit FoxLogWindow (QSettings *, Configuration const *, QSqlTableModel * fox_log_model | ||||
|                          , QWidget * parent = nullptr); | ||||
|   ~FoxLogWindow (); | ||||
| 
 | ||||
|   void change_font (QFont const&); | ||||
|   void callers (int); | ||||
|   void queued (int); | ||||
|   void rate (int); | ||||
| 
 | ||||
| private: | ||||
|   void read_settings (); | ||||
|   void write_settings () const; | ||||
|   Q_SIGNAL void reset_log_model () const; | ||||
| 
 | ||||
|   QSettings * settings_; | ||||
|   Configuration const * configuration_; | ||||
|   FontOverrideModel fox_log_model_; | ||||
|   QScopedPointer<Ui::FoxLogWindow> ui_; | ||||
| private: | ||||
|   void log_model_changed (int row) override; | ||||
| 
 | ||||
|   class impl; | ||||
|   pimpl<impl> m_; | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -2,12 +2,33 @@ | ||||
| <ui version="4.0"> | ||||
|  <class>FoxLogWindow</class> | ||||
|  <widget class="QWidget" name="FoxLogWindow"> | ||||
|   <property name="geometry"> | ||||
|    <rect> | ||||
|     <x>0</x> | ||||
|     <y>0</y> | ||||
|     <width>453</width> | ||||
|     <height>238</height> | ||||
|    </rect> | ||||
|   </property> | ||||
|   <property name="contextMenuPolicy"> | ||||
|    <enum>Qt::DefaultContextMenu</enum> | ||||
|   </property> | ||||
|   <property name="windowTitle"> | ||||
|    <string>Fox Log</string> | ||||
|   </property> | ||||
|   <layout class="QVBoxLayout" name="verticalLayout"> | ||||
|    <item> | ||||
|     <widget class="QTableView" name="log_table_view"/> | ||||
|     <widget class="QTableView" name="log_table_view"> | ||||
|      <property name="contextMenuPolicy"> | ||||
|       <enum>Qt::ActionsContextMenu</enum> | ||||
|      </property> | ||||
|      <property name="toolTip"> | ||||
|       <string><html><head/><body><p>Right-click here for available actions.</p></body></html></string> | ||||
|      </property> | ||||
|      <attribute name="horizontalHeaderStretchLastSection"> | ||||
|       <bool>true</bool> | ||||
|      </attribute> | ||||
|     </widget> | ||||
|    </item> | ||||
|    <item> | ||||
|     <layout class="QHBoxLayout" name="horizontalLayout"> | ||||
|  | ||||
| @ -213,7 +213,7 @@ auto Astro::astroUpdate(QDateTime const& t, QString const& mygrid, QString const | ||||
|         // we do the next period if we calculate just before it starts
 | ||||
|         auto sec_since_epoch = t.toMSecsSinceEpoch () / 1000 + 2; | ||||
|         auto target_sec = sec_since_epoch - sec_since_epoch % TR_period + TR_period / 2; | ||||
|         auto target_date_time = QDateTime::fromMSecsSinceEpoch (target_sec * 1000, QTimeZone::utc ()); | ||||
|         auto target_date_time = QDateTime::fromMSecsSinceEpoch (target_sec * 1000, Qt::UTC); | ||||
|         QString date {target_date_time.date().toString("yyyy MMM dd").trimmed ()}; | ||||
|         QString utc {target_date_time.time().toString().trimmed ()}; | ||||
|         int nyear {target_date_time.date().year()}; | ||||
|  | ||||
| @ -120,6 +120,7 @@ namespace | ||||
| void DisplayText::appendText(QString const& text, QColor bg, QColor fg | ||||
|                              , QString const& call1, QString const& call2) | ||||
| { | ||||
| //  qDebug () << "DisplayText::appendText: text:" << text << "Nbsp pos:" << text.indexOf (QChar::Nbsp);
 | ||||
|   auto cursor = textCursor (); | ||||
|   cursor.movePosition (QTextCursor::End); | ||||
|   auto block_format = cursor.blockFormat (); | ||||
|  | ||||
| @ -10,6 +10,7 @@ | ||||
| #include "MessageBox.hpp" | ||||
| #include "Configuration.hpp" | ||||
| #include "models/Bands.hpp" | ||||
| #include "models/CabrilloLog.hpp" | ||||
| #include "validators/MaidenheadLocatorValidator.hpp" | ||||
| 
 | ||||
| #include "ui_logqso.h" | ||||
| @ -57,11 +58,10 @@ void LogQSO::storeSettings () const | ||||
| void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString mode, | ||||
|                         QString const& rptSent, QString const& rptRcvd, | ||||
|                         QDateTime const& dateTimeOn, QDateTime const& dateTimeOff, | ||||
|                         Radio::Frequency dialFreq, bool noSuffix, QString xSent, QString xRcvd) | ||||
|                         Radio::Frequency dialFreq, bool noSuffix, QString xSent, QString xRcvd, | ||||
|                         CabrilloLog * cabrillo_log) | ||||
| { | ||||
|   if(!isHidden()) return; | ||||
|   m_xSent=xSent; | ||||
|   m_xRcvd=xRcvd; | ||||
|   ui->call->setText(hisCall); | ||||
|   ui->grid->setText(hisGrid); | ||||
|   ui->name->setText(""); | ||||
| @ -87,17 +87,23 @@ void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString | ||||
|   m_myGrid=m_config->my_grid(); | ||||
|   ui->band->setText (m_config->bands ()->find (dialFreq)); | ||||
|   ui->loggedOperator->setText(m_config->opCall()); | ||||
|   ui->exchSent->setText(m_xSent); | ||||
|   ui->exchRcvd->setText(m_xRcvd); | ||||
|   ui->exchSent->setText (xSent); | ||||
|   ui->exchRcvd->setText (xRcvd); | ||||
|   m_cabrilloLog = cabrillo_log; | ||||
| 
 | ||||
|   using SpOp = Configuration::SpecialOperatingActivity; | ||||
|   if( SpOp::FOX == m_config->special_op_id() or  | ||||
|       (m_config->autoLog() and SpOp::NONE < m_config->special_op_id() and | ||||
|       m_xSent!="" and m_xRcvd!="")) { | ||||
|     accept(); | ||||
|   } else { | ||||
|     show(); | ||||
|   } | ||||
|   auto special_op = m_config->special_op_id (); | ||||
|   if (SpOp::FOX == special_op | ||||
|       || (m_config->autoLog () | ||||
|           && SpOp::NONE < special_op && special_op < SpOp::FOX)) | ||||
|     { | ||||
|       // allow auto logging in Fox mode and contests
 | ||||
|       accept(); | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       show(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void LogQSO::accept() | ||||
| @ -120,6 +126,29 @@ void LogQSO::accept() | ||||
|   QString strDialFreq(QString::number(m_dialFreq / 1.e6,'f',6)); | ||||
|   operator_call = ui->loggedOperator->text(); | ||||
| 
 | ||||
|   // validate
 | ||||
|   using SpOp = Configuration::SpecialOperatingActivity; | ||||
|   auto special_op = m_config->special_op_id (); | ||||
|   if (SpOp::NONE < special_op && special_op < SpOp::FOX) | ||||
|     { | ||||
|       if (ui->exchSent->text ().isEmpty () || ui->exchRcvd->text ().isEmpty ()) | ||||
|         { | ||||
|           show (); | ||||
|           MessageBox::warning_message (this, tr ("Invalid QSO Data"), | ||||
|                                        tr ("Check exchange sent and received")); | ||||
|           return;               // without accepting
 | ||||
|         } | ||||
| 
 | ||||
|       if (!m_cabrilloLog->add_QSO (m_dialFreq, QDateTime::currentDateTimeUtc (), hisCall, | ||||
|                                    ui->exchSent->text (), ui->exchRcvd->text ())) | ||||
|         { | ||||
|           show (); | ||||
|           MessageBox::warning_message (this, tr ("Invalid QSO Data"), | ||||
|                                        tr ("Check all fields")); | ||||
|           return;               // without accepting
 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|   //Log this QSO to file "wsjtx.log"
 | ||||
|   static QFile f {QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath ("wsjtx.log")}; | ||||
|   if(!f.open(QIODevice::Text | QIODevice::Append)) { | ||||
| @ -169,8 +198,8 @@ void LogQSO::accept() | ||||
|                                           , m_myGrid | ||||
|                                           , m_txPower | ||||
|                                           , operator_call | ||||
|                                           , m_xSent | ||||
|                                           , m_xRcvd)); | ||||
|                                           , ui->exchSent->text () | ||||
|                                           , ui->exchRcvd->text ())); | ||||
|   QDialog::accept(); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -17,6 +17,7 @@ namespace Ui { | ||||
| class QSettings; | ||||
| class Configuration; | ||||
| class QByteArray; | ||||
| class CabrilloLog; | ||||
| 
 | ||||
| class LogQSO : public QDialog | ||||
| { | ||||
| @ -28,7 +29,7 @@ public: | ||||
|   void initLogQSO(QString const& hisCall, QString const& hisGrid, QString mode, | ||||
|                   QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn, | ||||
|                   QDateTime const& dateTimeOff, Radio::Frequency dialFreq,  | ||||
|                   bool noSuffix, QString xSent, QString xRcvd);  | ||||
|                   bool noSuffix, QString xSent, QString xRcvd, CabrilloLog *);  | ||||
| 
 | ||||
| public slots: | ||||
|   void accept(); | ||||
| @ -56,10 +57,9 @@ private: | ||||
|   Radio::Frequency m_dialFreq; | ||||
|   QString m_myCall; | ||||
|   QString m_myGrid; | ||||
|   QString m_xSent; | ||||
|   QString m_xRcvd; | ||||
|   QDateTime m_dateTimeOn; | ||||
|   QDateTime m_dateTimeOff; | ||||
|   CabrilloLog * m_cabrilloLog; | ||||
| }; | ||||
| 
 | ||||
| #endif // LogQSO_H
 | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include <functional> | ||||
| #include <fstream> | ||||
| #include <iterator> | ||||
| #include <algorithm> | ||||
| #include <fftw3.h> | ||||
| #include <QLineEdit> | ||||
| #include <QRegExpValidator> | ||||
| @ -735,6 +736,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, | ||||
|   ui->labDXped->setStyleSheet("QLabel {background-color: red; color: white;}"); | ||||
|   ui->labNextCall->setText(""); | ||||
|   ui->labNextCall->setVisible(false); | ||||
|   ui->labNextCall->setToolTip("");                //### Possibly temporary ? ###
 | ||||
| 
 | ||||
|   for(int i=0; i<28; i++)  {                      //Initialize dBm values
 | ||||
|     float dbm=(10.0*i)/3.0 - 30.0; | ||||
| @ -931,13 +933,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, | ||||
|     ui->cbMenus->setChecked(true); | ||||
|     ui->cbMenus->setChecked(false); | ||||
|   } | ||||
| 
 | ||||
|   mouseLastPos=QCursor::pos(); | ||||
|   m_mouseIdleSeconds=0; | ||||
|   connect(&mouseTimer, &QTimer::timeout, this, &MainWindow::mouseTimerTick); | ||||
|   mouseTimer.start(1000); | ||||
| 
 | ||||
|   // this must be the last statement of constructor
 | ||||
| // this must be the last statement of constructor
 | ||||
|   if (!m_valid) throw std::runtime_error {"Fatal initialization exception"}; | ||||
| } | ||||
| 
 | ||||
| @ -948,10 +944,16 @@ void MainWindow::not_GA_warning_message () | ||||
| 
 | ||||
|   MessageBox::critical_message (this, | ||||
|                                 "This version of WSJT-X is a beta-level Release Candidate.\n\n" | ||||
|                                 "In FT8 and MSK144 modes it uses ONLY the new 77-bit\n" | ||||
|                                 "message formats. It will not decode 75-bit or 72-bit\n" | ||||
|                                 "messages.\n\n" | ||||
|                                 "On December 10, 2018, 77-bit messages will become the\n" | ||||
|                                 "standard. Everyone should upgrade to WSJT-X 2.0 by\n" | ||||
|                                 "January 1, 2019.\n\n" | ||||
|                                 "On-the-air use carries an obligation to report problems\n" | ||||
|                                 "to the WSJT Development group and to upgrade to a GA\n" | ||||
|                                 "(General Availability) release when it becomes available.\n\n" | ||||
|                                 "This version cannot be used after December 31, 2018\n\n"); | ||||
|                                 "This version cannot be used after December 31, 2018.\n\n"); | ||||
| 
 | ||||
|   if(now.daysTo(timeout) < 0) Q_EMIT finished(); | ||||
| } | ||||
| @ -962,22 +964,6 @@ void MainWindow::initialize_fonts () | ||||
|   setDecodedTextFont (m_config.decoded_text_font ()); | ||||
| } | ||||
| 
 | ||||
| void MainWindow::mouseTimerTick() | ||||
| { | ||||
|   QPoint point = QCursor::pos(); | ||||
|   if(point != mouseLastPos) | ||||
|     m_mouseIdleSeconds = 0; | ||||
|   else | ||||
|     m_mouseIdleSeconds++; | ||||
|   mouseLastPos = point; | ||||
| //Here we should do what's necessary when mouseIdleSeconds gets too big.
 | ||||
| //  qDebug() << m_mouseIdleSeconds;
 | ||||
|   if(ui->cbAutoSeq->isChecked() and m_mouseIdleSeconds>300) { | ||||
|     auto_tx_mode (false); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void MainWindow::splash_done () | ||||
| { | ||||
|   m_splash && m_splash->close (); | ||||
| @ -1077,6 +1063,7 @@ void MainWindow::writeSettings() | ||||
|   m_settings->setValue("RR73",m_send_RR73); | ||||
|   m_settings->setValue ("WSPRPreferType1", ui->WSPR_prefer_type_1_check_box->isChecked ()); | ||||
|   m_settings->setValue("UploadSpots",m_uploadSpots); | ||||
|   m_settings->setValue("NoOwnCall",ui->cbNoOwnCall->isChecked()); | ||||
|   m_settings->setValue ("BandHopping", ui->band_hopping_group_box->isChecked ()); | ||||
|   m_settings->setValue ("TRPeriod", ui->sbTR->value ()); | ||||
|   m_settings->setValue("FastMode",m_bFastMode); | ||||
| @ -1168,6 +1155,7 @@ void MainWindow::readSettings() | ||||
|   ui->WSPR_prefer_type_1_check_box->setChecked (m_settings->value ("WSPRPreferType1", true).toBool ()); | ||||
|   m_uploadSpots=m_settings->value("UploadSpots",false).toBool(); | ||||
|   if(!m_uploadSpots) ui->cbUploadWSPR_Spots->setStyleSheet("QCheckBox{background-color: yellow}"); | ||||
|   ui->cbNoOwnCall->setChecked(m_settings->value("NoOwnCall",false).toBool()); | ||||
|   ui->band_hopping_group_box->setChecked (m_settings->value ("BandHopping", false).toBool()); | ||||
|   // setup initial value of tx attenuator
 | ||||
|   m_block_pwr_tooltip = true; | ||||
| @ -1248,10 +1236,10 @@ void MainWindow::setDecodedTextFont (QFont const& font) | ||||
|     m_msgAvgWidget->changeFont (font); | ||||
|   } | ||||
|   if (m_foxLogWindow) { | ||||
|     m_foxLogWindow->change_font (font); | ||||
|     m_foxLogWindow->set_log_view_font (font); | ||||
|   } | ||||
|   if (m_contestLogWindow) { | ||||
|     m_contestLogWindow->change_font (font); | ||||
|     m_contestLogWindow->set_log_view_font (font); | ||||
|   } | ||||
|   updateGeometry (); | ||||
| } | ||||
| @ -1880,7 +1868,6 @@ void MainWindow::keyPressEvent (QKeyEvent * e) | ||||
|       if((e->modifiers() & Qt::ControlModifier) and (e->modifiers() & Qt::ShiftModifier)) { | ||||
|         m_bandEdited = true; | ||||
|         band_changed(m_freqNominal-2000); | ||||
| //        qDebug() << "Down" << m_freqNominal;
 | ||||
|       } else { | ||||
|         n=11; | ||||
|         if(e->modifiers() & Qt::ControlModifier) n+=100; | ||||
| @ -1895,7 +1882,6 @@ void MainWindow::keyPressEvent (QKeyEvent * e) | ||||
|       if((e->modifiers() & Qt::ControlModifier) and (e->modifiers() & Qt::ShiftModifier)) { | ||||
|         m_bandEdited = true; | ||||
|         band_changed(m_freqNominal+2000); | ||||
| //        qDebug() << "Up  " << m_freqNominal;
 | ||||
|       } else { | ||||
|         n=12; | ||||
|         if(e->modifiers() & Qt::ControlModifier) n+=100; | ||||
| @ -2440,6 +2426,10 @@ void MainWindow::on_fox_log_action_triggered() | ||||
| 
 | ||||
|       // Connect signals from fox log window
 | ||||
|       connect (this, &MainWindow::finished, m_foxLogWindow.data (), &FoxLogWindow::close); | ||||
|       connect (m_foxLogWindow.data (), &FoxLogWindow::reset_log_model, [this] () { | ||||
|           if (!m_foxLog) m_foxLog.reset (new FoxLog); | ||||
|           m_foxLog->reset (); | ||||
|         }); | ||||
|     } | ||||
|   m_foxLogWindow->showNormal (); | ||||
|   m_foxLogWindow->raise (); | ||||
| @ -5353,9 +5343,15 @@ void MainWindow::on_logQSOButton_clicked()                 //Log QSO button | ||||
|       default: break; | ||||
|     } | ||||
| 
 | ||||
|   auto special_op = m_config.special_op_id (); | ||||
|   if (SpecOp::NONE < special_op && special_op < SpecOp::FOX) | ||||
|     { | ||||
|       if (!m_cabrilloLog) m_cabrilloLog.reset (new CabrilloLog {&m_config}); | ||||
|     } | ||||
|   m_logDlg->initLogQSO (m_hisCall, grid, m_modeTx, m_rptSent, m_rptRcvd, | ||||
|                         m_dateTimeQSOOn, dateTimeQSOOff, m_freqNominal + | ||||
|                         ui->TxFreqSpinBox->value(), m_noSuffix, m_xSent, m_xRcvd); | ||||
|                         ui->TxFreqSpinBox->value(), m_noSuffix, m_xSent, m_xRcvd, | ||||
|                         m_cabrilloLog.data ()); | ||||
| } | ||||
| 
 | ||||
| void MainWindow::acceptQSO (QDateTime const& QSO_date_off, QString const& call, QString const& grid | ||||
| @ -5372,15 +5368,6 @@ void MainWindow::acceptQSO (QDateTime const& QSO_date_off, QString const& call, | ||||
|                                    tr ("Cannot open \"%1\"").arg (m_logBook.path ())); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|   if (SpecOp::NONE < m_config.special_op_id() && SpecOp::FOX > m_config.special_op_id()) { | ||||
|     if (!m_cabrilloLog) m_cabrilloLog.reset (new CabrilloLog {&m_config}); | ||||
|     m_cabrilloLog->add_QSO (m_freqNominal, QDateTime::currentDateTimeUtc (), m_hisCall, m_xSent, m_xRcvd); | ||||
|     m_xSent=""; | ||||
|     m_xRcvd=""; | ||||
|     ui->sbSerialNumber->setValue (ui->sbSerialNumber->value () + 1); | ||||
|   } | ||||
| 
 | ||||
|   m_messageClient->qso_logged (QSO_date_off, call, grid, dial_freq, mode, rpt_sent, rpt_received | ||||
|                                , tx_power, comments, name, QSO_date_on, operator_call, my_call, my_grid); | ||||
|   m_messageClient->logged_ADIF (ADIF); | ||||
| @ -5400,6 +5387,14 @@ void MainWindow::acceptQSO (QDateTime const& QSO_date_off, QString const& call, | ||||
| 
 | ||||
|   if (m_config.clear_DX () and SpecOp::HOUND != m_config.special_op_id()) clearDX (); | ||||
|   m_dateTimeQSOOn = QDateTime {}; | ||||
|   auto special_op = m_config.special_op_id (); | ||||
|   if (SpecOp::NONE < special_op && special_op < SpecOp::FOX) | ||||
|     { | ||||
|       ui->sbSerialNumber->setValue (ui->sbSerialNumber->value () + 1); | ||||
|     } | ||||
| 
 | ||||
|   m_xSent.clear (); | ||||
|   m_xRcvd.clear (); | ||||
| } | ||||
| 
 | ||||
| qint64 MainWindow::nWidgets(QString t) | ||||
| @ -5464,7 +5459,6 @@ void MainWindow::displayWidgets(qint64 n) | ||||
|     if(i==32) ui->cbCQonly->setVisible(b); | ||||
|     j=j>>1; | ||||
|   } | ||||
|   if(!ui->cbAutoSeq->isVisible()) ui->cbAutoSeq->setChecked(false); | ||||
|   b=SpecOp::EU_VHF==m_config.special_op_id() or (SpecOp::RTTY==m_config.special_op_id() and | ||||
|     (m_config.RTTY_Exchange()=="#" or m_config.RTTY_Exchange()=="DX")); | ||||
|   ui->sbSerialNumber->setVisible(b); | ||||
| @ -6134,25 +6128,14 @@ void MainWindow::on_actionErase_ALL_TXT_triggered()          //Erase ALL.TXT | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void MainWindow::on_reset_fox_log_action_triggered () | ||||
| { | ||||
|   int ret = MessageBox::query_message(this, tr("Confirm Reset"), | ||||
|                   tr("Are you sure you want to erase file FoxQSO.txt and start a new Fox log?")); | ||||
|   if(ret==MessageBox::Yes) { | ||||
|     QFile f{m_config.writeable_data_dir().absoluteFilePath("FoxQSO.txt")}; | ||||
|     f.remove(); | ||||
|     if (!m_foxLog) m_foxLog.reset (new FoxLog); | ||||
|     m_foxLog->reset (); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void MainWindow::on_reset_cabrillo_log_action_triggered () | ||||
| { | ||||
|   if (MessageBox::Yes == MessageBox::query_message(this, tr("Confirm Erase"), | ||||
|                                                    tr("Are you sure you want to erase file cabrillo.log" | ||||
|                                                       " and start a new Cabrillo log?"))) | ||||
|   if (MessageBox::Yes == MessageBox::query_message (this, tr ("Confirm Reset"), | ||||
|                                                     tr ("Are you sure you want to erase your contest log?"), | ||||
|                                                     tr ("Doing this will remove all QSO records for the current contest. " | ||||
|                                                         "They will be kept in the ADIF log file but will not be available " | ||||
|                                                         "for export in your Cabrillo log."))) | ||||
|     { | ||||
|       QFile {m_config.writeable_data_dir ().absoluteFilePath ("cabrillo.log")}.remove (); | ||||
|       ui->sbSerialNumber->setValue (1); | ||||
|       if (!m_cabrilloLog) m_cabrilloLog.reset (new CabrilloLog {&m_config}); | ||||
|       m_cabrilloLog->reset (); | ||||
| @ -6505,15 +6488,17 @@ void MainWindow::on_readFreq_clicked() | ||||
| 
 | ||||
| void MainWindow::on_pbTxMode_clicked() | ||||
| { | ||||
|   if(m_modeTx=="JT9") { | ||||
|     m_modeTx="JT65"; | ||||
|     ui->pbTxMode->setText("Tx JT65  #"); | ||||
|   } else { | ||||
|     m_modeTx="JT9"; | ||||
|     ui->pbTxMode->setText("Tx JT9  @"); | ||||
|   if(m_mode=="JT9+JT65") { | ||||
|     if(m_modeTx=="JT9") { | ||||
|       m_modeTx="JT65"; | ||||
|       ui->pbTxMode->setText("Tx JT65  #"); | ||||
|     } else { | ||||
|       m_modeTx="JT9"; | ||||
|       ui->pbTxMode->setText("Tx JT9  @"); | ||||
|     } | ||||
|     m_wideGraph->setModeTx(m_modeTx); | ||||
|     statusChanged(); | ||||
|   } | ||||
|   m_wideGraph->setModeTx(m_modeTx); | ||||
|   statusChanged(); | ||||
| } | ||||
| 
 | ||||
| void MainWindow::setXIT(int n, Frequency base) | ||||
| @ -7266,6 +7251,10 @@ void MainWindow::p1ReadFromStdout()                        //p1readFromStdout | ||||
|   QString t1; | ||||
|   while(p1.canReadLine()) { | ||||
|     QString t(p1.readLine()); | ||||
|     if(ui->cbNoOwnCall->isChecked()) { | ||||
|       if(t.contains(" " + m_config.my_callsign() + " ")) continue; | ||||
|       if(t.contains(" <" + m_config.my_callsign() + "> ")) continue; | ||||
|     } | ||||
|     if(t.indexOf("<DecodeFinished>") >= 0) { | ||||
|       m_bDecoded = m_nWSPRdecodes > 0; | ||||
|       if(!m_diskData) { | ||||
| @ -7391,7 +7380,6 @@ void MainWindow::WSPR_history(Frequency dialFreq, int ndecodes) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void MainWindow::uploadSpots() | ||||
| { | ||||
|   // do not spot replays or if rig control not working
 | ||||
| @ -7933,9 +7921,9 @@ QString MainWindow::sortHoundCalls(QString t, int isort, int max_dB) | ||||
| 
 | ||||
|   if(isort>1) { | ||||
|     if(bReverse) { | ||||
|       qSort(list.begin(),list.end(),qGreater<int>()); | ||||
|       std::sort (list.begin (), list.end (), std::greater<int> ()); | ||||
|     } else { | ||||
|       qSort(list.begin(),list.end()); | ||||
|       std::sort (list.begin (), list.end ()); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -204,7 +204,6 @@ private slots: | ||||
|   void on_actionDeepestDecode_toggled (bool); | ||||
|   void bumpFqso(int n); | ||||
|   void on_actionErase_ALL_TXT_triggered(); | ||||
|   void on_reset_fox_log_action_triggered (); | ||||
|   void on_reset_cabrillo_log_action_triggered (); | ||||
|   void on_actionErase_wsjtx_log_adi_triggered(); | ||||
|   void on_actionExport_Cabrillo_log_triggered(); | ||||
| @ -446,7 +445,6 @@ private: | ||||
|   qint32  m_Nslots=5; | ||||
|   qint32  m_nFoxMsgTimes[5]={0,0,0,0,0}; | ||||
|   qint32  m_tAutoOn; | ||||
|   qint32  m_mouseIdleSeconds; | ||||
|   qint32  m_tFoxTx=0; | ||||
|   qint32  m_tFoxTx0=0; | ||||
|   qint32  m_maxStrikes=3;      //Max # of repeats: 3 strikes and you're out
 | ||||
| @ -570,9 +568,6 @@ private: | ||||
|   QTimer minuteTimer; | ||||
|   QTimer splashTimer; | ||||
|   QTimer p1Timer; | ||||
|   QTimer mouseTimer; | ||||
| 
 | ||||
|   QPoint mouseLastPos; | ||||
| 
 | ||||
|   QString m_path; | ||||
|   QString m_baseCall; | ||||
| @ -701,7 +696,6 @@ private: | ||||
|   void CQTxFreq(); | ||||
|   void useNextCall(); | ||||
|   void abortQSO(); | ||||
|   void mouseTimerTick(); | ||||
|   bool isWorked(int itype, QString key, float fMHz=0, QString=""); | ||||
| 
 | ||||
|   QString save_wave_file (QString const& name | ||||
|  | ||||
| @ -573,6 +573,430 @@ QLabel[oob="true"] { | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="0" rowspan="2"> | ||||
|        <widget class="SignalMeter" name="signal_meter_widget"> | ||||
|         <property name="sizePolicy"> | ||||
|          <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> | ||||
|           <horstretch>0</horstretch> | ||||
|           <verstretch>0</verstretch> | ||||
|          </sizepolicy> | ||||
|         </property> | ||||
|         <property name="maximumSize"> | ||||
|          <size> | ||||
|           <width>100</width> | ||||
|           <height>16777215</height> | ||||
|          </size> | ||||
|         </property> | ||||
|         <property name="toolTip"> | ||||
|          <string><html><head/><body><p>30dB recommended when only noise present<br/>Green when good<br/>Red when clipping may occur<br/>Yellow when too low</p></body></html></string> | ||||
|         </property> | ||||
|         <property name="frameShape"> | ||||
|          <enum>QFrame::Panel</enum> | ||||
|         </property> | ||||
|         <property name="frameShadow"> | ||||
|          <enum>QFrame::Sunken</enum> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="2"> | ||||
|        <widget class="QWidget" name="DX_controls_widget" native="true"> | ||||
|         <property name="sizePolicy"> | ||||
|          <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> | ||||
|           <horstretch>0</horstretch> | ||||
|           <verstretch>0</verstretch> | ||||
|          </sizepolicy> | ||||
|         </property> | ||||
|         <layout class="QGridLayout" name="gridLayout_2"> | ||||
|          <property name="leftMargin"> | ||||
|           <number>0</number> | ||||
|          </property> | ||||
|          <property name="topMargin"> | ||||
|           <number>0</number> | ||||
|          </property> | ||||
|          <property name="rightMargin"> | ||||
|           <number>0</number> | ||||
|          </property> | ||||
|          <property name="bottomMargin"> | ||||
|           <number>0</number> | ||||
|          </property> | ||||
|          <item row="0" column="0"> | ||||
|           <widget class="QLabel" name="label_3"> | ||||
|            <property name="sizePolicy"> | ||||
|             <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> | ||||
|              <horstretch>0</horstretch> | ||||
|              <verstretch>0</verstretch> | ||||
|             </sizepolicy> | ||||
|            </property> | ||||
|            <property name="palette"> | ||||
|             <palette> | ||||
|              <active> | ||||
|               <colorrole role="Base"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>252</red> | ||||
|                  <green>252</green> | ||||
|                  <blue>252</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|               <colorrole role="Window"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>159</red> | ||||
|                  <green>175</green> | ||||
|                  <blue>213</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|              </active> | ||||
|              <inactive> | ||||
|               <colorrole role="Base"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>252</red> | ||||
|                  <green>252</green> | ||||
|                  <blue>252</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|               <colorrole role="Window"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>159</red> | ||||
|                  <green>175</green> | ||||
|                  <blue>213</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|              </inactive> | ||||
|              <disabled> | ||||
|               <colorrole role="Base"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>159</red> | ||||
|                  <green>175</green> | ||||
|                  <blue>213</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|               <colorrole role="Window"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>159</red> | ||||
|                  <green>175</green> | ||||
|                  <blue>213</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|              </disabled> | ||||
|             </palette> | ||||
|            </property> | ||||
|            <property name="autoFillBackground"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|            <property name="text"> | ||||
|             <string>DX Call</string> | ||||
|            </property> | ||||
|            <property name="alignment"> | ||||
|             <set>Qt::AlignCenter</set> | ||||
|            </property> | ||||
|            <property name="margin"> | ||||
|             <number>5</number> | ||||
|            </property> | ||||
|            <property name="indent"> | ||||
|             <number>2</number> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="0" column="1"> | ||||
|           <widget class="QLabel" name="label_4"> | ||||
|            <property name="sizePolicy"> | ||||
|             <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> | ||||
|              <horstretch>0</horstretch> | ||||
|              <verstretch>0</verstretch> | ||||
|             </sizepolicy> | ||||
|            </property> | ||||
|            <property name="palette"> | ||||
|             <palette> | ||||
|              <active> | ||||
|               <colorrole role="Base"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>252</red> | ||||
|                  <green>252</green> | ||||
|                  <blue>252</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|               <colorrole role="Window"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>159</red> | ||||
|                  <green>175</green> | ||||
|                  <blue>213</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|              </active> | ||||
|              <inactive> | ||||
|               <colorrole role="Base"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>252</red> | ||||
|                  <green>252</green> | ||||
|                  <blue>252</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|               <colorrole role="Window"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>159</red> | ||||
|                  <green>175</green> | ||||
|                  <blue>213</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|              </inactive> | ||||
|              <disabled> | ||||
|               <colorrole role="Base"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>159</red> | ||||
|                  <green>175</green> | ||||
|                  <blue>213</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|               <colorrole role="Window"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>159</red> | ||||
|                  <green>175</green> | ||||
|                  <blue>213</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|              </disabled> | ||||
|             </palette> | ||||
|            </property> | ||||
|            <property name="autoFillBackground"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|            <property name="text"> | ||||
|             <string>DX Grid</string> | ||||
|            </property> | ||||
|            <property name="alignment"> | ||||
|             <set>Qt::AlignCenter</set> | ||||
|            </property> | ||||
|            <property name="margin"> | ||||
|             <number>5</number> | ||||
|            </property> | ||||
|            <property name="indent"> | ||||
|             <number>2</number> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="1" column="0"> | ||||
|           <widget class="QLineEdit" name="dxCallEntry"> | ||||
|            <property name="toolTip"> | ||||
|             <string>Callsign of station to be worked</string> | ||||
|            </property> | ||||
|            <property name="text"> | ||||
|             <string/> | ||||
|            </property> | ||||
|            <property name="alignment"> | ||||
|             <set>Qt::AlignCenter</set> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="3" column="0"> | ||||
|           <widget class="QPushButton" name="lookupButton"> | ||||
|            <property name="toolTip"> | ||||
|             <string>Search for callsign in database</string> | ||||
|            </property> | ||||
|            <property name="text"> | ||||
|             <string>&Lookup</string> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="1" column="1"> | ||||
|           <widget class="QLineEdit" name="dxGridEntry"> | ||||
|            <property name="toolTip"> | ||||
|             <string>Locator of station to be worked</string> | ||||
|            </property> | ||||
|            <property name="text"> | ||||
|             <string/> | ||||
|            </property> | ||||
|            <property name="alignment"> | ||||
|             <set>Qt::AlignCenter</set> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="2" column="0" colspan="2"> | ||||
|           <widget class="QLabel" name="labAz"> | ||||
|            <property name="sizePolicy"> | ||||
|             <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> | ||||
|              <horstretch>0</horstretch> | ||||
|              <verstretch>0</verstretch> | ||||
|             </sizepolicy> | ||||
|            </property> | ||||
|            <property name="autoFillBackground"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|            <property name="text"> | ||||
|             <string>Az: 251     16553 km</string> | ||||
|            </property> | ||||
|            <property name="alignment"> | ||||
|             <set>Qt::AlignCenter</set> | ||||
|            </property> | ||||
|            <property name="indent"> | ||||
|             <number>4</number> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="3" column="1"> | ||||
|           <widget class="QPushButton" name="addButton"> | ||||
|            <property name="toolTip"> | ||||
|             <string>Add callsign and locator to database</string> | ||||
|            </property> | ||||
|            <property name="text"> | ||||
|             <string>Add</string> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|         </layout> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="4"> | ||||
|        <widget class="QLabel" name="label"> | ||||
|         <property name="text"> | ||||
|          <string> Pwr</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="1" alignment="Qt::AlignHCenter|Qt::AlignVCenter"> | ||||
|        <widget class="QPushButton" name="readFreq"> | ||||
|         <property name="enabled"> | ||||
|          <bool>false</bool> | ||||
|         </property> | ||||
|         <property name="toolTip"> | ||||
|          <string><html><head/><body><p>If orange or red there has been a rig control failure, click to reset and read the dial frequency.  S implies split mode.</p></body></html></string> | ||||
|         </property> | ||||
|         <property name="styleSheet"> | ||||
|          <string notr="true">QPushButton { | ||||
|  font-family: helvetica; | ||||
|  font-size: 9pt; | ||||
|  font-weight: bold; | ||||
|  background-color: white; | ||||
|  color: black; | ||||
|  border-style: solid; | ||||
|  border-width:1px; | ||||
|  border-radius:10px; | ||||
|  border-color: gray; | ||||
|  max-width:20px; | ||||
|  max-height:20px; | ||||
|  min-width:20px; | ||||
|  min-height:20px; | ||||
| } | ||||
| QPushButton[state="error"] { | ||||
|  background-color: red; | ||||
| } | ||||
| QPushButton[state="warning"] { | ||||
|  background-color: orange; | ||||
| } | ||||
| QPushButton[state="ok"] { | ||||
|  background-color: #00ff00; | ||||
| }</string> | ||||
|         </property> | ||||
|         <property name="text"> | ||||
|          <string>?</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="4" rowspan="2"> | ||||
|        <widget class="QSlider" name="outAttenuation"> | ||||
|         <property name="toolTip"> | ||||
|          <string>Adjust Tx audio level</string> | ||||
|         </property> | ||||
|         <property name="maximum"> | ||||
|          <number>450</number> | ||||
|         </property> | ||||
|         <property name="value"> | ||||
|          <number>0</number> | ||||
|         </property> | ||||
|         <property name="orientation"> | ||||
|          <enum>Qt::Vertical</enum> | ||||
|         </property> | ||||
|         <property name="invertedAppearance"> | ||||
|          <bool>true</bool> | ||||
|         </property> | ||||
|         <property name="invertedControls"> | ||||
|          <bool>true</bool> | ||||
|         </property> | ||||
|         <property name="tickPosition"> | ||||
|          <enum>QSlider::TicksBelow</enum> | ||||
|         </property> | ||||
|         <property name="tickInterval"> | ||||
|          <number>50</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="0"> | ||||
|        <widget class="QComboBox" name="bandComboBox"> | ||||
|         <property name="toolTip"> | ||||
|          <string><html><head/><body><p>Select operating band or enter frequency in MHz or enter kHz increment followed by k.</p></body></html></string> | ||||
|         </property> | ||||
|         <property name="editable"> | ||||
|          <bool>true</bool> | ||||
|         </property> | ||||
|         <property name="insertPolicy"> | ||||
|          <enum>QComboBox::NoInsert</enum> | ||||
|         </property> | ||||
|         <property name="sizeAdjustPolicy"> | ||||
|          <enum>QComboBox::AdjustToMinimumContentsLength</enum> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="2" column="2"> | ||||
|        <widget class="QLabel" name="labUTC"> | ||||
|         <property name="sizePolicy"> | ||||
|          <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> | ||||
|           <horstretch>0</horstretch> | ||||
|           <verstretch>0</verstretch> | ||||
|          </sizepolicy> | ||||
|         </property> | ||||
|         <property name="styleSheet"> | ||||
|          <string notr="true">QLabel { | ||||
|   font-family: MS Shell Dlg 2; | ||||
|   font-size: 16pt; | ||||
|   background-color : black; | ||||
|   color : yellow; | ||||
| }</string> | ||||
|         </property> | ||||
|         <property name="frameShape"> | ||||
|          <enum>QFrame::StyledPanel</enum> | ||||
|         </property> | ||||
|         <property name="frameShadow"> | ||||
|          <enum>QFrame::Sunken</enum> | ||||
|         </property> | ||||
|         <property name="lineWidth"> | ||||
|          <number>2</number> | ||||
|         </property> | ||||
|         <property name="midLineWidth"> | ||||
|          <number>0</number> | ||||
|         </property> | ||||
|         <property name="text"> | ||||
|          <string><html><head/><body><p align="center"> 2015 Jun 17 </p><p align="center"> 01:23:45 </p></body></html></string> | ||||
|         </property> | ||||
|         <property name="alignment"> | ||||
|          <set>Qt::AlignCenter</set> | ||||
|         </property> | ||||
|         <property name="margin"> | ||||
|          <number>5</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="3" rowspan="3"> | ||||
|        <widget class="QStackedWidget" name="controls_stack_widget"> | ||||
|         <property name="currentIndex"> | ||||
| @ -845,7 +1269,7 @@ QLabel[oob="true"] { | ||||
|                     <bool>false</bool> | ||||
|                    </property> | ||||
|                    <property name="toolTip"> | ||||
|                     <string><html><head/><body><p>Check this to call CQ on the &quot;Tx CQ&quot; frequency. Rx will be on the current frequency and the CQ message wiill include the current Rx frequency so callers know which frequency to reply on.</p><p>Not available to type 2 compound callsign holders.</p></body></html></string> | ||||
|                     <string><html><head/><body><p>Check this to call CQ on the &quot;Tx CQ&quot; frequency. Rx will be on the current frequency and the CQ message wiill include the current Rx frequency so callers know which frequency to reply on.</p><p>Not available to nonstandard callsign holders.</p></body></html></string> | ||||
|                    </property> | ||||
|                    <property name="text"> | ||||
|                     <string/> | ||||
| @ -2105,6 +2529,13 @@ list. The list can be maintained in Settings (F2).</string> | ||||
|                         </property> | ||||
|                        </widget> | ||||
|                       </item> | ||||
|                       <item> | ||||
|                        <widget class="QCheckBox" name="cbNoOwnCall"> | ||||
|                         <property name="text"> | ||||
|                          <string>No own call decodes</string> | ||||
|                         </property> | ||||
|                        </widget> | ||||
|                       </item> | ||||
|                       <item> | ||||
|                        <layout class="QHBoxLayout" name="horizontalLayout_13"> | ||||
|                         <item> | ||||
| @ -2199,430 +2630,6 @@ list. The list can be maintained in Settings (F2).</string> | ||||
|         </widget> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="0" rowspan="2"> | ||||
|        <widget class="SignalMeter" name="signal_meter_widget"> | ||||
|         <property name="sizePolicy"> | ||||
|          <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> | ||||
|           <horstretch>0</horstretch> | ||||
|           <verstretch>0</verstretch> | ||||
|          </sizepolicy> | ||||
|         </property> | ||||
|         <property name="maximumSize"> | ||||
|          <size> | ||||
|           <width>100</width> | ||||
|           <height>16777215</height> | ||||
|          </size> | ||||
|         </property> | ||||
|         <property name="toolTip"> | ||||
|          <string><html><head/><body><p>30dB recommended when only noise present<br/>Green when good<br/>Red when clipping may occur<br/>Yellow when too low</p></body></html></string> | ||||
|         </property> | ||||
|         <property name="frameShape"> | ||||
|          <enum>QFrame::Panel</enum> | ||||
|         </property> | ||||
|         <property name="frameShadow"> | ||||
|          <enum>QFrame::Sunken</enum> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="2"> | ||||
|        <widget class="QWidget" name="DX_controls_widget" native="true"> | ||||
|         <property name="sizePolicy"> | ||||
|          <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> | ||||
|           <horstretch>0</horstretch> | ||||
|           <verstretch>0</verstretch> | ||||
|          </sizepolicy> | ||||
|         </property> | ||||
|         <layout class="QGridLayout" name="gridLayout_2"> | ||||
|          <property name="leftMargin"> | ||||
|           <number>0</number> | ||||
|          </property> | ||||
|          <property name="topMargin"> | ||||
|           <number>0</number> | ||||
|          </property> | ||||
|          <property name="rightMargin"> | ||||
|           <number>0</number> | ||||
|          </property> | ||||
|          <property name="bottomMargin"> | ||||
|           <number>0</number> | ||||
|          </property> | ||||
|          <item row="0" column="0"> | ||||
|           <widget class="QLabel" name="label_3"> | ||||
|            <property name="sizePolicy"> | ||||
|             <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> | ||||
|              <horstretch>0</horstretch> | ||||
|              <verstretch>0</verstretch> | ||||
|             </sizepolicy> | ||||
|            </property> | ||||
|            <property name="palette"> | ||||
|             <palette> | ||||
|              <active> | ||||
|               <colorrole role="Base"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>252</red> | ||||
|                  <green>252</green> | ||||
|                  <blue>252</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|               <colorrole role="Window"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>159</red> | ||||
|                  <green>175</green> | ||||
|                  <blue>213</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|              </active> | ||||
|              <inactive> | ||||
|               <colorrole role="Base"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>252</red> | ||||
|                  <green>252</green> | ||||
|                  <blue>252</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|               <colorrole role="Window"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>159</red> | ||||
|                  <green>175</green> | ||||
|                  <blue>213</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|              </inactive> | ||||
|              <disabled> | ||||
|               <colorrole role="Base"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>159</red> | ||||
|                  <green>175</green> | ||||
|                  <blue>213</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|               <colorrole role="Window"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>159</red> | ||||
|                  <green>175</green> | ||||
|                  <blue>213</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|              </disabled> | ||||
|             </palette> | ||||
|            </property> | ||||
|            <property name="autoFillBackground"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|            <property name="text"> | ||||
|             <string>DX Call</string> | ||||
|            </property> | ||||
|            <property name="alignment"> | ||||
|             <set>Qt::AlignCenter</set> | ||||
|            </property> | ||||
|            <property name="margin"> | ||||
|             <number>5</number> | ||||
|            </property> | ||||
|            <property name="indent"> | ||||
|             <number>2</number> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="0" column="1"> | ||||
|           <widget class="QLabel" name="label_4"> | ||||
|            <property name="sizePolicy"> | ||||
|             <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> | ||||
|              <horstretch>0</horstretch> | ||||
|              <verstretch>0</verstretch> | ||||
|             </sizepolicy> | ||||
|            </property> | ||||
|            <property name="palette"> | ||||
|             <palette> | ||||
|              <active> | ||||
|               <colorrole role="Base"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>252</red> | ||||
|                  <green>252</green> | ||||
|                  <blue>252</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|               <colorrole role="Window"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>159</red> | ||||
|                  <green>175</green> | ||||
|                  <blue>213</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|              </active> | ||||
|              <inactive> | ||||
|               <colorrole role="Base"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>252</red> | ||||
|                  <green>252</green> | ||||
|                  <blue>252</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|               <colorrole role="Window"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>159</red> | ||||
|                  <green>175</green> | ||||
|                  <blue>213</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|              </inactive> | ||||
|              <disabled> | ||||
|               <colorrole role="Base"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>159</red> | ||||
|                  <green>175</green> | ||||
|                  <blue>213</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|               <colorrole role="Window"> | ||||
|                <brush brushstyle="SolidPattern"> | ||||
|                 <color alpha="255"> | ||||
|                  <red>159</red> | ||||
|                  <green>175</green> | ||||
|                  <blue>213</blue> | ||||
|                 </color> | ||||
|                </brush> | ||||
|               </colorrole> | ||||
|              </disabled> | ||||
|             </palette> | ||||
|            </property> | ||||
|            <property name="autoFillBackground"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|            <property name="text"> | ||||
|             <string>DX Grid</string> | ||||
|            </property> | ||||
|            <property name="alignment"> | ||||
|             <set>Qt::AlignCenter</set> | ||||
|            </property> | ||||
|            <property name="margin"> | ||||
|             <number>5</number> | ||||
|            </property> | ||||
|            <property name="indent"> | ||||
|             <number>2</number> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="1" column="0"> | ||||
|           <widget class="QLineEdit" name="dxCallEntry"> | ||||
|            <property name="toolTip"> | ||||
|             <string>Callsign of station to be worked</string> | ||||
|            </property> | ||||
|            <property name="text"> | ||||
|             <string/> | ||||
|            </property> | ||||
|            <property name="alignment"> | ||||
|             <set>Qt::AlignCenter</set> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="1" column="1"> | ||||
|           <widget class="QLineEdit" name="dxGridEntry"> | ||||
|            <property name="toolTip"> | ||||
|             <string>Locator of station to be worked</string> | ||||
|            </property> | ||||
|            <property name="text"> | ||||
|             <string/> | ||||
|            </property> | ||||
|            <property name="alignment"> | ||||
|             <set>Qt::AlignCenter</set> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="3" column="0"> | ||||
|           <widget class="QPushButton" name="lookupButton"> | ||||
|            <property name="toolTip"> | ||||
|             <string>Search for callsign in database</string> | ||||
|            </property> | ||||
|            <property name="text"> | ||||
|             <string>&Lookup</string> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="3" column="1"> | ||||
|           <widget class="QPushButton" name="addButton"> | ||||
|            <property name="toolTip"> | ||||
|             <string>Add callsign and locator to database</string> | ||||
|            </property> | ||||
|            <property name="text"> | ||||
|             <string>Add</string> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|          <item row="2" column="0" colspan="2"> | ||||
|           <widget class="QLabel" name="labAz"> | ||||
|            <property name="sizePolicy"> | ||||
|             <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> | ||||
|              <horstretch>0</horstretch> | ||||
|              <verstretch>0</verstretch> | ||||
|             </sizepolicy> | ||||
|            </property> | ||||
|            <property name="autoFillBackground"> | ||||
|             <bool>true</bool> | ||||
|            </property> | ||||
|            <property name="text"> | ||||
|             <string>Az: 251     16553 km</string> | ||||
|            </property> | ||||
|            <property name="alignment"> | ||||
|             <set>Qt::AlignCenter</set> | ||||
|            </property> | ||||
|            <property name="indent"> | ||||
|             <number>4</number> | ||||
|            </property> | ||||
|           </widget> | ||||
|          </item> | ||||
|         </layout> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="4"> | ||||
|        <widget class="QLabel" name="label"> | ||||
|         <property name="text"> | ||||
|          <string> Pwr</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="1" alignment="Qt::AlignHCenter|Qt::AlignVCenter"> | ||||
|        <widget class="QPushButton" name="readFreq"> | ||||
|         <property name="enabled"> | ||||
|          <bool>false</bool> | ||||
|         </property> | ||||
|         <property name="toolTip"> | ||||
|          <string><html><head/><body><p>If orange or red there has been a rig control failure, click to reset and read the dial frequency.  S implies split mode.</p></body></html></string> | ||||
|         </property> | ||||
|         <property name="styleSheet"> | ||||
|          <string notr="true">QPushButton { | ||||
|  font-family: helvetica; | ||||
|  font-size: 9pt; | ||||
|  font-weight: bold; | ||||
|  background-color: white; | ||||
|  color: black; | ||||
|  border-style: solid; | ||||
|  border-width:1px; | ||||
|  border-radius:10px; | ||||
|  border-color: gray; | ||||
|  max-width:20px; | ||||
|  max-height:20px; | ||||
|  min-width:20px; | ||||
|  min-height:20px; | ||||
| } | ||||
| QPushButton[state="error"] { | ||||
|  background-color: red; | ||||
| } | ||||
| QPushButton[state="warning"] { | ||||
|  background-color: orange; | ||||
| } | ||||
| QPushButton[state="ok"] { | ||||
|  background-color: #00ff00; | ||||
| }</string> | ||||
|         </property> | ||||
|         <property name="text"> | ||||
|          <string>?</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="4" rowspan="2"> | ||||
|        <widget class="QSlider" name="outAttenuation"> | ||||
|         <property name="toolTip"> | ||||
|          <string>Adjust Tx audio level</string> | ||||
|         </property> | ||||
|         <property name="maximum"> | ||||
|          <number>450</number> | ||||
|         </property> | ||||
|         <property name="value"> | ||||
|          <number>0</number> | ||||
|         </property> | ||||
|         <property name="orientation"> | ||||
|          <enum>Qt::Vertical</enum> | ||||
|         </property> | ||||
|         <property name="invertedAppearance"> | ||||
|          <bool>true</bool> | ||||
|         </property> | ||||
|         <property name="invertedControls"> | ||||
|          <bool>true</bool> | ||||
|         </property> | ||||
|         <property name="tickPosition"> | ||||
|          <enum>QSlider::TicksBelow</enum> | ||||
|         </property> | ||||
|         <property name="tickInterval"> | ||||
|          <number>50</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="0"> | ||||
|        <widget class="QComboBox" name="bandComboBox"> | ||||
|         <property name="toolTip"> | ||||
|          <string><html><head/><body><p>Select operating band or enter frequency in MHz or enter kHz increment followed by k.</p></body></html></string> | ||||
|         </property> | ||||
|         <property name="editable"> | ||||
|          <bool>true</bool> | ||||
|         </property> | ||||
|         <property name="insertPolicy"> | ||||
|          <enum>QComboBox::NoInsert</enum> | ||||
|         </property> | ||||
|         <property name="sizeAdjustPolicy"> | ||||
|          <enum>QComboBox::AdjustToMinimumContentsLength</enum> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="2" column="2"> | ||||
|        <widget class="QLabel" name="labUTC"> | ||||
|         <property name="sizePolicy"> | ||||
|          <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> | ||||
|           <horstretch>0</horstretch> | ||||
|           <verstretch>0</verstretch> | ||||
|          </sizepolicy> | ||||
|         </property> | ||||
|         <property name="styleSheet"> | ||||
|          <string notr="true">QLabel { | ||||
|   font-family: MS Shell Dlg 2; | ||||
|   font-size: 16pt; | ||||
|   background-color : black; | ||||
|   color : yellow; | ||||
| }</string> | ||||
|         </property> | ||||
|         <property name="frameShape"> | ||||
|          <enum>QFrame::StyledPanel</enum> | ||||
|         </property> | ||||
|         <property name="frameShadow"> | ||||
|          <enum>QFrame::Sunken</enum> | ||||
|         </property> | ||||
|         <property name="lineWidth"> | ||||
|          <number>2</number> | ||||
|         </property> | ||||
|         <property name="midLineWidth"> | ||||
|          <number>0</number> | ||||
|         </property> | ||||
|         <property name="text"> | ||||
|          <string><html><head/><body><p align="center"> 2015 Jun 17 </p><p align="center"> 01:23:45 </p></body></html></string> | ||||
|         </property> | ||||
|         <property name="alignment"> | ||||
|          <set>Qt::AlignCenter</set> | ||||
|         </property> | ||||
|         <property name="margin"> | ||||
|          <number>5</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|      </layout> | ||||
|     </item> | ||||
|    </layout> | ||||
| @ -2646,7 +2653,6 @@ QPushButton[state="ok"] { | ||||
|     <addaction name="separator"/> | ||||
|     <addaction name="actionDelete_all_wav_files_in_SaveDir"/> | ||||
|     <addaction name="actionErase_ALL_TXT"/> | ||||
|     <addaction name="reset_fox_log_action"/> | ||||
|     <addaction name="actionErase_wsjtx_log_adi"/> | ||||
|     <addaction name="reset_cabrillo_log_action"/> | ||||
|     <addaction name="actionExport_Cabrillo_log"/> | ||||
|  | ||||
| @ -7,7 +7,8 @@ SOURCES += \ | ||||
|   widgets/echoplot.cpp widgets/echograph.cpp widgets/fastgraph.cpp \ | ||||
|   widgets/fastplot.cpp widgets/MessageBox.cpp \ | ||||
|   widgets/colorhighlighting.cpp widgets/ExportCabrillo.cpp \ | ||||
|   widgets/CabrilloLogWindow.cpp | ||||
|   widgets/AbstractLogWindow.cpp \ | ||||
|   widgets/FoxLogWindow.cpp widgets/CabrilloLogWindow.cpp | ||||
| 
 | ||||
| HEADERS  += \ | ||||
|   widgets/mainwindow.h widgets/plotter.h \ | ||||
| @ -17,8 +18,8 @@ HEADERS  += \ | ||||
|   widgets/meterwidget.h widgets/messageaveraging.h \ | ||||
|   widgets/echoplot.h widgets/echograph.h widgets/fastgraph.h \ | ||||
|   widgets/fastplot.h widgets/MessageBox.hpp widgets/colorhighlighting.h \ | ||||
|   widgets/ExportCabrillo.h \ | ||||
|   widgets/CabrilloLogWindow.cpp | ||||
|   widgets/ExportCabrillo.h widgets/AbstractLogWindow.hpp \ | ||||
|   widgets/FoxLogWindow.cpp widgets/CabrilloLogWindow.cpp | ||||
| 
 | ||||
| FORMS    += \ | ||||
|   widgets/mainwindow.ui widgets/about.ui \ | ||||
| @ -26,5 +27,4 @@ FORMS    += \ | ||||
|   widgets/logqso.ui widgets/messageaveraging.ui \ | ||||
|   widgets/echograph.ui widgets/fastgraph.ui \ | ||||
|   widgets/colorhighlighting.ui widgets/ExportCabrillo.ui \ | ||||
|   widgets/FoxLogWindow.ui \ | ||||
|   widgets/CabrilloLogWindow.ui | ||||
|   widgets/FoxLogWindow.ui widgets/CabrilloLogWindow.ui | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user