<commit_before>"""
This file is part of the Avast project.
Copyright 2016 David W. Hogg (NYU).
"""
import numpy as np

class OneDGaussianModel():

    def __init__(self, K, h, offset, baseline=0.):
        assert K > 1
        assert h > 0.
        self.K = K
        self.h = h
        self.means = np.arange(K) * h + offset
        self.var = (1.5 * h) ** 2 # well sampled
        self.offset = offset
        self.baseline = baseline
        self.amps = None

    def _OneDGaussians(self, xs):
        return self.amps[None,:] * np.exp(-0.5 * (xs[:,None] - self.means[None,:]) ** 2 / self.var)

    def _d_OneDGaussians_dx(self, xs):
        return self._OneDGaussians(xs) * (self.means[None, :] - xs[:,None]) / self.var

    def set_amplitudes(self, amps):
        assert amps.shape == (self.K, )
        self.amps = amps

    def evaluate(self, xs):
        N = len(xs)
        assert xs.shape == (N, )
        return np.sum(self._OneDGaussians(xs), axis=1) + self.baseline

    def evaluate_derivative(self, xs):
        N = len(xs)
        assert xs.shape == (N, )
        return np.sum(self._d_OneDGaussians_dx(xs), axis=1)

def make_fake_data():
    np.random.seed(17)
    N = 50 # number of spectra
    K = 1000  # number of control points
    h = 1. # spacing of control points (Ang)
    offset = 4500. # location of k=0 control point (Ang)
    c = 3.e8 # m / s
    truth = OneDGaussianModel(K, h, offset, 1.0)
    truth.set_amplitudes(-0.5 * np.random.uniform(size=K) ** 32.) # made up
    times = (np.random.uniform(size=N) - 0.5) * 1400. # four+ years
    rvs = 2.2 * np.sin(2. * np.pi * times / 55.81) # m / s
    waves = 1. * truth.means # copy
    data = np.zeros((N, len(waves)))
    for n in range(N):
        data[n, :] = truth.evaluate(waves) - (waves / c) * truth.evaluate_derivative(waves) * rvs[n]
    data += 0.01 * np.random.normal(size=data.shape) # s/n = 100
    return data, waves

if __name__ == "__main__":
    import pylab as plt

    data, waves = make_fake_data()
    N, M = data.shape
    plt.clf()
    n = 0
    plt.step(waves, data[n, :], color="k", where="mid")
    plt.xlabel("wavelength (Angstrom)")
    plt.ylabel("normalized flux")
    plt.savefig("data00.png")

if False:
    np.random.seed(42)

    K = 2 ** 10  # number of points
    h = 0.443 # spacing of points
    offset = 1.022 # location of k=0
    model = OneDGaussianModel(K, h, offset)
    model.set_amplitudes(np.random.normal(size=K))

    xs = np.arange(-5., 100., 0.01)
    plt.clf()
    plt.plot(xs, model.evaluate(xs), "k-")
    plt.plot(xs, model.evaluate_derivative(xs), "r-")
    plt.axhline(0., color="r", alpha=0.25)
    plt.savefig("test.png")

    model.set_amplitudes(np.ones(K))
    plt.clf()
    plt.plot(xs, model.evaluate(xs), "k-")
    plt.plot(xs, model.evaluate_derivative(xs), "r-")
    plt.axhline(0., color="r", alpha=0.25)
    plt.savefig("test2.png")

    model.set_amplitudes(-0.5 * np.random.uniform(size=K) ** 32.) # made up
    model.baseline = 1.
    plt.clf()
    plt.plot(xs, model.evaluate(xs), "k-")
    plt.plot(xs, model.evaluate_derivative(xs), "r-")
    plt.axhline(0., color="r", alpha=0.25)
    plt.savefig("test3.png")
<commit_msg>experiments<commit_after>"""
This file is part of the Avast project.
Copyright 2016 David W. Hogg (NYU).
"""
import numpy as np
c = 3.e8 # m / s

class OneDGaussianModel():

    def __init__(self, K, h, offset, baseline=0.):
        assert K > 1
        assert h > 0.
        self.K = K
        self.h = h
        self.means = np.arange(K) * h + offset
        self.var = (1.5 * h) ** 2 # well sampled
        self.offset = offset
        self.baseline = baseline
        self.amps = None

    def _OneDGaussians(self, xs):
        return self.amps[None,:] * np.exp(-0.5 * (xs[:,None] - self.means[None,:]) ** 2 / self.var)

    def _d_OneDGaussians_dx(self, xs):
        return self._OneDGaussians(xs) * (self.means[None, :] - xs[:,None]) / self.var

    def set_amplitudes(self, amps):
        assert amps.shape == (self.K, )
        self.amps = amps

    def evaluate(self, xs):
        N = len(xs)
        assert xs.shape == (N, )
        return np.sum(self._OneDGaussians(xs), axis=1) + self.baseline

    def evaluate_derivative(self, xs):
        N = len(xs)
        assert xs.shape == (N, )
        return np.sum(self._d_OneDGaussians_dx(xs), axis=1)

    def evaluate_at_redshift(self, xs, rv):
        restxs = redshift_wavelengths(xs, -rv)
        return self.evaluate(restxs)

    def evaluate_at_redshift_linearized(self, xs, rv):
        return self.evaluate(xs) - xs * self.evaluate_derivative(xs) * (rv / c)

def redshift_wavelengths(waves, v):
    beta = v / c
    return waves * np.sqrt((1. + beta) / (1. - beta))

def make_fake_data():
    np.random.seed(17)
    N = 50 # number of spectra
    K = 1000  # number of control points
    h = 1. # spacing of control points (Ang)
    offset = 4500. # location of k=0 control point (Ang)
    truth = OneDGaussianModel(K, h, offset, 1.0)
    truth.set_amplitudes(-0.5 * np.random.uniform(size=K) ** 32.) # made up
    times = (np.random.uniform(size=N) - 0.5) * 1400. # four+ years
    rvs = 2200. * np.sin(2. * np.pi * times / 55.81) # m / s
    waves = 1. * truth.means # copy
    data = np.zeros((N, len(waves)))
    for n in range(N):
        restwaves = redshift_wavelengths(waves, -rvs[n])
        data[n, :] = truth.evaluate(restwaves)
    data += 0.01 * np.random.normal(size=data.shape) # s/n = 100
    return data, waves

if __name__ == "__main__":
    import pylab as plt
    np.random.seed(42)

    K = 2 ** 10  # number of points
    h = 0.443 # spacing of points
    offset = 4999. # location of k=0
    model = OneDGaussianModel(K, h, offset)
    model.set_amplitudes(np.random.normal(size=K))

    xs = np.arange(5000, 5010., 0.01)
    plt.clf()
    plt.plot(xs, model.evaluate(xs), "k-")
    plt.plot(xs, model.evaluate_derivative(xs), "r-")
    plt.axhline(0., color="r", alpha=0.25)
    plt.savefig("test.png")

    model.set_amplitudes(np.ones(K))
    plt.clf()
    plt.plot(xs, model.evaluate(xs), "k-")
    plt.plot(xs, model.evaluate_derivative(xs), "r-")
    plt.axhline(0., color="r", alpha=0.25)
    plt.savefig("test2.png")

    model.set_amplitudes(-0.5 * np.random.uniform(size=K) ** 32.) # made up
    model.baseline = 1.
    plt.clf()
    plt.plot(xs, model.evaluate(xs), "k-")
    plt.plot(xs, model.evaluate_derivative(xs), "r-")
    delta = 0.01 * np.sqrt(model.var)
    numerical_derivative = (model.evaluate(xs + delta) - model.evaluate(xs)) / delta
    plt.plot(xs, numerical_derivative, "g--", alpha=0.5)
    plt.axhline(0., color="r", alpha=0.25)
    plt.savefig("test3.png")

    plt.clf()
    plt.plot(xs, model.evaluate(xs), "k-")
    rv = 1.e4 # m/s
    plt.plot(xs, model.evaluate_at_redshift(xs, rv), "r-")
    plt.plot(xs, model.evaluate_at_redshift_linearized(xs, rv), "g--", alpha=0.5)
    plt.savefig("test4.png")

if False:
    data, waves = make_fake_data()
    N, M = data.shape
    n = 0
    plt.clf()
    plt.step(waves, data[n, :], color="k", where="mid")
    plt.xlabel("wavelength (Angstrom)")
    plt.ylabel("normalized flux")
    plt.savefig("data00.png")

<|endoftext|>


<commit_before>import argparse
from sklearn import cross_validation
from sklearn.metrics import confusion_matrix

from similarity_utils import *
from readfacedatabases import *
import similarity

parser = argparse.ArgumentParser(description='digit recognition')
parser.add_argument('--relu', dest='relu',action='store_true', default=False,
                    help=("if true, trains the RBM or DBN with a rectified linear unit"))
parser.add_argument('--cv', dest='cv',action='store_true', default=False,
                    help=("if true, does cv"))
parser.add_argument('--testYaleMain', dest='testYaleMain',action='store_true', default=False,
                    help=("if true, tests the net with the Kanade databse"))
parser.add_argument('--diffsubjects', dest='diffsubjects',action='store_true', default=False,
                    help=("if true, trains a net with different test and train subjects"))
parser.add_argument('--emotionsdiff', dest='emotionsdiff',action='store_true', default=False,
                    help=("if true, trains a net to distinguish between emotions"))
parser.add_argument('--emotionsdiffsamesubj', dest='emotionsdiffsamesubj',action='store_true', default=False,
                    help=("if true, trains a net to distinguish between emotions where the pictures presented are the same people"))

args = parser.parse_args()

def similarityMain():
  trainData1, trainData2, testData1, testData2, similaritiesTrain, similaritiesTest =\
     splitDataMultiPIESubject(instanceToPairRatio=2)

  print "training with dataset of size ", len(trainData1)
  print len(trainData1)

  print "testing with dataset of size ", len(testData1)

  print "training with ", similaritiesTrain.sum(), "positive examples"
  print "training with ", len(similaritiesTrain) - similaritiesTrain.sum(), "negative examples"

  print "testing with ", similaritiesTest.sum(), "positive examples"
  print "testing with ", len(similaritiesTest) - similaritiesTest.sum(), "negative examples"
  print len(testData1)

  simNet = similarity.SimilarityNet(learningRate=0.001,
                                    maxMomentum=0.95,
                                    binary=True,
                                    rbmNrVis=1200,
                                    rbmNrHid=1000,
                                    rbmLearningRate=0.005,
                                    rbmDropoutHid=1.0,
                                    rbmDropoutVis=1.0,
                                    trainingEpochsRBM=10)

  simNet.train(trainData1, trainData2, similaritiesTrain, epochs=1000)

  res = simNet.test(testData1, testData2)

  # Try to change this threshold?
  predicted = res > 0.5

  correct = (similaritiesTest == predicted).sum() * 1.0 / len(res)

  # print res
  for r in res:
    print r

  confMatrix = confusion_matrix(predicted, similaritiesTest)
  print confMatrix

  print "correct"
  print correct

def similarityMainTestYale():
  subjectsToImgs = readMultiPIESubjects()

  trainData1, trainData2, trainSubjects1, trainSubjects2 =\
    splitDataAccordingToLabels(subjectsToImgs, None, imgsPerSubject=None)

  similaritiesTrain =  similarityDifferentSubjects(trainSubjects1, trainSubjects2)

  testData1, testData2, similaritiesTest = splitSimilarityYale()

  print "training with dataset of size ", len(trainData1)
  print len(trainData1)

  print "testing with dataset of size ", len(testData1)
  print len(testData1)

  print "training with ", similaritiesTrain.sum(), "positive examples"
  print "training with ", len(similaritiesTrain) - similaritiesTrain.sum(), "negative examples"

  print "testing with ", similaritiesTest.sum(), "positive examples"
  print "testing with ", len(similaritiesTest) - similaritiesTest.sum(), "negative examples"

  simNet = similarity.SimilarityNet(learningRate=0.001,
                                    maxMomentum=0.95,
                                    binary=True,
                                    rbmNrVis=1200,
                                    rbmNrHid=1000,
                                    rbmLearningRate=0.005,
                                    rbmDropoutHid=1.0,
                                    rbmDropoutVis=1.0,
                                    trainingEpochsRBM=10)

  simNet.train(trainData1, trainData2, similaritiesTrain)

  res = simNet.test(testData1, testData2)

  predicted = res > 0.5

  correct = (similaritiesTest == predicted).sum() * 1.0 / len(res)

  print res

  confMatrix = confusion_matrix(predicted, similaritiesTest)
  print confMatrix

  print correct

def similarityDifferentSubjectsMain():
  nrSubjects = 147
  subjects = np.array(range(nrSubjects))
  kf = cross_validation.KFold(n=len(subjects), n_folds=5)

  for train, test in kf:
    break

  subjectsToImgs = readMultiPIESubjects()

  subjectTrain = subjects[train]
  subjectTest = subjects[test]

  print "len(subjectTrain)"
  print len(subjectTrain)
  print "len(subjectTest)"
  print len(subjectTest)

  trainData1, trainData2, trainSubjects1, trainSubjects2 =\
    splitDataAccordingToLabels(subjectsToImgs, subjectTrain, imgsPerSubject=None)

  testData1, testData2, testSubjects1, testSubjects2 =\
    splitDataAccordingToLabels(subjectsToImgs, subjectTest, imgsPerSubject=None)

  print "training with dataset of size ", len(trainData1)
  print "testing with dataset of size ", len(testData1)

  similaritiesTrain =  similarityDifferentSubjects(trainSubjects1, trainSubjects2)
  similaritiesTest =  similarityDifferentSubjects(testSubjects1, testSubjects2)

  print "training with ", similaritiesTrain.sum(), "positive examples"
  print "training with ", len(similaritiesTrain) - similaritiesTrain.sum(), "negative examples"

  print "testing with ", similaritiesTest.sum(), "positive examples"
  print "testing with ", len(similaritiesTest) - similaritiesTest.sum(), "negative examples"

  simNet = similarity.SimilarityNet(learningRate=0.001,
                                    maxMomentum=0.95,
                                    binary=True,
                                    rbmNrVis=1200,
                                    rbmNrHid=1000,
                                    rbmLearningRate=0.005,
                                    rbmDropoutHid=1.0,
                                    rbmDropoutVis=1.0,
                                    trainingEpochsRBM=10)

  simNet.train(trainData1, trainData2, similaritiesTrain)

  res = simNet.test(testData1, testData2)

  predicted = res > 0.5

  correct = (similaritiesTest == predicted).sum() * 1.0 / len(res)

  print res

  confMatrix = confusion_matrix(predicted, similaritiesTest)
  print confMatrix

  print correct

def similarityCV():
  trainData1, trainData2, testData1, testData2, similaritiesTrain, similaritiesTest =\
     splitDataMultiPIESubject(instanceToPairRatio=2)

  params = [(0.0001, 0.01), (0.0001, 0.005), (0.001, 0.01), (0.001, 0.005)]
  kf = cross_validation.KFold(n=len(trainData1), n_folds=len(params))

  fold = 0
  for train, test in kf:
    simNet = similarity.SimilarityNet(learningRate=params[fold][0],
                                    maxMomentum=0.95,
                                    binary=True,
                                    rbmNrVis=1200,
                                    rbmNrHid=1000,
                                    rbmLearningRate=params[fold][1],
                                    rbmDropoutHid=1.0,
                                    rbmDropoutVis=1.0,
                                    trainingEpochsRBM=1)

    simNet.train(trainData1, trainData2, similaritiesTrain)

    print "training with ", similaritiesTrain.sum(), "positive examples"
    print "training with ", len(similaritiesTrain) - similaritiesTrain.sum(), "negative examples"

    print "testing with ", similaritiesTest.sum(), "positive examples"
    print "testing with ", len(similaritiesTest) - similaritiesTest.sum(), "negative examples"

    res = simNet.test(testData1, testData2)

    # error = (similaritiesTest - res)  * 1.0 / len(res)

    predicted = res > 0.5

    print "predicted"
    print predicted

    correct = (similaritiesTest == predicted).sum() * 1.0 / len(res)

    print "params[fold]"
    print params[fold]
    print "res"
    print res
    print "correct"
    print correct

    fold += 1

def similarityEmotionsMain():
  trainData1, trainData2, trainLabels, testData1, testData2, testLabels =\
       splitSimilaritiesPIEEmotions(instanceToPairRatio=2)

  print "training with dataset of size ", len(trainData1)
  print len(trainData1)

  print "testing with dataset of size ", len(testData1)
  print len(testData1)

  # for k in testLabels:
  #   print k

  # for k in trainLabels:
  #   print k

  simNet = similarity.SimilarityNet(learningRate=0.001,
                                    maxMomentum=0.95,
                                    binary=True,
                                    rbmNrVis=1200,
                                    rbmNrHid=1000,
                                    rbmLearningRate=0.005,
                                    rbmDropoutHid=1.0,
                                    rbmDropoutVis=1.0,
                                    trainingEpochsRBM=10)

  print "training with ", trainLabels.sum(), "positive examples"
  print "training with ", len(trainLabels) - trainLabels.sum(), "negative examples"

  print "testing with ", testLabels.sum(), "positive examples"
  print "testing with ", len(testLabels) - testLabels.sum(), "negative examples"

  for i in xrange(len(trainData1)):
      # Create 1 by 1 image
      res = np.hstack([trainData1[i].reshape(40,30), trainData2[i].reshape(40,30)])
      plt.imshow(res, cmap=plt.cm.gray)
      plt.axis('off')
      plt.show()

  simNet.train(trainData1, trainData2, trainLabels, epochs=400)

  res = simNet.test(testData1, testData2)

  predicted = res > 0.5

  correct = (testLabels == predicted).sum() * 1.0 / len(res)

  print res

  confMatrix = confusion_matrix(predicted, testLabels)
  print confMatrix

  print correct

def similarityEmotionsSameSubject():
  trainData1, trainData2, trainLabels, testData1, testData2, testLabels =\
       splitEmotionsMultiPieKeepSubjects(instanceToPairRatio=2)

  print "training with dataset of size ", len(trainData1)
  print len(trainData1)

  print "testing with dataset of size ", len(testData1)
  print len(testData1)

  simNet = similarity.SimilarityNet(learningRate=0.001,
                                    maxMomentum=0.95,
                                    binary=True,
                                    rbmNrVis=1200,
                                    rbmNrHid=1000,
                                    rbmLearningRate=0.005,
                                    rbmDropoutHid=1.0,
                                    rbmDropoutVis=1.0,
                                    trainingEpochsRBM=10)

  print "training with ", trainLabels.sum(), "positive examples"
  print "training with ", len(trainLabels) - trainLabels.sum(), "negative examples"

  print "testing with ", testLabels.sum(), "positive examples"
  print "testing with ", len(testLabels) - testLabels.sum(), "negative examples"

  simNet.train(trainData1, trainData2, trainLabels, epochs=400)

  res = simNet.test(testData1, testData2)

  predicted = res > 0.5

  correct = (testLabels == predicted).sum() * 1.0 / len(res)

  print res

  confMatrix = confusion_matrix(predicted, testLabels)
  print confMatrix

  print correct

def main():
  if args.cv:
    similarityCV()
  if args.diffsubjects:
    similarityDifferentSubjectsMain()
  if args.testYaleMain:
    similarityMainTestYale()
  if args.emotionsdiff:
    similarityEmotionsMain()
  if args.emotionsdiffsamesubj:
    similarityEmotionsSameSubject()
  else:

    similarityMain()

if __name__ == '__main__':
  main()
<commit_msg>print<commit_after>import argparse
from sklearn import cross_validation
from sklearn.metrics import confusion_matrix

from similarity_utils import *
from readfacedatabases import *
import similarity

parser = argparse.ArgumentParser(description='digit recognition')
parser.add_argument('--relu', dest='relu',action='store_true', default=False,
                    help=("if true, trains the RBM or DBN with a rectified linear unit"))
parser.add_argument('--cv', dest='cv',action='store_true', default=False,
                    help=("if true, does cv"))
parser.add_argument('--testYaleMain', dest='testYaleMain',action='store_true', default=False,
                    help=("if true, tests the net with the Kanade databse"))
parser.add_argument('--diffsubjects', dest='diffsubjects',action='store_true', default=False,
                    help=("if true, trains a net with different test and train subjects"))
parser.add_argument('--emotionsdiff', dest='emotionsdiff',action='store_true', default=False,
                    help=("if true, trains a net to distinguish between emotions"))
parser.add_argument('--emotionsdiffsamesubj', dest='emotionsdiffsamesubj',action='store_true', default=False,
                    help=("if true, trains a net to distinguish between emotions where the pictures presented are the same people"))

args = parser.parse_args()

def similarityMain():
  trainData1, trainData2, testData1, testData2, similaritiesTrain, similaritiesTest =\
     splitDataMultiPIESubject(instanceToPairRatio=2)

  print "training with dataset of size ", len(trainData1)
  print len(trainData1)

  print "testing with dataset of size ", len(testData1)

  print "training with ", similaritiesTrain.sum(), "positive examples"
  print "training with ", len(similaritiesTrain) - similaritiesTrain.sum(), "negative examples"

  print "testing with ", similaritiesTest.sum(), "positive examples"
  print "testing with ", len(similaritiesTest) - similaritiesTest.sum(), "negative examples"
  print len(testData1)

  simNet = similarity.SimilarityNet(learningRate=0.001,
                                    maxMomentum=0.95,
                                    binary=True,
                                    rbmNrVis=1200,
                                    rbmNrHid=1000,
                                    rbmLearningRate=0.005,
                                    rbmDropoutHid=1.0,
                                    rbmDropoutVis=1.0,
                                    trainingEpochsRBM=10)

  simNet.train(trainData1, trainData2, similaritiesTrain, epochs=1000)

  res = simNet.test(testData1, testData2)

  # Try to change this threshold?
  predicted = res > 0.5

  correct = (similaritiesTest == predicted).sum() * 1.0 / len(res)

  # print res
  for r in res:
    print r

  confMatrix = confusion_matrix(predicted, similaritiesTest)
  print confMatrix

  print "correct"
  print correct

def similarityMainTestYale():
  subjectsToImgs = readMultiPIESubjects()

  trainData1, trainData2, trainSubjects1, trainSubjects2 =\
    splitDataAccordingToLabels(subjectsToImgs, None, imgsPerSubject=None)

  similaritiesTrain =  similarityDifferentSubjects(trainSubjects1, trainSubjects2)

  testData1, testData2, similaritiesTest = splitSimilarityYale()

  print "training with dataset of size ", len(trainData1)
  print len(trainData1)

  print "testing with dataset of size ", len(testData1)
  print len(testData1)

  print "training with ", similaritiesTrain.sum(), "positive examples"
  print "training with ", len(similaritiesTrain) - similaritiesTrain.sum(), "negative examples"

  print "testing with ", similaritiesTest.sum(), "positive examples"
  print "testing with ", len(similaritiesTest) - similaritiesTest.sum(), "negative examples"

  simNet = similarity.SimilarityNet(learningRate=0.001,
                                    maxMomentum=0.95,
                                    binary=True,
                                    rbmNrVis=1200,
                                    rbmNrHid=1000,
                                    rbmLearningRate=0.005,
                                    rbmDropoutHid=1.0,
                                    rbmDropoutVis=1.0,
                                    trainingEpochsRBM=10)

  simNet.train(trainData1, trainData2, similaritiesTrain)

  res = simNet.test(testData1, testData2)

  predicted = res > 0.5

  correct = (similaritiesTest == predicted).sum() * 1.0 / len(res)

  print res

  confMatrix = confusion_matrix(predicted, similaritiesTest)
  print confMatrix

  print correct

def similarityDifferentSubjectsMain():
  nrSubjects = 147
  subjects = np.array(range(nrSubjects))
  kf = cross_validation.KFold(n=len(subjects), n_folds=5)

  for train, test in kf:
    break

  subjectsToImgs = readMultiPIESubjects()

  subjectTrain = subjects[train]
  subjectTest = subjects[test]

  print "len(subjectTrain)"
  print len(subjectTrain)
  print "len(subjectTest)"
  print len(subjectTest)

  trainData1, trainData2, trainSubjects1, trainSubjects2 =\
    splitDataAccordingToLabels(subjectsToImgs, subjectTrain, imgsPerSubject=None)

  testData1, testData2, testSubjects1, testSubjects2 =\
    splitDataAccordingToLabels(subjectsToImgs, subjectTest, imgsPerSubject=None)

  print "training with dataset of size ", len(trainData1)
  print "testing with dataset of size ", len(testData1)

  similaritiesTrain =  similarityDifferentSubjects(trainSubjects1, trainSubjects2)
  similaritiesTest =  similarityDifferentSubjects(testSubjects1, testSubjects2)

  print "training with ", similaritiesTrain.sum(), "positive examples"
  print "training with ", len(similaritiesTrain) - similaritiesTrain.sum(), "negative examples"

  print "testing with ", similaritiesTest.sum(), "positive examples"
  print "testing with ", len(similaritiesTest) - similaritiesTest.sum(), "negative examples"

  simNet = similarity.SimilarityNet(learningRate=0.001,
                                    maxMomentum=0.95,
                                    binary=True,
                                    rbmNrVis=1200,
                                    rbmNrHid=1000,
                                    rbmLearningRate=0.005,
                                    rbmDropoutHid=1.0,
                                    rbmDropoutVis=1.0,
                                    trainingEpochsRBM=10)

  simNet.train(trainData1, trainData2, similaritiesTrain)

  res = simNet.test(testData1, testData2)

  predicted = res > 0.5

  correct = (similaritiesTest == predicted).sum() * 1.0 / len(res)

  print res

  confMatrix = confusion_matrix(predicted, similaritiesTest)
  print confMatrix

  print correct

def similarityCV():
  trainData1, trainData2, testData1, testData2, similaritiesTrain, similaritiesTest =\
     splitDataMultiPIESubject(instanceToPairRatio=2)

  params = [(0.0001, 0.01), (0.0001, 0.005), (0.001, 0.01), (0.001, 0.005)]
  kf = cross_validation.KFold(n=len(trainData1), n_folds=len(params))

  fold = 0
  for train, test in kf:
    simNet = similarity.SimilarityNet(learningRate=params[fold][0],
                                    maxMomentum=0.95,
                                    binary=True,
                                    rbmNrVis=1200,
                                    rbmNrHid=1000,
                                    rbmLearningRate=params[fold][1],
                                    rbmDropoutHid=1.0,
                                    rbmDropoutVis=1.0,
                                    trainingEpochsRBM=1)

    simNet.train(trainData1, trainData2, similaritiesTrain)

    print "training with ", similaritiesTrain.sum(), "positive examples"
    print "training with ", len(similaritiesTrain) - similaritiesTrain.sum(), "negative examples"

    print "testing with ", similaritiesTest.sum(), "positive examples"
    print "testing with ", len(similaritiesTest) - similaritiesTest.sum(), "negative examples"

    res = simNet.test(testData1, testData2)

    # error = (similaritiesTest - res)  * 1.0 / len(res)

    predicted = res > 0.5

    print "predicted"
    print predicted

    correct = (similaritiesTest == predicted).sum() * 1.0 / len(res)

    print "params[fold]"
    print params[fold]
    print "res"
    print res
    print "correct"
    print correct

    fold += 1

def similarityEmotionsMain():
  trainData1, trainData2, trainLabels, testData1, testData2, testLabels =\
       splitSimilaritiesPIEEmotions(instanceToPairRatio=2)

  print "training with dataset of size ", len(trainData1)
  print len(trainData1)

  print "testing with dataset of size ", len(testData1)
  print len(testData1)

  # for k in testLabels:
  #   print k

  # for k in trainLabels:
  #   print k

  simNet = similarity.SimilarityNet(learningRate=0.001,
                                    maxMomentum=0.95,
                                    binary=True,
                                    rbmNrVis=1200,
                                    rbmNrHid=1000,
                                    rbmLearningRate=0.005,
                                    rbmDropoutHid=1.0,
                                    rbmDropoutVis=1.0,
                                    trainingEpochsRBM=10)

  print "training with ", trainLabels.sum(), "positive examples"
  print "training with ", len(trainLabels) - trainLabels.sum(), "negative examples"

  print "testing with ", testLabels.sum(), "positive examples"
  print "testing with ", len(testLabels) - testLabels.sum(), "negative examples"

  for i in xrange(len(trainData1)):
      # Create 1 by 1 image
      res = np.hstack([trainData1[i].reshape(40,30), trainData2[i].reshape(40,30)])
      plt.imshow(res, cmap=plt.cm.gray)
      plt.axis('off')
      plt.show()

      print trainLabels[i]

  simNet.train(trainData1, trainData2, trainLabels, epochs=400)

  res = simNet.test(testData1, testData2)

  predicted = res > 0.5

  correct = (testLabels == predicted).sum() * 1.0 / len(res)

  print res

  confMatrix = confusion_matrix(predicted, testLabels)
  print confMatrix

  print correct

def similarityEmotionsSameSubject():
  trainData1, trainData2, trainLabels, testData1, testData2, testLabels =\
       splitEmotionsMultiPieKeepSubjects(instanceToPairRatio=2)

  print "training with dataset of size ", len(trainData1)
  print len(trainData1)

  print "testing with dataset of size ", len(testData1)
  print len(testData1)

  simNet = similarity.SimilarityNet(learningRate=0.001,
                                    maxMomentum=0.95,
                                    binary=True,
                                    rbmNrVis=1200,
                                    rbmNrHid=1000,
                                    rbmLearningRate=0.005,
                                    rbmDropoutHid=1.0,
                                    rbmDropoutVis=1.0,
                                    trainingEpochsRBM=10)

  print "training with ", trainLabels.sum(), "positive examples"
  print "training with ", len(trainLabels) - trainLabels.sum(), "negative examples"

  print "testing with ", testLabels.sum(), "positive examples"
  print "testing with ", len(testLabels) - testLabels.sum(), "negative examples"

  simNet.train(trainData1, trainData2, trainLabels, epochs=400)

  res = simNet.test(testData1, testData2)

  predicted = res > 0.5

  correct = (testLabels == predicted).sum() * 1.0 / len(res)

  print res

  confMatrix = confusion_matrix(predicted, testLabels)
  print confMatrix

  print correct

def main():
  if args.cv:
    similarityCV()
  if args.diffsubjects:
    similarityDifferentSubjectsMain()
  if args.testYaleMain:
    similarityMainTestYale()
  if args.emotionsdiff:
    similarityEmotionsMain()
  if args.emotionsdiffsamesubj:
    similarityEmotionsSameSubject()
  else:

    similarityMain()

if __name__ == '__main__':
  main()
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
####################################################
##                                                ##
##           Image Occlusion Enhanced             ##
##                                                ##
##      Copyright (c) Glutanimate 2016-2017       ##
##       (https://github.com/Glutanimate)         ##
##                                                ##
##         Based on Image Occlusion 2.0           ##
##         Copyright (c) 2012-2015 tmbb           ##
##           (https://github.com/tmbb)            ##
##                                                ##
####################################################

"""
Image Occlusion editor dialog
"""

import os

from aqt.qt import *

from aqt import mw, webview, deckchooser, tagedit, sip
from aqt.utils import saveGeom, restoreGeom
from anki.hooks import addHook, remHook

from .dialogs import ioHelp
from .consts import *
from .config import *

class ImgOccWebPage(webview.AnkiWebPage):
    def acceptNavigationRequest(self, url, navType, isMainFrame):
        return True

class ImgOccWebView(webview.AnkiWebView):
    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self._domDone = False

    def _onBridgeCmd(self, cmd):
        # ignore webchannel messages that arrive after underlying webview
        # deleted
        if sip.isdeleted(self):
            return

        if cmd == "domDone":
            return

        if cmd == "svgEditDone":
            self._domDone = True
            self._maybeRunActions()
        else:
            return self.onBridgeCmd(cmd)

    def runOnLoaded(self, callback):
        self._domDone = False
        self._queueAction("callback", callback)

    def _maybeRunActions(self):
        while self._pendingActions and self._domDone:
            name, args = self._pendingActions.pop(0)

            if name == "eval":
                self._evalWithCallback(*args)
            elif name == "setHtml":
                self._setHtml(*args)
            elif name == "callback":
                callback = args[0]
                callback()
            else:
                raise Exception("unknown action: {}".format(name))

class ImgOccEdit(QDialog):
    """Main Image Occlusion Editor dialog"""

    def __init__(self, imgoccadd, parent):
        QDialog.__init__(self, parent=parent)
        mw.setupDialogGC(self)
        self.setWindowFlags(Qt.Window)
        self.visible = False
        self.imgoccadd = imgoccadd
        self.parent = parent
        self.mode = "add"
        loadConfig(self)
        self.setupUi()
        restoreGeom(self, "imgoccedit")
        addHook("unloadProfile", self.onProfileUnload)

    def closeEvent(self, event):
        if mw.pm.profile is not None:
            self.deckChooser.cleanup()
            saveGeom(self, "imgoccedit")
        self.visible = False
        self.svg_edit = None
        del(self.svg_edit_anim)  # might not be gc'd
        remHook("unloadProfile", self.onProfileUnload)
        QDialog.reject(self)

    def onProfileUnload(self):
        if not sip.isdeleted(self):
            self.close()

    def reject(self):
        # Override QDialog Esc key reject
        pass

    def setupUi(self):
        """Set up ImgOccEdit UI"""
        # Main widgets aside from fields
        self.svg_edit = ImgOccWebView(parent=self)
        self.svg_edit._page = ImgOccWebPage(self.svg_edit._onBridgeCmd)
        self.svg_edit.setPage(self.svg_edit._page)

        self.tags_hbox = QHBoxLayout()
        self.tags_edit = tagedit.TagEdit(self)
        self.tags_label = QLabel("Tags")
        self.tags_label.setFixedWidth(70)
        self.deck_container = QWidget()
        self.deckChooser = deckchooser.DeckChooser(mw,
                                                   self.deck_container, label=True)
        self.deckChooser.deck.setAutoDefault(False)

        # workaround for tab focus order issue of the tags entry
        # (this particular section is only needed when the quick deck
        # buttons add-on is installed)
        if self.deck_container.layout().children():  # multiple deck buttons
            for i in range(self.deck_container.layout().children()[0].count()):
                try:
                    item = self.deck_container.layout().children()[0].itemAt(i)
                    # remove Tab focus manually:
                    item.widget().setFocusPolicy(Qt.ClickFocus)
                    item.widget().setAutoDefault(False)
                except AttributeError:
                    pass

        # Button row widgets
        self.bottom_label = QLabel()
        button_box = QDialogButtonBox(Qt.Horizontal, self)
        button_box.setCenterButtons(False)

        image_btn = QPushButton("Change &Image", clicked=self.changeImage)
        image_btn.setIcon(QIcon(os.path.join(ICONS_PATH, "add.png")))
        image_btn.setIconSize(QSize(16, 16))
        image_btn.setAutoDefault(False)
        help_btn = QPushButton("&Help", clicked=self.onHelp)
        help_btn.setAutoDefault(False)

        self.occl_tp_select = QComboBox()
        self.occl_tp_select.addItems(["Don't Change", "Hide All, Guess One",
                                      "Hide One, Guess One"])

        self.edit_btn = button_box.addButton("&Edit Cards",
                                             QDialogButtonBox.ActionRole)
        self.new_btn = button_box.addButton("&Add New Cards",
                                            QDialogButtonBox.ActionRole)
        self.ao_btn = button_box.addButton("Hide &All, Guess One",
                                           QDialogButtonBox.ActionRole)
        self.oa_btn = button_box.addButton("Hide &One, Guess One",
                                           QDialogButtonBox.ActionRole)
        close_button = button_box.addButton("&Close",
                                            QDialogButtonBox.RejectRole)

        image_tt = ("Switch to a different image while preserving all of "
                    "the shapes and fields")
        dc_tt = "Preserve existing occlusion type"
        edit_tt = "Edit all cards using current mask shapes and field entries"
        new_tt = "Create new batch of cards without editing existing ones"
        ao_tt = ("Generate cards with nonoverlapping information, where all
"
                 "labels are hidden on the front and one revealed on the back")
        oa_tt = ("Generate cards with overlapping information, where one
"
                 "label is hidden on the front and revealed on the back")
        close_tt = "Close Image Occlusion Editor without generating cards"

        image_btn.setToolTip(image_tt)
        self.edit_btn.setToolTip(edit_tt)
        self.new_btn.setToolTip(new_tt)
        self.ao_btn.setToolTip(ao_tt)
        self.oa_btn.setToolTip(oa_tt)
        close_button.setToolTip(close_tt)
        self.occl_tp_select.setItemData(0, dc_tt, Qt.ToolTipRole)
        self.occl_tp_select.setItemData(1, ao_tt, Qt.ToolTipRole)
        self.occl_tp_select.setItemData(2, oa_tt, Qt.ToolTipRole)

        for btn in [image_btn, self.edit_btn, self.new_btn, self.ao_btn,
                    self.oa_btn, close_button]:
            btn.setFocusPolicy(Qt.ClickFocus)

        self.edit_btn.clicked.connect(self.editNote)
        self.new_btn.clicked.connect(self.new)
        self.ao_btn.clicked.connect(self.addAO)
        self.oa_btn.clicked.connect(self.addOA)
        close_button.clicked.connect(self.close)

        # Set basic layout up

        # Button row
        bottom_hbox = QHBoxLayout()
        bottom_hbox.addWidget(image_btn)
        bottom_hbox.addWidget(help_btn)
        bottom_hbox.insertStretch(2, stretch=1)
        bottom_hbox.addWidget(self.bottom_label)
        bottom_hbox.addWidget(self.occl_tp_select)
        bottom_hbox.addWidget(button_box)

        # Tab 1
        vbox1 = QVBoxLayout()

        svg_edit_loader = QLabel("Loading...")
        svg_edit_loader.setAlignment(Qt.AlignCenter)
        loader_icon = os.path.join(ICONS_PATH, "loader.gif")
        anim = QMovie(loader_icon)
        svg_edit_loader.setMovie(anim)
        anim.start()
        self.svg_edit_loader = svg_edit_loader
        self.svg_edit_anim = anim

        vbox1.addWidget(self.svg_edit, stretch=1)
        vbox1.addWidget(self.svg_edit_loader, stretch=1)

        # Tab 2
        # vbox2 fields are variable and added by setupFields() at a later point
        self.vbox2 = QVBoxLayout()

        # Main Tab Widget
        tab1 = QWidget()
        self.tab2 = QWidget()
        tab1.setLayout(vbox1)
        self.tab2.setLayout(self.vbox2)
        self.tab_widget = QTabWidget()
        self.tab_widget.setFocusPolicy(Qt.ClickFocus)
        self.tab_widget.addTab(tab1, "&Masks Editor")
        self.tab_widget.addTab(self.tab2, "&Fields")
        self.tab_widget.setTabToolTip(
            1, "Include additional information (optional)")
        self.tab_widget.setTabToolTip(
            0, "Create image occlusion masks (required)")

        # Main Window
        vbox_main = QVBoxLayout()
        vbox_main.addWidget(self.tab_widget)
        vbox_main.addLayout(bottom_hbox)
        self.setLayout(vbox_main)
        self.setMinimumWidth(640)
        self.tab_widget.setCurrentIndex(0)
        self.svg_edit.setFocus()
        self.showSvgEdit(False)

        # Define and connect key bindings

        # Field focus hotkeys
        for i in range(1, 10):
            QShortcut(QKeySequence("Ctrl+%i" % i),
                      self).activated.connect(lambda f=i-1: self.focusField(f))
        # Other hotkeys
        QShortcut(QKeySequence("Ctrl+Return"),
                  self).activated.connect(lambda: self.defaultAction(True))
        QShortcut(QKeySequence("Ctrl+Shift+Return"),
                  self).activated.connect(lambda: self.addOA(True))
        QShortcut(QKeySequence("Ctrl+Tab"),
                  self).activated.connect(self.switchTabs)
        QShortcut(QKeySequence("Ctrl+r"),
                  self).activated.connect(self.resetMainFields)
        QShortcut(QKeySequence("Ctrl+Shift+r"),
                  self).activated.connect(self.resetAllFields)
        QShortcut(QKeySequence("Ctrl+Shift+t"),
                  self).activated.connect(self.focusTags)
        QShortcut(QKeySequence("Ctrl+f"),
                  self).activated.connect(self.fitImageCanvas)

    # Various actions that act on / interact with the ImgOccEdit UI:

    # Note actions

    def changeImage(self):
        self.imgoccadd.onChangeImage()
        self.fitImageCanvas()

    def defaultAction(self, close):
        if self.mode == "add":
            self.addAO(close)
        else:
            self.editNote()

    def addAO(self, close=False):
        self.imgoccadd.onAddNotesButton("ao", close)

    def addOA(self, close=False):
        self.imgoccadd.onAddNotesButton("oa", close)

    def new(self, close=False):
        choice = self.occl_tp_select.currentText()
        self.imgoccadd.onAddNotesButton(choice, close)

    def editNote(self):
        choice = self.occl_tp_select.currentText()
        self.imgoccadd.onEditNotesButton(choice)

    def onHelp(self):
        if self.mode == "add":
            ioHelp("add", parent=self)
        else:
            ioHelp("edit", parent=self)

    # Window state

    def resetFields(self):
        """Reset all widgets. Needed for changes to the note type"""
        layout = self.vbox2
        for i in reversed(list(range(layout.count()))):
            item = layout.takeAt(i)
            layout.removeItem(item)
            if item.widget():
                item.widget().setParent(None)
            elif item.layout():
                sublayout = item.layout()
                sublayout.setParent(None)
                for i in reversed(list(range(sublayout.count()))):
                    subitem = sublayout.takeAt(i)
                    sublayout.removeItem(subitem)
                    subitem.widget().setParent(None)
        self.tags_hbox.setParent(None)

    def setupFields(self, flds):
        """Setup dialog text edits based on note type fields"""
        self.tedit = {}
        self.tlabel = {}
        self.flds = flds
        for i in flds:
            if i['name'] in self.ioflds_priv:
                continue
            hbox = QHBoxLayout()
            tedit = QPlainTextEdit()
            label = QLabel(i["name"])
            hbox.addWidget(label)
            hbox.addWidget(tedit)
            tedit.setTabChangesFocus(True)
            tedit.setMinimumHeight(40)
            label.setFixedWidth(70)
            self.tedit[i["name"]] = tedit
            self.tlabel[i["name"]] = label
            self.vbox2.addLayout(hbox)

        self.tags_hbox.addWidget(self.tags_label)
        self.tags_hbox.addWidget(self.tags_edit)
        self.vbox2.addLayout(self.tags_hbox)
        self.vbox2.addWidget(self.deck_container)
        # switch Tab focus order of deckchooser and tags_edit (
        # for some reason it's the wrong way around by default):
        self.tab2.setTabOrder(self.tags_edit, self.deckChooser.deck)

    def switchToMode(self, mode):
        """Toggle between add and edit layouts"""
        hide_on_add = [self.occl_tp_select, self.edit_btn, self.new_btn]
        hide_on_edit = [self.ao_btn, self.oa_btn]
        self.mode = mode
        for i in list(self.tedit.values()):
            i.show()
        for i in list(self.tlabel.values()):
            i.show()
        if mode == "add":
            for i in hide_on_add:
                i.hide()
            for i in hide_on_edit:
                i.show()
            dl_txt = "Deck"
            ttl = "Image Occlusion Enhanced - Add Mode"
            bl_txt = "Add Cards:"
        else:
            for i in hide_on_add:
                i.show()
            for i in hide_on_edit:
                i.hide()
            for i in self.sconf['skip']:
                if i in list(self.tedit.keys()):
                    self.tedit[i].hide()
                    self.tlabel[i].hide()
            dl_txt = "Deck for Add new cards"
            ttl = "Image Occlusion Enhanced - Editing Mode"
            bl_txt = "Type:"
        self.deckChooser.deckLabel.setText(dl_txt)
        self.setWindowTitle(ttl)
        self.bottom_label.setText(bl_txt)

    def showSvgEdit(self, state):
        if not state:
            self.svg_edit.hide()
            self.svg_edit_anim.start()
            self.svg_edit_loader.show()
        else:
            self.svg_edit_anim.stop()
            self.svg_edit_loader.hide()
            self.svg_edit.show()

    # Other actions

    def switchTabs(self):
        currentTab = self.tab_widget.currentIndex()
        if currentTab == 0:
            self.tab_widget.setCurrentIndex(1)
            if isinstance(QApplication.focusWidget(), QPushButton):
                self.tedit[self.ioflds["hd"]].setFocus()
        else:
            self.tab_widget.setCurrentIndex(0)

    def focusField(self, idx):
        """Focus field in vbox2 layout by index number"""
        self.tab_widget.setCurrentIndex(1)
        target_item = self.vbox2.itemAt(idx)
        if not target_item:
            return
        target_layout = target_item.layout()
        target_widget = target_item.widget()
        if target_layout:
            target = target_layout.itemAt(1).widget()
        elif target_widget:
            target = target_widget
        target.setFocus()

    def focusTags(self):
        self.tab_widget.setCurrentIndex(1)
        self.tags_edit.setFocus()

    def resetMainFields(self):
        """Reset all fields aside from sticky ones"""
        for i in self.flds:
            fn = i['name']
            if fn in self.ioflds_priv or fn in self.ioflds_prsv:
                continue
            self.tedit[fn].setPlainText("")

    def resetAllFields(self):
        """Reset all fields"""
        self.resetMainFields()
        for i in self.ioflds_prsv:
            self.tedit[i].setPlainText("")

    def fitImageCanvas(self):
        self.svg_edit.eval("""
                           setTimeout(function(){
                               svgCanvas.zoomChanged('', 'canvas');
                           }, 5)
                           """)
<commit_msg>Don't assign parent to ImgOccEdit instances<commit_after># -*- coding: utf-8 -*-
####################################################
##                                                ##
##           Image Occlusion Enhanced             ##
##                                                ##
##      Copyright (c) Glutanimate 2016-2017       ##
##       (https://github.com/Glutanimate)         ##
##                                                ##
##         Based on Image Occlusion 2.0           ##
##         Copyright (c) 2012-2015 tmbb           ##
##           (https://github.com/tmbb)            ##
##                                                ##
####################################################

"""
Image Occlusion editor dialog
"""

import os

from aqt.qt import *

from aqt import mw, webview, deckchooser, tagedit, sip
from aqt.utils import saveGeom, restoreGeom
from anki.hooks import addHook, remHook

from .dialogs import ioHelp
from .consts import *
from .config import *

class ImgOccWebPage(webview.AnkiWebPage):
    def acceptNavigationRequest(self, url, navType, isMainFrame):
        return True

class ImgOccWebView(webview.AnkiWebView):
    def __init__(self, parent=None):
        super().__init__(parent=parent)
        self._domDone = False

    def _onBridgeCmd(self, cmd):
        # ignore webchannel messages that arrive after underlying webview
        # deleted
        if sip.isdeleted(self):
            return

        if cmd == "domDone":
            return

        if cmd == "svgEditDone":
            self._domDone = True
            self._maybeRunActions()
        else:
            return self.onBridgeCmd(cmd)

    def runOnLoaded(self, callback):
        self._domDone = False
        self._queueAction("callback", callback)

    def _maybeRunActions(self):
        while self._pendingActions and self._domDone:
            name, args = self._pendingActions.pop(0)

            if name == "eval":
                self._evalWithCallback(*args)
            elif name == "setHtml":
                self._setHtml(*args)
            elif name == "callback":
                callback = args[0]
                callback()
            else:
                raise Exception("unknown action: {}".format(name))

class ImgOccEdit(QDialog):
    """Main Image Occlusion Editor dialog"""

    def __init__(self, imgoccadd, parent):
        QDialog.__init__(self)
        mw.setupDialogGC(self)
        self.setWindowFlags(Qt.Window)
        self.visible = False
        self.imgoccadd = imgoccadd
        self.parent = parent
        self.mode = "add"
        loadConfig(self)
        self.setupUi()
        restoreGeom(self, "imgoccedit")
        addHook("unloadProfile", self.onProfileUnload)

    def closeEvent(self, event):
        if mw.pm.profile is not None:
            self.deckChooser.cleanup()
            saveGeom(self, "imgoccedit")
        self.visible = False
        self.svg_edit = None
        del(self.svg_edit_anim)  # might not be gc'd
        remHook("unloadProfile", self.onProfileUnload)
        QDialog.reject(self)

    def onProfileUnload(self):
        if not sip.isdeleted(self):
            self.close()

    def reject(self):
        # Override QDialog Esc key reject
        pass

    def setupUi(self):
        """Set up ImgOccEdit UI"""
        # Main widgets aside from fields
        self.svg_edit = ImgOccWebView(parent=self)
        self.svg_edit._page = ImgOccWebPage(self.svg_edit._onBridgeCmd)
        self.svg_edit.setPage(self.svg_edit._page)

        self.tags_hbox = QHBoxLayout()
        self.tags_edit = tagedit.TagEdit(self)
        self.tags_label = QLabel("Tags")
        self.tags_label.setFixedWidth(70)
        self.deck_container = QWidget()
        self.deckChooser = deckchooser.DeckChooser(mw,
                                                   self.deck_container, label=True)
        self.deckChooser.deck.setAutoDefault(False)

        # workaround for tab focus order issue of the tags entry
        # (this particular section is only needed when the quick deck
        # buttons add-on is installed)
        if self.deck_container.layout().children():  # multiple deck buttons
            for i in range(self.deck_container.layout().children()[0].count()):
                try:
                    item = self.deck_container.layout().children()[0].itemAt(i)
                    # remove Tab focus manually:
                    item.widget().setFocusPolicy(Qt.ClickFocus)
                    item.widget().setAutoDefault(False)
                except AttributeError:
                    pass

        # Button row widgets
        self.bottom_label = QLabel()
        button_box = QDialogButtonBox(Qt.Horizontal, self)
        button_box.setCenterButtons(False)

        image_btn = QPushButton("Change &Image", clicked=self.changeImage)
        image_btn.setIcon(QIcon(os.path.join(ICONS_PATH, "add.png")))
        image_btn.setIconSize(QSize(16, 16))
        image_btn.setAutoDefault(False)
        help_btn = QPushButton("&Help", clicked=self.onHelp)
        help_btn.setAutoDefault(False)

        self.occl_tp_select = QComboBox()
        self.occl_tp_select.addItems(["Don't Change", "Hide All, Guess One",
                                      "Hide One, Guess One"])

        self.edit_btn = button_box.addButton("&Edit Cards",
                                             QDialogButtonBox.ActionRole)
        self.new_btn = button_box.addButton("&Add New Cards",
                                            QDialogButtonBox.ActionRole)
        self.ao_btn = button_box.addButton("Hide &All, Guess One",
                                           QDialogButtonBox.ActionRole)
        self.oa_btn = button_box.addButton("Hide &One, Guess One",
                                           QDialogButtonBox.ActionRole)
        close_button = button_box.addButton("&Close",
                                            QDialogButtonBox.RejectRole)

        image_tt = ("Switch to a different image while preserving all of "
                    "the shapes and fields")
        dc_tt = "Preserve existing occlusion type"
        edit_tt = "Edit all cards using current mask shapes and field entries"
        new_tt = "Create new batch of cards without editing existing ones"
        ao_tt = ("Generate cards with nonoverlapping information, where all
"
                 "labels are hidden on the front and one revealed on the back")
        oa_tt = ("Generate cards with overlapping information, where one
"
                 "label is hidden on the front and revealed on the back")
        close_tt = "Close Image Occlusion Editor without generating cards"

        image_btn.setToolTip(image_tt)
        self.edit_btn.setToolTip(edit_tt)
        self.new_btn.setToolTip(new_tt)
        self.ao_btn.setToolTip(ao_tt)
        self.oa_btn.setToolTip(oa_tt)
        close_button.setToolTip(close_tt)
        self.occl_tp_select.setItemData(0, dc_tt, Qt.ToolTipRole)
        self.occl_tp_select.setItemData(1, ao_tt, Qt.ToolTipRole)
        self.occl_tp_select.setItemData(2, oa_tt, Qt.ToolTipRole)

        for btn in [image_btn, self.edit_btn, self.new_btn, self.ao_btn,
                    self.oa_btn, close_button]:
            btn.setFocusPolicy(Qt.ClickFocus)

        self.edit_btn.clicked.connect(self.editNote)
        self.new_btn.clicked.connect(self.new)
        self.ao_btn.clicked.connect(self.addAO)
        self.oa_btn.clicked.connect(self.addOA)
        close_button.clicked.connect(self.close)

        # Set basic layout up

        # Button row
        bottom_hbox = QHBoxLayout()
        bottom_hbox.addWidget(image_btn)
        bottom_hbox.addWidget(help_btn)
        bottom_hbox.insertStretch(2, stretch=1)
        bottom_hbox.addWidget(self.bottom_label)
        bottom_hbox.addWidget(self.occl_tp_select)
        bottom_hbox.addWidget(button_box)

        # Tab 1
        vbox1 = QVBoxLayout()

        svg_edit_loader = QLabel("Loading...")
        svg_edit_loader.setAlignment(Qt.AlignCenter)
        loader_icon = os.path.join(ICONS_PATH, "loader.gif")
        anim = QMovie(loader_icon)
        svg_edit_loader.setMovie(anim)
        anim.start()
        self.svg_edit_loader = svg_edit_loader
        self.svg_edit_anim = anim

        vbox1.addWidget(self.svg_edit, stretch=1)
        vbox1.addWidget(self.svg_edit_loader, stretch=1)

        # Tab 2
        # vbox2 fields are variable and added by setupFields() at a later point
        self.vbox2 = QVBoxLayout()

        # Main Tab Widget
        tab1 = QWidget()
        self.tab2 = QWidget()
        tab1.setLayout(vbox1)
        self.tab2.setLayout(self.vbox2)
        self.tab_widget = QTabWidget()
        self.tab_widget.setFocusPolicy(Qt.ClickFocus)
        self.tab_widget.addTab(tab1, "&Masks Editor")
        self.tab_widget.addTab(self.tab2, "&Fields")
        self.tab_widget.setTabToolTip(
            1, "Include additional information (optional)")
        self.tab_widget.setTabToolTip(
            0, "Create image occlusion masks (required)")

        # Main Window
        vbox_main = QVBoxLayout()
        vbox_main.addWidget(self.tab_widget)
        vbox_main.addLayout(bottom_hbox)
        self.setLayout(vbox_main)
        self.setMinimumWidth(640)
        self.tab_widget.setCurrentIndex(0)
        self.svg_edit.setFocus()
        self.showSvgEdit(False)

        # Define and connect key bindings

        # Field focus hotkeys
        for i in range(1, 10):
            QShortcut(QKeySequence("Ctrl+%i" % i),
                      self).activated.connect(lambda f=i-1: self.focusField(f))
        # Other hotkeys
        QShortcut(QKeySequence("Ctrl+Return"),
                  self).activated.connect(lambda: self.defaultAction(True))
        QShortcut(QKeySequence("Ctrl+Shift+Return"),
                  self).activated.connect(lambda: self.addOA(True))
        QShortcut(QKeySequence("Ctrl+Tab"),
                  self).activated.connect(self.switchTabs)
        QShortcut(QKeySequence("Ctrl+r"),
                  self).activated.connect(self.resetMainFields)
        QShortcut(QKeySequence("Ctrl+Shift+r"),
                  self).activated.connect(self.resetAllFields)
        QShortcut(QKeySequence("Ctrl+Shift+t"),
                  self).activated.connect(self.focusTags)
        QShortcut(QKeySequence("Ctrl+f"),
                  self).activated.connect(self.fitImageCanvas)

    # Various actions that act on / interact with the ImgOccEdit UI:

    # Note actions

    def changeImage(self):
        self.imgoccadd.onChangeImage()
        self.fitImageCanvas()

    def defaultAction(self, close):
        if self.mode == "add":
            self.addAO(close)
        else:
            self.editNote()

    def addAO(self, close=False):
        self.imgoccadd.onAddNotesButton("ao", close)

    def addOA(self, close=False):
        self.imgoccadd.onAddNotesButton("oa", close)

    def new(self, close=False):
        choice = self.occl_tp_select.currentText()
        self.imgoccadd.onAddNotesButton(choice, close)

    def editNote(self):
        choice = self.occl_tp_select.currentText()
        self.imgoccadd.onEditNotesButton(choice)

    def onHelp(self):
        if self.mode == "add":
            ioHelp("add", parent=self)
        else:
            ioHelp("edit", parent=self)

    # Window state

    def resetFields(self):
        """Reset all widgets. Needed for changes to the note type"""
        layout = self.vbox2
        for i in reversed(list(range(layout.count()))):
            item = layout.takeAt(i)
            layout.removeItem(item)
            if item.widget():
                item.widget().setParent(None)
            elif item.layout():
                sublayout = item.layout()
                sublayout.setParent(None)
                for i in reversed(list(range(sublayout.count()))):
                    subitem = sublayout.takeAt(i)
                    sublayout.removeItem(subitem)
                    subitem.widget().setParent(None)
        self.tags_hbox.setParent(None)

    def setupFields(self, flds):
        """Setup dialog text edits based on note type fields"""
        self.tedit = {}
        self.tlabel = {}
        self.flds = flds
        for i in flds:
            if i['name'] in self.ioflds_priv:
                continue
            hbox = QHBoxLayout()
            tedit = QPlainTextEdit()
            label = QLabel(i["name"])
            hbox.addWidget(label)
            hbox.addWidget(tedit)
            tedit.setTabChangesFocus(True)
            tedit.setMinimumHeight(40)
            label.setFixedWidth(70)
            self.tedit[i["name"]] = tedit
            self.tlabel[i["name"]] = label
            self.vbox2.addLayout(hbox)

        self.tags_hbox.addWidget(self.tags_label)
        self.tags_hbox.addWidget(self.tags_edit)
        self.vbox2.addLayout(self.tags_hbox)
        self.vbox2.addWidget(self.deck_container)
        # switch Tab focus order of deckchooser and tags_edit (
        # for some reason it's the wrong way around by default):
        self.tab2.setTabOrder(self.tags_edit, self.deckChooser.deck)

    def switchToMode(self, mode):
        """Toggle between add and edit layouts"""
        hide_on_add = [self.occl_tp_select, self.edit_btn, self.new_btn]
        hide_on_edit = [self.ao_btn, self.oa_btn]
        self.mode = mode
        for i in list(self.tedit.values()):
            i.show()
        for i in list(self.tlabel.values()):
            i.show()
        if mode == "add":
            for i in hide_on_add:
                i.hide()
            for i in hide_on_edit:
                i.show()
            dl_txt = "Deck"
            ttl = "Image Occlusion Enhanced - Add Mode"
            bl_txt = "Add Cards:"
        else:
            for i in hide_on_add:
                i.show()
            for i in hide_on_edit:
                i.hide()
            for i in self.sconf['skip']:
                if i in list(self.tedit.keys()):
                    self.tedit[i].hide()
                    self.tlabel[i].hide()
            dl_txt = "Deck for Add new cards"
            ttl = "Image Occlusion Enhanced - Editing Mode"
            bl_txt = "Type:"
        self.deckChooser.deckLabel.setText(dl_txt)
        self.setWindowTitle(ttl)
        self.bottom_label.setText(bl_txt)

    def showSvgEdit(self, state):
        if not state:
            self.svg_edit.hide()
            self.svg_edit_anim.start()
            self.svg_edit_loader.show()
        else:
            self.svg_edit_anim.stop()
            self.svg_edit_loader.hide()
            self.svg_edit.show()

    # Other actions

    def switchTabs(self):
        currentTab = self.tab_widget.currentIndex()
        if currentTab == 0:
            self.tab_widget.setCurrentIndex(1)
            if isinstance(QApplication.focusWidget(), QPushButton):
                self.tedit[self.ioflds["hd"]].setFocus()
        else:
            self.tab_widget.setCurrentIndex(0)

    def focusField(self, idx):
        """Focus field in vbox2 layout by index number"""
        self.tab_widget.setCurrentIndex(1)
        target_item = self.vbox2.itemAt(idx)
        if not target_item:
            return
        target_layout = target_item.layout()
        target_widget = target_item.widget()
        if target_layout:
            target = target_layout.itemAt(1).widget()
        elif target_widget:
            target = target_widget
        target.setFocus()

    def focusTags(self):
        self.tab_widget.setCurrentIndex(1)
        self.tags_edit.setFocus()

    def resetMainFields(self):
        """Reset all fields aside from sticky ones"""
        for i in self.flds:
            fn = i['name']
            if fn in self.ioflds_priv or fn in self.ioflds_prsv:
                continue
            self.tedit[fn].setPlainText("")

    def resetAllFields(self):
        """Reset all fields"""
        self.resetMainFields()
        for i in self.ioflds_prsv:
            self.tedit[i].setPlainText("")

    def fitImageCanvas(self):
        self.svg_edit.eval("""
                           setTimeout(function(){
                               svgCanvas.zoomChanged('', 'canvas');
                           }, 5)
                           """)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
#
# django-codenerix-pos
#
# Copyright 2017 Centrologic Computational Logistic Center S.L.
#
# Project URL : http://www.codenerix.com
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import json
import hashlib
import random
import string

from django.db.models import Q
from django.db.models.fields import FieldDoesNotExist
from django.forms.utils import ErrorList
from django.http import HttpResponse
from django.utils.translation import ugettext as _
from django.views.generic import View
from django.db.models import Count

from codenerix.views import GenList, GenCreate, GenCreateModal, GenUpdate, GenUpdateModal, GenDelete, GenDetail, GenDetailModal
from codenerix_extensions.views import GenCreateBridge, GenUpdateBridge

from .models import POSZone, POSHardware, POS, POSSlot, POSPlant, POSProduct, POSLog, POSOperator
from .forms import POSZoneForm, POSHardwareForm, POSHardwareFormCreate, POSForm, POSFormCreate, POSSlotForm, POSPlantForm, POSProductForm, POSOperatorForm

# ###########################################
# POSPlant
class POSPlantList(GenList):
    model = POSPlant
    extra_context = {'menu': ['pos', 'posplant'], 'bread': [_('POS'), _('Plant')]}

class POSPlantCreate(GenCreate):
    model = POSPlant
    form_class = POSPlantForm

class POSPlantCreateModal(GenCreateModal, POSPlantCreate):
    pass

class POSPlantUpdate(GenUpdate):
    model = POSPlant
    form_class = POSPlantForm

class POSPlantUpdateModal(GenUpdateModal, POSPlantUpdate):
    pass

class POSPlantDelete(GenDelete):
    model = POSPlant

class POSPlantDetails(GenDetail):
    model = POSPlant
    groups = POSPlantForm.__groups_details__()

# ###########################################
# POSZone
class POSZoneList(GenList):
    model = POSZone
    extra_context = {'menu': ['pos', 'poszone'], 'bread': [_('POS'), _('Zone'), ]}

class POSZoneCreate(GenCreate):
    model = POSZone
    form_class = POSZoneForm

class POSZoneCreateModal(GenCreateModal, POSZoneCreate):
    pass

class POSZoneUpdate(GenUpdate):
    model = POSZone
    form_class = POSZoneForm

class POSZoneUpdateModal(GenUpdateModal, POSZoneUpdate):
    pass

class POSZoneDelete(GenDelete):
    model = POSZone

class POSZoneDetails(GenDetail):
    model = POSZone
    groups = POSZoneForm.__groups_details__()

# ###########################################
# POSHardware
class POSHardwareList(GenList):
    model = POSHardware
    extra_context = {'menu': ['pos', 'poshardware'], 'bread': [_('POS'), _('Hardware'), ]}
    annotations = {
        'where': Count('poss'),
    }
    gentrans = {
        'warning_toomany': _('Too many POSs are using this hardware!'),
        'warning_toomany_total': _('Total POSs'),
    }

    def __fields__(self, info):
        fields = []
        fields.append(('pos', _("POS")))
        fields.append(('get_kind_display', _("Kind")))
        fields.append(('name', _("Name")))
        fields.append(('enable', _("Enable")))
        fields.append(('uuid', _("UUID")))
        fields.append(('key', _("Key")))
        fields.append(('config', _("Config")))
        fields.append(('value', _("Value")))
        fields.append(('where', None))
        return fields

class POSHardwareCreate(GenCreate):
    model = POSHardware
    form_class = POSHardwareFormCreate

    def get_form(self, *args, **kwargs):
        form = super(POSHardwareCreate, self).get_form(*args, **kwargs)
        form.fields["key"].initial = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(32))
        return form

class POSHardwareCreateModal(GenCreateModal, POSHardwareCreate):
    pass

class POSHardwareUpdate(GenUpdate):
    model = POSHardware
    form_class = POSHardwareForm

class POSHardwareUpdateModal(GenUpdateModal, POSHardwareUpdate):
    pass

class POSHardwareDelete(GenDelete):
    model = POSHardware

class POSHardwareSubList(GenList):
    model = POSHardware
    extra_context = {'menu': ['pos', 'poshardware'], 'bread': [_('POS'), _('Hardware'), ]}

    def __limitQ__(self, info):
        limit = {}
        pk = info.kwargs.get('pk', None)
        limit['link'] = Q(pos__pk=pk)
        return limit

class POSHardwareDetails(GenDetail):
    model = POSHardware
    groups = POSHardwareForm.__groups_details__()

class POSHardwareDetailModal(GenDetailModal, POSHardwareDetails):
    pass

# ###########################################
# POS
class POSList(GenList):
    model = POS
    extra_context = {'menu': ['pos', 'pos'], 'bread': [_('POS'), _('POS'), ]}

class POSCreate(GenCreate):
    model = POS
    form_class = POSFormCreate

    def get_form(self, *args, **kwargs):
        form = super(POSCreate, self).get_form(*args, **kwargs)
        form.fields["key"].initial = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(32))
        return form

class POSCreateModal(GenCreateModal, POSCreate):
    pass

class POSUpdate(GenUpdate):
    model = POS
    form_class = POSForm

class POSUpdateModal(GenUpdateModal, POSUpdate):
    pass

class POSDelete(GenDelete):
    model = POS

class POSSubList(GenList):
    model = POS
    extra_context = {'menu': ['pos', 'pos'], 'bread': [_('POS'), _('POS'), ]}

    def __limitQ__(self, info):
        limit = {}
        pk = info.kwargs.get('pk', None)
        limit['link'] = Q(zone__pk=pk)
        return limit

class POSDetails(GenDetail):
    model = POS
    groups = POSForm.__groups_details__()

class POSDetailModal(GenDetailModal, POSDetails):
    pass

# ###########################################
# POSSlot
class POSSlotList(GenList):
    model = POSSlot
    extra_context = {'menu': ['pos', 'posslot'], 'bread': [_('POS'), _('Slot'), ]}

class POSSlotCreate(GenCreate):
    model = POSSlot
    form_class = POSSlotForm

class POSSlotCreateModal(GenCreateModal, POSSlotCreate):
    pass

class POSSlotUpdate(GenUpdate):
    model = POSSlot
    form_class = POSSlotForm

class POSSlotUpdateModal(GenUpdateModal, POSSlotUpdate):
    pass

class POSSlotDelete(GenDelete):
    model = POSSlot

class POSSlotSubList(GenList):
    model = POSSlot
    extra_context = {'menu': ['pos', 'posslot'], 'bread': [_('POS'), _('Slot'), ]}

    def __limitQ__(self, info):
        limit = {}
        pk = info.kwargs.get('pk', None)
        limit['link'] = Q(zone__pk=pk)
        return limit

class POSSlotDetails(GenDetail):
    model = POSSlot
    groups = POSSlotForm.__groups_details__()

class POSSlotDetailModal(GenDetailModal, POSSlotDetails):
    pass

# ###########################################
# POSProduct
class POSProductList(GenList):
    model = POSProduct
    extra_context = {'menu': ['pos', 'posproduct'], 'bread': [_('POS'), _('Product')]}

class POSProductCreate(GenCreate):
    model = POSProduct
    form_class = POSProductForm

class POSProductCreateModal(GenCreateModal, POSProductCreate):
    pass

class POSProductUpdate(GenUpdate):
    model = POSProduct
    form_class = POSProductForm

class POSProductUpdateModal(GenUpdateModal, POSProductUpdate):
    pass

class POSProductDelete(GenDelete):
    model = POSProduct

class POSProductSubList(GenList):
    model = POSProduct
    extra_context = {'menu': ['POSProduct', 'people'], 'bread': [_('POSProduct'), _('People')]}

    def __limitQ__(self, info):
        limit = {}
        pk = info.kwargs.get('pk', None)
        limit['link'] = Q(pos__pk=pk)
        return limit

class POSProductDetails(GenDetail):
    model = POSProduct
    groups = POSProductForm.__groups_details__()

class POSProductDetailModal(GenDetailModal, POSProductDetails):
    pass

# ###########################################
# POSLog
class POSLogList(GenList):
    model = POSLog
    extra_context = {'menu': ['pos', 'poslog'], 'bread': [_('POS'), _('Log')]}
    default_ordering = '-pk'
    linkadd = False
    linkedit = False
    search_filter_button = True

# ###########################################
# POSOperator
class POSOperatorList(GenList):
    model = POSOperator
    extra_context = {'menu': ['people', 'POSOperator'], 'bread': [_('People'), _('POSOperator')]}

class POSOperatorCreate(GenCreate, GenCreateBridge):
    model = POSOperator
    form_class = POSOperatorForm

    def form_valid(self, form):
        field = 'codenerix_external_field'
        model = POSOperator
        related_field = 'pos_operator'
        error_message = [
            _("The selected entry is already a operator, select another entry!"),
            _("The selected entry is not available anymore, please, try again!")
        ]

        external = self.request.POST.get('codenerix_external_field', None)
        password1 = self.request.POST.get('password1', None)
        password2 = self.request.POST.get('password2', None)
        if external is None:
            errors = form._errors.setdefault("codenerix_external_field", ErrorList())
            errors.append(_("Not related to a user"))
            return super(POSOperatorCreate, self).form_invalid(form)
        else:
            model_tmp = None
            for related in self.model._meta.related_objects:
                related_model = related.related_model
                try:
                    if related_model._meta.get_field('pos_operator'):
                        model_tmp = related_model
                        break
                except FieldDoesNotExist:
                    pass
            if model_tmp:
                operator = model_tmp.objects.filter(pk=external).first()
                if operator is None or operator.user is None:
                    errors = form._errors.setdefault("codenerix_external_field", ErrorList())
                    errors.append(_("Not related to a user"))
                    return super(POSOperatorCreate, self).form_invalid(form)
            else:
                errors = form._errors.setdefault("codenerix_external_field", ErrorList())
                errors.append(_("Not related to a user"))
                return super(POSOperatorCreate, self).form_invalid(form)

        if password1 is None or password2 is None:
            errors = form._errors.setdefault("password1", ErrorList())
            errors.append(_("Passwords required"))
            return super(POSOperatorCreate, self).form_invalid(form)
        if password1 != password2:
            errors = form._errors.setdefault("password1", ErrorList())
            errors.append(_("Passwords do not match"))
            return super(POSOperatorCreate, self).form_invalid(form)

        try:
            # python 2.7
            operator.user.last_name = hashlib.sha1(password1).hexdigest()[:30]
        except TypeError:
            # python 3.x
            password1_str = bytes(password1, encoding='utf-8')
            operator.user.last_name = hashlib.sha1(password1_str).hexdigest()[:30]
        operator.user.save()
        return self.form_valid_bridge(form, field, model, related_field, error_message)

class POSOperatorCreateModal(GenCreateModal, POSOperatorCreate):
    pass

class POSOperatorUpdate(GenUpdate, GenUpdateBridge):
    model = POSOperator
    form_class = POSOperatorForm

    def get_form(self, form_class=None):
        form = super(POSOperatorUpdate, self).get_form(form_class)
        # initial external field
        form.fields['codenerix_external_field'].initial = form.instance.external
        return form

    def form_valid(self, form):
        field = 'codenerix_external_field'
        model = POSOperator
        related_field = 'pos_operator'
        error_message = [
            _("The selected entry is not available anymore, please, try again!")
        ]
        external = self.request.POST.get('codenerix_external_field', None)
        password1 = self.request.POST.get('password1', None)
        password2 = self.request.POST.get('password2', None)

        if external is None:
            errors = form._errors.setdefault("codenerix_external_field", ErrorList())
            errors.append(_("Not related to a user"))
            return super(POSOperatorUpdate, self).form_invalid(form)
        else:
            model_tmp = None
            for related in self.model._meta.related_objects:
                related_model = related.related_model
                try:
                    if related_model._meta.get_field('pos_operator'):
                        model_tmp = related_model
                        break
                except FieldDoesNotExist:
                    pass
            if model_tmp:
                operator = model_tmp.objects.filter(pk=external).first()
                if operator is None or operator.user is None:
                    errors = form._errors.setdefault("codenerix_external_field", ErrorList())
                    errors.append(_("Not related to a user"))
                    return super(POSOperatorUpdate, self).form_invalid(form)
            else:
                errors = form._errors.setdefault("codenerix_external_field", ErrorList())
                errors.append(_("Not related to a user"))
                return super(POSOperatorUpdate, self).form_invalid(form)

        if password1 != password2:
            errors = form._errors.setdefault("password1", ErrorList())
            errors.append(_("Passwords do not match"))
            return super(POSOperatorUpdate, self).form_invalid(form)

        if password1:
            operator.user.last_name = hashlib.sha1(password1).hexdigest()[:30]
            operator.user.save()
        return self.form_valid_bridge(form, field, model, related_field, error_message)

class POSOperatorUpdateModal(GenUpdateModal, POSOperatorUpdate):
    pass

class POSOperatorDelete(GenDelete):
    model = POSOperator

class POSOperatorSubList(GenList):
    model = POSOperator
    extra_context = {'menu': ['people', 'POSOperator'], 'bread': [_('People'), _('POSOperator')]}

    def __limitQ__(self, info):
        limit = {}
        pk = info.kwargs.get('pk', None)
        limit['link'] = Q(person__pk=pk)
        return limit

class POSOperatorDetails(GenDetail):
    model = POSOperator
    groups = POSOperatorForm.__groups_details__()

class POSOperatorDetailModal(GenDetailModal, POSOperatorDetails):
    pass

class POSSession(View):
    def post(self, request, *args, **kwargs):
        context = {}
        old_uuid = self.request.session.get('POS_client_UUID', None)
        new_uuid = request.POST.get('uuid', None)

        if old_uuid and new_uuid and old_uuid != new_uuid:
            context['msg'] = 'KO'
            context['txt'] = 'UUID changed. {} => {}'.format(old_uuid, new_uuid)
        else:
            context['msg'] = 'OK'

        self.request.session['POS_client_UUID'] = new_uuid
        json_answer = json.dumps(context)
        return HttpResponse(json_answer, content_type='application/json')
<commit_msg>New ordering for poshardware<commit_after># -*- coding: utf-8 -*-
#
# django-codenerix-pos
#
# Copyright 2017 Centrologic Computational Logistic Center S.L.
#
# Project URL : http://www.codenerix.com
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import json
import hashlib
import random
import string

from django.db.models import Q
from django.db.models.fields import FieldDoesNotExist
from django.forms.utils import ErrorList
from django.http import HttpResponse
from django.utils.translation import ugettext as _
from django.views.generic import View
from django.db.models import Count

from codenerix.views import GenList, GenCreate, GenCreateModal, GenUpdate, GenUpdateModal, GenDelete, GenDetail, GenDetailModal
from codenerix_extensions.views import GenCreateBridge, GenUpdateBridge

from .models import POSZone, POSHardware, POS, POSSlot, POSPlant, POSProduct, POSLog, POSOperator
from .forms import POSZoneForm, POSHardwareForm, POSHardwareFormCreate, POSForm, POSFormCreate, POSSlotForm, POSPlantForm, POSProductForm, POSOperatorForm

# ###########################################
# POSPlant
class POSPlantList(GenList):
    model = POSPlant
    extra_context = {'menu': ['pos', 'posplant'], 'bread': [_('POS'), _('Plant')]}

class POSPlantCreate(GenCreate):
    model = POSPlant
    form_class = POSPlantForm

class POSPlantCreateModal(GenCreateModal, POSPlantCreate):
    pass

class POSPlantUpdate(GenUpdate):
    model = POSPlant
    form_class = POSPlantForm

class POSPlantUpdateModal(GenUpdateModal, POSPlantUpdate):
    pass

class POSPlantDelete(GenDelete):
    model = POSPlant

class POSPlantDetails(GenDetail):
    model = POSPlant
    groups = POSPlantForm.__groups_details__()

# ###########################################
# POSZone
class POSZoneList(GenList):
    model = POSZone
    extra_context = {'menu': ['pos', 'poszone'], 'bread': [_('POS'), _('Zone'), ]}

class POSZoneCreate(GenCreate):
    model = POSZone
    form_class = POSZoneForm

class POSZoneCreateModal(GenCreateModal, POSZoneCreate):
    pass

class POSZoneUpdate(GenUpdate):
    model = POSZone
    form_class = POSZoneForm

class POSZoneUpdateModal(GenUpdateModal, POSZoneUpdate):
    pass

class POSZoneDelete(GenDelete):
    model = POSZone

class POSZoneDetails(GenDetail):
    model = POSZone
    groups = POSZoneForm.__groups_details__()

# ###########################################
# POSHardware
class POSHardwareList(GenList):
    model = POSHardware
    extra_context = {'menu': ['pos', 'poshardware'], 'bread': [_('POS'), _('Hardware'), ]}
    annotations = {
        'where': Count('poss'),
    }
    gentrans = {
        'warning_toomany': _('Too many POSs are using this hardware!'),
        'warning_toomany_total': _('Total POSs'),
    }
    default_ordering = ["pos", "kind", "name"]

    def __fields__(self, info):
        fields = []
        fields.append(('pos', _("POS")))
        fields.append(('get_kind_display', _("Kind")))
        fields.append(('name', _("Name")))
        fields.append(('enable', _("Enable")))
        fields.append(('uuid', _("UUID")))
        fields.append(('key', _("Key")))
        fields.append(('config', _("Config")))
        fields.append(('value', _("Value")))
        fields.append(('where', None))
        return fields

class POSHardwareCreate(GenCreate):
    model = POSHardware
    form_class = POSHardwareFormCreate

    def get_form(self, *args, **kwargs):
        form = super(POSHardwareCreate, self).get_form(*args, **kwargs)
        form.fields["key"].initial = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(32))
        return form

class POSHardwareCreateModal(GenCreateModal, POSHardwareCreate):
    pass

class POSHardwareUpdate(GenUpdate):
    model = POSHardware
    form_class = POSHardwareForm

class POSHardwareUpdateModal(GenUpdateModal, POSHardwareUpdate):
    pass

class POSHardwareDelete(GenDelete):
    model = POSHardware

class POSHardwareSubList(GenList):
    model = POSHardware
    extra_context = {'menu': ['pos', 'poshardware'], 'bread': [_('POS'), _('Hardware'), ]}

    def __limitQ__(self, info):
        limit = {}
        pk = info.kwargs.get('pk', None)
        limit['link'] = Q(pos__pk=pk)
        return limit

class POSHardwareDetails(GenDetail):
    model = POSHardware
    groups = POSHardwareForm.__groups_details__()

class POSHardwareDetailModal(GenDetailModal, POSHardwareDetails):
    pass

# ###########################################
# POS
class POSList(GenList):
    model = POS
    extra_context = {'menu': ['pos', 'pos'], 'bread': [_('POS'), _('POS'), ]}

class POSCreate(GenCreate):
    model = POS
    form_class = POSFormCreate

    def get_form(self, *args, **kwargs):
        form = super(POSCreate, self).get_form(*args, **kwargs)
        form.fields["key"].initial = ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(32))
        return form

class POSCreateModal(GenCreateModal, POSCreate):
    pass

class POSUpdate(GenUpdate):
    model = POS
    form_class = POSForm

class POSUpdateModal(GenUpdateModal, POSUpdate):
    pass

class POSDelete(GenDelete):
    model = POS

class POSSubList(GenList):
    model = POS
    extra_context = {'menu': ['pos', 'pos'], 'bread': [_('POS'), _('POS'), ]}

    def __limitQ__(self, info):
        limit = {}
        pk = info.kwargs.get('pk', None)
        limit['link'] = Q(zone__pk=pk)
        return limit

class POSDetails(GenDetail):
    model = POS
    groups = POSForm.__groups_details__()

class POSDetailModal(GenDetailModal, POSDetails):
    pass

# ###########################################
# POSSlot
class POSSlotList(GenList):
    model = POSSlot
    extra_context = {'menu': ['pos', 'posslot'], 'bread': [_('POS'), _('Slot'), ]}

class POSSlotCreate(GenCreate):
    model = POSSlot
    form_class = POSSlotForm

class POSSlotCreateModal(GenCreateModal, POSSlotCreate):
    pass

class POSSlotUpdate(GenUpdate):
    model = POSSlot
    form_class = POSSlotForm

class POSSlotUpdateModal(GenUpdateModal, POSSlotUpdate):
    pass

class POSSlotDelete(GenDelete):
    model = POSSlot

class POSSlotSubList(GenList):
    model = POSSlot
    extra_context = {'menu': ['pos', 'posslot'], 'bread': [_('POS'), _('Slot'), ]}

    def __limitQ__(self, info):
        limit = {}
        pk = info.kwargs.get('pk', None)
        limit['link'] = Q(zone__pk=pk)
        return limit

class POSSlotDetails(GenDetail):
    model = POSSlot
    groups = POSSlotForm.__groups_details__()

class POSSlotDetailModal(GenDetailModal, POSSlotDetails):
    pass

# ###########################################
# POSProduct
class POSProductList(GenList):
    model = POSProduct
    extra_context = {'menu': ['pos', 'posproduct'], 'bread': [_('POS'), _('Product')]}

class POSProductCreate(GenCreate):
    model = POSProduct
    form_class = POSProductForm

class POSProductCreateModal(GenCreateModal, POSProductCreate):
    pass

class POSProductUpdate(GenUpdate):
    model = POSProduct
    form_class = POSProductForm

class POSProductUpdateModal(GenUpdateModal, POSProductUpdate):
    pass

class POSProductDelete(GenDelete):
    model = POSProduct

class POSProductSubList(GenList):
    model = POSProduct
    extra_context = {'menu': ['POSProduct', 'people'], 'bread': [_('POSProduct'), _('People')]}

    def __limitQ__(self, info):
        limit = {}
        pk = info.kwargs.get('pk', None)
        limit['link'] = Q(pos__pk=pk)
        return limit

class POSProductDetails(GenDetail):
    model = POSProduct
    groups = POSProductForm.__groups_details__()

class POSProductDetailModal(GenDetailModal, POSProductDetails):
    pass

# ###########################################
# POSLog
class POSLogList(GenList):
    model = POSLog
    extra_context = {'menu': ['pos', 'poslog'], 'bread': [_('POS'), _('Log')]}
    default_ordering = '-pk'
    linkadd = False
    linkedit = False
    search_filter_button = True

# ###########################################
# POSOperator
class POSOperatorList(GenList):
    model = POSOperator
    extra_context = {'menu': ['people', 'POSOperator'], 'bread': [_('People'), _('POSOperator')]}

class POSOperatorCreate(GenCreate, GenCreateBridge):
    model = POSOperator
    form_class = POSOperatorForm

    def form_valid(self, form):
        field = 'codenerix_external_field'
        model = POSOperator
        related_field = 'pos_operator'
        error_message = [
            _("The selected entry is already a operator, select another entry!"),
            _("The selected entry is not available anymore, please, try again!")
        ]

        external = self.request.POST.get('codenerix_external_field', None)
        password1 = self.request.POST.get('password1', None)
        password2 = self.request.POST.get('password2', None)
        if external is None:
            errors = form._errors.setdefault("codenerix_external_field", ErrorList())
            errors.append(_("Not related to a user"))
            return super(POSOperatorCreate, self).form_invalid(form)
        else:
            model_tmp = None
            for related in self.model._meta.related_objects:
                related_model = related.related_model
                try:
                    if related_model._meta.get_field('pos_operator'):
                        model_tmp = related_model
                        break
                except FieldDoesNotExist:
                    pass
            if model_tmp:
                operator = model_tmp.objects.filter(pk=external).first()
                if operator is None or operator.user is None:
                    errors = form._errors.setdefault("codenerix_external_field", ErrorList())
                    errors.append(_("Not related to a user"))
                    return super(POSOperatorCreate, self).form_invalid(form)
            else:
                errors = form._errors.setdefault("codenerix_external_field", ErrorList())
                errors.append(_("Not related to a user"))
                return super(POSOperatorCreate, self).form_invalid(form)

        if password1 is None or password2 is None:
            errors = form._errors.setdefault("password1", ErrorList())
            errors.append(_("Passwords required"))
            return super(POSOperatorCreate, self).form_invalid(form)
        if password1 != password2:
            errors = form._errors.setdefault("password1", ErrorList())
            errors.append(_("Passwords do not match"))
            return super(POSOperatorCreate, self).form_invalid(form)

        try:
            # python 2.7
            operator.user.last_name = hashlib.sha1(password1).hexdigest()[:30]
        except TypeError:
            # python 3.x
            password1_str = bytes(password1, encoding='utf-8')
            operator.user.last_name = hashlib.sha1(password1_str).hexdigest()[:30]
        operator.user.save()
        return self.form_valid_bridge(form, field, model, related_field, error_message)

class POSOperatorCreateModal(GenCreateModal, POSOperatorCreate):
    pass

class POSOperatorUpdate(GenUpdate, GenUpdateBridge):
    model = POSOperator
    form_class = POSOperatorForm

    def get_form(self, form_class=None):
        form = super(POSOperatorUpdate, self).get_form(form_class)
        # initial external field
        form.fields['codenerix_external_field'].initial = form.instance.external
        return form

    def form_valid(self, form):
        field = 'codenerix_external_field'
        model = POSOperator
        related_field = 'pos_operator'
        error_message = [
            _("The selected entry is not available anymore, please, try again!")
        ]
        external = self.request.POST.get('codenerix_external_field', None)
        password1 = self.request.POST.get('password1', None)
        password2 = self.request.POST.get('password2', None)

        if external is None:
            errors = form._errors.setdefault("codenerix_external_field", ErrorList())
            errors.append(_("Not related to a user"))
            return super(POSOperatorUpdate, self).form_invalid(form)
        else:
            model_tmp = None
            for related in self.model._meta.related_objects:
                related_model = related.related_model
                try:
                    if related_model._meta.get_field('pos_operator'):
                        model_tmp = related_model
                        break
                except FieldDoesNotExist:
                    pass
            if model_tmp:
                operator = model_tmp.objects.filter(pk=external).first()
                if operator is None or operator.user is None:
                    errors = form._errors.setdefault("codenerix_external_field", ErrorList())
                    errors.append(_("Not related to a user"))
                    return super(POSOperatorUpdate, self).form_invalid(form)
            else:
                errors = form._errors.setdefault("codenerix_external_field", ErrorList())
                errors.append(_("Not related to a user"))
                return super(POSOperatorUpdate, self).form_invalid(form)

        if password1 != password2:
            errors = form._errors.setdefault("password1", ErrorList())
            errors.append(_("Passwords do not match"))
            return super(POSOperatorUpdate, self).form_invalid(form)

        if password1:
            operator.user.last_name = hashlib.sha1(password1).hexdigest()[:30]
            operator.user.save()
        return self.form_valid_bridge(form, field, model, related_field, error_message)

class POSOperatorUpdateModal(GenUpdateModal, POSOperatorUpdate):
    pass

class POSOperatorDelete(GenDelete):
    model = POSOperator

class POSOperatorSubList(GenList):
    model = POSOperator
    extra_context = {'menu': ['people', 'POSOperator'], 'bread': [_('People'), _('POSOperator')]}

    def __limitQ__(self, info):
        limit = {}
        pk = info.kwargs.get('pk', None)
        limit['link'] = Q(person__pk=pk)
        return limit

class POSOperatorDetails(GenDetail):
    model = POSOperator
    groups = POSOperatorForm.__groups_details__()

class POSOperatorDetailModal(GenDetailModal, POSOperatorDetails):
    pass

class POSSession(View):
    def post(self, request, *args, **kwargs):
        context = {}
        old_uuid = self.request.session.get('POS_client_UUID', None)
        new_uuid = request.POST.get('uuid', None)

        if old_uuid and new_uuid and old_uuid != new_uuid:
            context['msg'] = 'KO'
            context['txt'] = 'UUID changed. {} => {}'.format(old_uuid, new_uuid)
        else:
            context['msg'] = 'OK'

        self.request.session['POS_client_UUID'] = new_uuid
        json_answer = json.dumps(context)
        return HttpResponse(json_answer, content_type='application/json')
<|endoftext|>